Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@uppy/provider-views: migrate to TS #4919

Merged
merged 21 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 */
Murderlon marked this conversation as resolved.
Show resolved Hide resolved
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,
Murderlon marked this conversation as resolved.
Show resolved Hide resolved
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>
)
}