Skip to content

Commit

Permalink
@uppy/provider-views: migrate to TS (#4919)
Browse files Browse the repository at this point in the history
Co-authored-by: Antoine du Hamel <[email protected]>
  • Loading branch information
Murderlon and aduh95 authored Feb 27, 2024
1 parent 12fb3ae commit a4bbd82
Show file tree
Hide file tree
Showing 34 changed files with 1,186 additions and 565 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
"watch:js": "npm-run-all --parallel watch:js:bundle watch:js:lib",
"watch": "npm-run-all --parallel watch:css watch:js"
},
"alias": {
"preact/jsx-dev-runtime": "preact/jsx-runtime"
},
"resolutions": {
"@types/eslint@^7.2.13": "^8.2.0",
"@types/react": "^17",
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/provider-views/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
38 changes: 0 additions & 38 deletions packages/@uppy/provider-views/src/Breadcrumbs.jsx

This file was deleted.

54 changes: 54 additions & 0 deletions packages/@uppy/provider-views/src/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { UnknownProviderPluginState } from '@uppy/core/lib/Uppy'
import { h, Fragment } from 'preact'
import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
import type ProviderView from './ProviderView'

type BreadcrumbProps = {
getFolder: () => void
title: string
isLast: boolean
}

const Breadcrumb = (props: BreadcrumbProps) => {
const { getFolder, title, isLast } = props

return (
<Fragment>
<button
type="button"
className="uppy-u-reset uppy-c-btn"
onClick={getFolder}
>
{title}
</button>
{!isLast ? ' / ' : ''}
</Fragment>
)
}

type BreadcrumbsProps<M extends Meta, B extends Body> = {
getFolder: ProviderView<M, B>['getFolder']
title: string
breadcrumbsIcon: JSX.Element
breadcrumbs: UnknownProviderPluginState['breadcrumbs']
}

export default function Breadcrumbs<M extends Meta, B extends Body>(
props: BreadcrumbsProps<M, B>,
): JSX.Element {
const { getFolder, title, breadcrumbsIcon, breadcrumbs } = props

return (
<div className="uppy-Provider-breadcrumbs">
<div className="uppy-Provider-breadcrumbsIcon">{breadcrumbsIcon}</div>
{breadcrumbs.map((directory, i) => (
<Breadcrumb
key={directory.id}
getFolder={() => getFolder(directory.requestPath, directory.name)}
title={i === 0 ? title : directory.name}
isLast={i + 1 === breadcrumbs.length}
/>
))}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
/* eslint-disable react/require-default-props */
import { h } from 'preact'

import classNames from 'classnames'
import remoteFileObjToLocal from '@uppy/utils/lib/remoteFileObjToLocal'
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 SearchFilterInput from './SearchFilterInput.jsx'
import FooterActions from './FooterActions.jsx'
import Item from './Item/index.jsx'
import type { CompanionFile } from '@uppy/utils/lib/CompanionFile'
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import type { I18n } from '@uppy/utils/lib/Translator'
import type Uppy from '@uppy/core'
import SearchFilterInput from './SearchFilterInput.tsx'
import FooterActions from './FooterActions.tsx'
import Item from './Item/index.tsx'

const VIRTUAL_SHARED_DIR = 'shared-with-me'

function ListItem (props) {
type ListItemProps<M extends Meta, B extends Body> = {
currentSelection: any[]
uppyFiles: UppyFile<M, B>[]
viewType: string
isChecked: (file: any) => boolean
toggleCheckbox: (event: Event, file: CompanionFile) => void
recordShiftKeyPress: (event: KeyboardEvent | MouseEvent) => void
showTitles: boolean
i18n: I18n
validateRestrictions: Uppy<M, B>['validateRestrictions']
getNextFolder?: (folder: any) => void
f: CompanionFile
}

function ListItem<M extends Meta, B extends Body>(
props: ListItemProps<M, B>,
): JSX.Element {
const {
currentSelection,
uppyFiles,
Expand All @@ -22,52 +45,84 @@ function ListItem (props) {
i18n,
validateRestrictions,
getNextFolder,
columns,
f,
} = props

if (f.isFolder) {
return Item({
columns,
return Item<M, B>({
showTitles,
viewType,
i18n,
id: f.id,
title: f.name,
getItemIcon: () => f.icon,
isChecked: isChecked(f),
toggleCheckbox: (event) => toggleCheckbox(event, f),
toggleCheckbox: (event: Event) => toggleCheckbox(event, f),
recordShiftKeyPress,
type: 'folder',
isDisabled: isChecked(f)?.loading,
// TODO: when was this supposed to be true?
isDisabled: false,
isCheckboxDisabled: f.id === VIRTUAL_SHARED_DIR,
handleFolderClick: () => getNextFolder(f),
// getNextFolder always exists when f.isFolder is true
handleFolderClick: () => getNextFolder!(f),
})
}
const restrictionError = validateRestrictions(remoteFileObjToLocal(f), [
...uppyFiles,
...currentSelection,
])

return Item({
return Item<M, B>({
id: f.id,
title: f.name,
author: f.author,
getItemIcon: () => f.icon,
isChecked: isChecked(f),
toggleCheckbox: (event) => toggleCheckbox(event, f),
toggleCheckbox: (event: Event) => toggleCheckbox(event, f),
isCheckboxDisabled: false,
recordShiftKeyPress,
columns,
showTitles,
viewType,
i18n,
type: 'file',
isDisabled: restrictionError && !isChecked(f),
isDisabled: Boolean(restrictionError) && !isChecked(f),
restrictionError,
})
}

function Browser (props) {
type BrowserProps<M extends Meta, B extends Body> = {
currentSelection: any[]
folders: CompanionFile[]
files: CompanionFile[]
uppyFiles: UppyFile<M, B>[]
viewType: string
headerComponent?: JSX.Element
showBreadcrumbs: boolean
isChecked: (file: any) => boolean
toggleCheckbox: (event: Event, file: CompanionFile) => void
recordShiftKeyPress: (event: KeyboardEvent | MouseEvent) => void
handleScroll: (event: Event) => Promise<void>
showTitles: boolean
i18n: I18n
validateRestrictions: Uppy<M, B>['validateRestrictions']
isLoading: boolean | string
showSearchFilter: boolean
search: (query: string) => void
searchTerm?: string | null
clearSearch: () => void
searchOnInput: boolean
searchInputLabel: string
clearSearchLabel: string
getNextFolder?: (folder: any) => void
cancel: () => void
done: () => void
noResultsLabel: string
loadAllFiles?: boolean
}

function Browser<M extends Meta, B extends Body>(
props: BrowserProps<M, B>,
): JSX.Element {
const {
currentSelection,
folders,
Expand All @@ -94,7 +149,6 @@ function Browser (props) {
getNextFolder,
cancel,
done,
columns,
noResultsLabel,
loadAllFiles,
} = props
Expand Down Expand Up @@ -156,7 +210,7 @@ function Browser (props) {
<ul className="uppy-ProviderBrowser-list">
<VirtualList
data={rows}
renderRow={(f) => (
renderRow={(f: CompanionFile) => (
<ListItem
currentSelection={currentSelection}
uppyFiles={uppyFiles}
Expand All @@ -168,7 +222,6 @@ function Browser (props) {
i18n={i18n}
validateRestrictions={validateRestrictions}
getNextFolder={getNextFolder}
columns={columns}
f={f}
/>
)}
Expand All @@ -186,7 +239,7 @@ function Browser (props) {
onScroll={handleScroll}
role="listbox"
// making <ul> not focusable for firefox
tabIndex="-1"
tabIndex={-1}
>
{rows.map((f) => (
<ListItem
Expand All @@ -200,7 +253,6 @@ function Browser (props) {
i18n={i18n}
validateRestrictions={validateRestrictions}
getNextFolder={getNextFolder}
columns={columns}
f={f}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component, toChildArray } from 'preact'

export default class CloseWrapper extends Component {
componentWillUnmount () {
export default class CloseWrapper extends Component<{ onUnmount: () => void }> {
componentWillUnmount(): void {
const { onUnmount } = this.props
onUnmount()
}

render () {
render(): ReturnType<typeof toChildArray>[0] {
const { children } = this.props
return toChildArray(children)[0]
}
Expand Down
16 changes: 0 additions & 16 deletions packages/@uppy/provider-views/src/FooterActions.jsx

This file was deleted.

35 changes: 35 additions & 0 deletions packages/@uppy/provider-views/src/FooterActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { h } from 'preact'
import type { I18n } from '@uppy/utils/lib/Translator'

export default function FooterActions({
cancel,
done,
i18n,
selected,
}: {
cancel: () => void
done: () => void
i18n: I18n
selected: number
}): JSX.Element {
return (
<div className="uppy-ProviderBrowser-footer">
<button
className="uppy-u-reset uppy-c-btn uppy-c-btn-primary"
onClick={done}
type="button"
>
{i18n('selectX', {
smart_count: selected,
})}
</button>
<button
className="uppy-u-reset uppy-c-btn uppy-c-btn-link"
onClick={cancel}
type="button"
>
{i18n('cancel')}
</button>
</div>
)
}
Loading

0 comments on commit a4bbd82

Please sign in to comment.