@uppy/informer: migrate to TS (#4967)

This commit is contained in:
Merlijn Vos 2024-02-27 18:04:52 +01:00 committed by GitHub
parent 71a8e54609
commit 8cb3840080
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 158 additions and 59 deletions

View file

@ -0,0 +1 @@
tsconfig.*

View file

@ -1,23 +1,23 @@
import { h, Component, createRef } from 'preact'
import { h, Component, createRef, type ComponentChild } from 'preact'
const TRANSITION_MS = 300
export default class FadeIn extends Component {
ref = createRef()
componentWillEnter (callback) {
componentWillEnter(callback: () => void): void {
this.ref.current.style.opacity = '1'
this.ref.current.style.transform = 'none'
setTimeout(callback, TRANSITION_MS)
}
componentWillLeave (callback) {
componentWillLeave(callback: () => void): void {
this.ref.current.style.opacity = '0'
this.ref.current.style.transform = 'translateY(350%)'
setTimeout(callback, TRANSITION_MS)
}
render () {
render(): ComponentChild {
const { children } = this.props
return (

View file

@ -1,12 +1,18 @@
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { h } from 'preact'
import { h, type ComponentChild } from 'preact'
import { UIPlugin } from '@uppy/core'
import FadeIn from './FadeIn.jsx'
import TransitionGroup from './TransitionGroup.js'
import type { State, UIPluginOptions, Uppy } from '@uppy/core'
import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
import FadeIn from './FadeIn.tsx'
import TransitionGroup from './TransitionGroup.ts'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore We don't want TS to generate types for the package.json
import packageJson from '../package.json'
export type InformerOptions = UIPluginOptions
/**
* Informer
* Shows rad message bubbles
@ -14,38 +20,38 @@ import packageJson from '../package.json'
* or for errors: `uppy.info('Error uploading img.jpg', 'error', 5000)`
*
*/
export default class Informer extends UIPlugin {
export default class Informer<M extends Meta, B extends Body> extends UIPlugin<
UIPluginOptions,
M,
B
> {
static VERSION = packageJson.version
constructor (uppy, opts) {
constructor(uppy: Uppy<M, B>, opts?: UIPluginOptions) {
super(uppy, opts)
this.type = 'progressindicator'
this.id = this.opts.id || 'Informer'
this.title = 'Informer'
// set default options
const defaultOptions = {}
// merge default options with the ones set by user
this.opts = { ...defaultOptions, ...opts }
}
render = (state) => {
render = (state: State<M, B>): ComponentChild => {
return (
<div className="uppy uppy-Informer">
<TransitionGroup>
{state.info.map((info) => (
<FadeIn key={info.message}>
<p role="alert">
{info.message}
{' '}
{info.message}{' '}
{info.details && (
<span
aria-label={info.details}
data-microtip-position="top-left"
data-microtip-size="medium"
role="tooltip"
// eslint-disable-next-line no-alert
onClick={() => alert(`${info.message} \n\n ${info.details}`)}
onClick={() =>
// eslint-disable-next-line no-alert
alert(`${info.message} \n\n ${info.details}`)
}
>
?
</span>
@ -58,7 +64,7 @@ export default class Informer extends UIPlugin {
)
}
install () {
install(): void {
const { target } = this.opts
if (target) {
this.mount(target, this)

View file

@ -1,3 +1,6 @@
// INFO: not typing copy pasted libarary code
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
/* eslint-disable */
/**
* @source https://github.com/developit/preact-transition-group
@ -5,20 +8,23 @@
import { Component, cloneElement, h, toChildArray } from 'preact'
function assign (obj, props) {
function assign(obj, props) {
return Object.assign(obj, props)
}
function getKey (vnode, fallback) {
function getKey(vnode, fallback) {
return vnode?.key ?? fallback
}
function linkRef (component, name) {
function linkRef(component, name) {
const cache = component._ptgLinkedRefs || (component._ptgLinkedRefs = {})
return cache[name] || (cache[name] = c => {
component.refs[name] = c
})
return (
cache[name] ||
(cache[name] = (c) => {
component.refs[name] = c
})
)
}
function getChildMapping (children) {
function getChildMapping(children) {
const out = {}
for (let i = 0; i < children.length; i++) {
if (children[i] != null) {
@ -29,11 +35,12 @@ function getChildMapping (children) {
return out
}
function mergeChildMappings (prev, next) {
function mergeChildMappings(prev, next) {
prev = prev || {}
next = next || {}
const getValueForKey = key => (next.hasOwnProperty(key) ? next[key] : prev[key])
const getValueForKey = (key) =>
next.hasOwnProperty(key) ? next[key] : prev[key]
// For each key of `next`, the list of keys to insert before that key in
// the combined list
@ -56,7 +63,8 @@ function mergeChildMappings (prev, next) {
if (nextKeysPending.hasOwnProperty(nextKey)) {
for (let i = 0; i < nextKeysPending[nextKey].length; i++) {
const pendingNextKey = nextKeysPending[nextKey][i]
childMapping[nextKeysPending[nextKey][i]] = getValueForKey(pendingNextKey)
childMapping[nextKeysPending[nextKey][i]] =
getValueForKey(pendingNextKey)
}
}
childMapping[nextKey] = getValueForKey(nextKey)
@ -70,16 +78,18 @@ function mergeChildMappings (prev, next) {
return childMapping
}
const identity = i => i
const identity = (i) => i
class TransitionGroup extends Component {
constructor (props, context) {
constructor(props, context) {
super(props, context)
this.refs = {}
this.state = {
children: getChildMapping(toChildArray(toChildArray(this.props.children)) || []),
children: getChildMapping(
toChildArray(toChildArray(this.props.children)) || [],
),
}
this.performAppear = this.performAppear.bind(this)
@ -87,14 +97,14 @@ class TransitionGroup extends Component {
this.performLeave = this.performLeave.bind(this)
}
componentWillMount () {
componentWillMount() {
this.currentlyTransitioningKeys = {}
this.keysToAbortLeave = []
this.keysToEnter = []
this.keysToLeave = []
}
componentDidMount () {
componentDidMount() {
const initialChildMapping = this.state.children
for (const key in initialChildMapping) {
if (initialChildMapping[key]) {
@ -104,11 +114,13 @@ class TransitionGroup extends Component {
}
}
componentWillReceiveProps (nextProps) {
const nextChildMapping = getChildMapping(toChildArray(nextProps.children) || [])
componentWillReceiveProps(nextProps) {
const nextChildMapping = getChildMapping(
toChildArray(nextProps.children) || [],
)
const prevChildMapping = this.state.children
this.setState(prevState => ({
this.setState((prevState) => ({
children: mergeChildMappings(prevState.children, nextChildMapping),
}))
@ -118,10 +130,18 @@ class TransitionGroup extends Component {
if (nextChildMapping.hasOwnProperty(key)) {
const hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key)
// We should re-enter the component and abort its leave function
if (nextChildMapping[key] && hasPrev && this.currentlyTransitioningKeys[key]) {
if (
nextChildMapping[key] &&
hasPrev &&
this.currentlyTransitioningKeys[key]
) {
this.keysToEnter.push(key)
this.keysToAbortLeave.push(key)
} else if (nextChildMapping[key] && !hasPrev && !this.currentlyTransitioningKeys[key]) {
} else if (
nextChildMapping[key] &&
!hasPrev &&
!this.currentlyTransitioningKeys[key]
) {
this.keysToEnter.push(key)
}
}
@ -130,14 +150,18 @@ class TransitionGroup extends Component {
for (key in prevChildMapping) {
if (prevChildMapping.hasOwnProperty(key)) {
const hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key)
if (prevChildMapping[key] && !hasNext && !this.currentlyTransitioningKeys[key]) {
if (
prevChildMapping[key] &&
!hasNext &&
!this.currentlyTransitioningKeys[key]
) {
this.keysToLeave.push(key)
}
}
}
}
componentDidUpdate () {
componentDidUpdate() {
const { keysToEnter } = this
this.keysToEnter = []
keysToEnter.forEach(this.performEnter)
@ -147,14 +171,14 @@ class TransitionGroup extends Component {
keysToLeave.forEach(this.performLeave)
}
_finishAbort (key) {
_finishAbort(key) {
const idx = this.keysToAbortLeave.indexOf(key)
if (idx !== -1) {
this.keysToAbortLeave.splice(idx, 1)
}
}
performAppear (key) {
performAppear(key) {
this.currentlyTransitioningKeys[key] = true
const component = this.refs[key]
@ -166,7 +190,7 @@ class TransitionGroup extends Component {
}
}
_handleDoneAppearing (key) {
_handleDoneAppearing(key) {
const component = this.refs[key]
if (component?.componentDidAppear) {
component.componentDidAppear()
@ -175,7 +199,9 @@ class TransitionGroup extends Component {
delete this.currentlyTransitioningKeys[key]
this._finishAbort(key)
const currentChildMapping = getChildMapping(toChildArray(this.props.children) || [])
const currentChildMapping = getChildMapping(
toChildArray(this.props.children) || [],
)
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
// This was removed before it had fully appeared. Remove it.
@ -183,7 +209,7 @@ class TransitionGroup extends Component {
}
}
performEnter (key) {
performEnter(key) {
this.currentlyTransitioningKeys[key] = true
const component = this.refs[key]
@ -195,7 +221,7 @@ class TransitionGroup extends Component {
}
}
_handleDoneEntering (key) {
_handleDoneEntering(key) {
const component = this.refs[key]
if (component?.componentDidEnter) {
component.componentDidEnter()
@ -204,7 +230,9 @@ class TransitionGroup extends Component {
delete this.currentlyTransitioningKeys[key]
this._finishAbort(key)
const currentChildMapping = getChildMapping(toChildArray(this.props.children) || [])
const currentChildMapping = getChildMapping(
toChildArray(this.props.children) || [],
)
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
// This was removed before it had fully entered. Remove it.
@ -212,7 +240,7 @@ class TransitionGroup extends Component {
}
}
performLeave (key) {
performLeave(key) {
// If we should immediately abort this leave function,
// don't run the leave transition at all.
const idx = this.keysToAbortLeave.indexOf(key)
@ -233,7 +261,7 @@ class TransitionGroup extends Component {
}
}
_handleDoneLeaving (key) {
_handleDoneLeaving(key) {
// If we should immediately abort the leave,
// then skip this altogether
const idx = this.keysToAbortLeave.indexOf(key)
@ -249,7 +277,9 @@ class TransitionGroup extends Component {
delete this.currentlyTransitioningKeys[key]
const currentChildMapping = getChildMapping(toChildArray(this.props.children) || [])
const currentChildMapping = getChildMapping(
toChildArray(this.props.children) || [],
)
if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
// This entered again before it fully left. Add it again.
@ -261,15 +291,31 @@ class TransitionGroup extends Component {
}
}
render ({ childFactory, transitionLeave, transitionName, transitionAppear, transitionEnter, transitionLeaveTimeout, transitionEnterTimeout, transitionAppearTimeout, component, ...props }, { children }) {
render(
{
childFactory,
transitionLeave,
transitionName,
transitionAppear,
transitionEnter,
transitionLeaveTimeout,
transitionEnterTimeout,
transitionAppearTimeout,
component,
...props
},
{ children },
) {
// TODO: we could get rid of the need for the wrapper node
// by cloning a single child
const childrenToRender = Object.entries(children).map(([key, child]) => {
if (!child) return undefined
const childrenToRender = Object.entries(children)
.map(([key, child]) => {
if (!child) return undefined
const ref = linkRef(this, key);
return cloneElement(childFactory(child), { ref, key })
}).filter(Boolean)
const ref = linkRef(this, key)
return cloneElement(childFactory(child), { ref, key })
})
.filter(Boolean)
return h(component, props, childrenToRender)
}

View file

@ -1 +0,0 @@
export { default } from './Informer.jsx'

View file

@ -0,0 +1 @@
export { default } from './Informer.tsx'

View file

@ -0,0 +1,25 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"noImplicitAny": false,
"outDir": "./lib",
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"]
},
"resolveJsonModule": false,
"rootDir": "./src",
"skipLibCheck": true
},
"include": ["./src/**/*.*"],
"exclude": ["./src/**/*.test.ts"],
"references": [
{
"path": "../utils/tsconfig.build.json"
},
{
"path": "../core/tsconfig.build.json"
}
]
}

View file

@ -0,0 +1,21 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"],
},
},
"include": ["./package.json", "./src/**/*.*"],
"references": [
{
"path": "../utils/tsconfig.build.json",
},
{
"path": "../core/tsconfig.build.json",
},
],
}