diff --git a/packages/@uppy/dashboard/src/components/FileList.tsx b/packages/@uppy/dashboard/src/components/FileList.tsx index 0ec98ef363..a636b8fa4b 100644 --- a/packages/@uppy/dashboard/src/components/FileList.tsx +++ b/packages/@uppy/dashboard/src/components/FileList.tsx @@ -1,7 +1,5 @@ import { h } from 'preact' import { useMemo } from 'preact/hooks' -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore untyped import VirtualList from '@uppy/utils/lib/VirtualList' import FileItem from './FileItem/index.tsx' diff --git a/packages/@uppy/utils/src/VirtualList.jsx b/packages/@uppy/utils/src/VirtualList.tsx similarity index 77% rename from packages/@uppy/utils/src/VirtualList.jsx rename to packages/@uppy/utils/src/VirtualList.tsx index 0be5fe96b7..1a9817074c 100644 --- a/packages/@uppy/utils/src/VirtualList.jsx +++ b/packages/@uppy/utils/src/VirtualList.tsx @@ -26,7 +26,8 @@ * - Tweaked styles for Uppy's Dashboard use case */ -import { h, Component } from 'preact' +import { h, Component } from 'preact' +import type { HTMLAttributes } from 'preact/compat' const STYLE_INNER = { position: 'relative', @@ -51,8 +52,21 @@ const STYLE_CONTENT = { overflow: 'visible', } -class VirtualList extends Component { - constructor (props) { +type Props = Omit, 'data'> & { + data: T[] + rowHeight: number + renderRow: (item: T) => h.JSX.Element + // eslint-disable-next-line react/require-default-props + overscanCount?: number | undefined +} + +class VirtualList extends Component< + Props, + { offset: number; height: number } +> { + focusElement: HTMLElement | null + + constructor(props: Props) { super(props) // The currently focused node, used to retain focus when the visible rows change. @@ -65,58 +79,61 @@ class VirtualList extends Component { } } - componentDidMount () { + componentDidMount(): void { this.resize() window.addEventListener('resize', this.handleResize) } // TODO: refactor to stable lifecycle method // eslint-disable-next-line - componentWillUpdate () { - if (this.base.contains(document.activeElement)) { - this.focusElement = document.activeElement + componentWillUpdate() { + if (this.base!.contains(document.activeElement)) { + this.focusElement = document.activeElement as HTMLElement } } - componentDidUpdate () { + componentDidUpdate(): void { // Maintain focus when rows are added and removed. - if (this.focusElement && this.focusElement.parentNode - && document.activeElement !== this.focusElement) { - this.focusElement.focus() + if ( + this.focusElement && + this.focusElement.parentNode && + document.activeElement !== this.focusElement + ) { + this.focusElement!.focus() } this.focusElement = null this.resize() } - componentWillUnmount () { + componentWillUnmount(): void { window.removeEventListener('resize', this.handleResize) } - handleScroll = () => { - this.setState({ offset: this.base.scrollTop }) + handleScroll = (): void => { + this.setState({ offset: (this.base! as HTMLElement).scrollTop }) } - handleResize = () => { + handleResize = (): void => { this.resize() } - resize () { + resize(): void { const { height } = this.state - if (height !== this.base.offsetHeight) { + if (height !== (this.base! as HTMLElement).offsetHeight) { this.setState({ - height: this.base.offsetHeight, + height: (this.base! as HTMLElement).offsetHeight, }) } } - render ({ + render({ data, rowHeight, renderRow, overscanCount = 10, ...props - }) { + }: Props): h.JSX.Element { const { offset, height } = this.state // first visible row index let start = Math.floor(offset / rowHeight) diff --git a/packages/@uppy/utils/tsconfig.json b/packages/@uppy/utils/tsconfig.json index 3148361844..fca37bdf5b 100644 --- a/packages/@uppy/utils/tsconfig.json +++ b/packages/@uppy/utils/tsconfig.json @@ -5,6 +5,6 @@ "emitDeclarationOnly": false, "noEmit": true, }, - "include": ["src/*.ts"], + "include": ["src/*.ts", "src/*.tsx"], "references": [], }