|
@@ -1,31 +1,49 @@
|
|
|
-import { UIPlugin } from '@uppy/core'
|
|
|
+import { h, type ComponentChild } from 'preact'
|
|
|
+
|
|
|
+import { UIPlugin, Uppy, type UIPluginOptions } from '@uppy/core'
|
|
|
import toArray from '@uppy/utils/lib/toArray'
|
|
|
-import { h } from 'preact'
|
|
|
+import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
|
|
|
+import type { DefinePluginOpts } from '@uppy/core/lib/BasePlugin.js'
|
|
|
|
|
|
+// 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'
|
|
|
-import locale from './locale.js'
|
|
|
+import locale from './locale.ts'
|
|
|
+
|
|
|
+export interface FileInputOptions extends UIPluginOptions {
|
|
|
+ pretty?: boolean
|
|
|
+ inputName?: string
|
|
|
+}
|
|
|
+// Default options, must be kept in sync with @uppy/react/src/FileInput.js.
|
|
|
+const defaultOptions = {
|
|
|
+ pretty: true,
|
|
|
+ inputName: 'files[]',
|
|
|
+}
|
|
|
+
|
|
|
+// https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/files
|
|
|
+interface HTMLFileInputElement extends HTMLInputElement {
|
|
|
+ files: FileList
|
|
|
+}
|
|
|
|
|
|
-export default class FileInput extends UIPlugin {
|
|
|
+type Opts = DefinePluginOpts<FileInputOptions, keyof typeof defaultOptions>
|
|
|
+
|
|
|
+export default class FileInput<M extends Meta, B extends Body> extends UIPlugin<
|
|
|
+ Opts,
|
|
|
+ M,
|
|
|
+ B
|
|
|
+> {
|
|
|
static VERSION = packageJson.version
|
|
|
|
|
|
- constructor (uppy, opts) {
|
|
|
- super(uppy, opts)
|
|
|
+ input: HTMLFileInputElement | null
|
|
|
+
|
|
|
+ constructor(uppy: Uppy<M, B>, opts?: FileInputOptions) {
|
|
|
+ super(uppy, { ...defaultOptions, ...opts })
|
|
|
this.id = this.opts.id || 'FileInput'
|
|
|
this.title = 'File Input'
|
|
|
this.type = 'acquirer'
|
|
|
|
|
|
this.defaultLocale = locale
|
|
|
|
|
|
- // Default options, must be kept in sync with @uppy/react/src/FileInput.js.
|
|
|
- const defaultOptions = {
|
|
|
- target: null,
|
|
|
- pretty: true,
|
|
|
- inputName: 'files[]',
|
|
|
- }
|
|
|
-
|
|
|
- // Merge default options with the ones set by user
|
|
|
- this.opts = { ...defaultOptions, ...opts }
|
|
|
-
|
|
|
this.i18nInit()
|
|
|
|
|
|
this.render = this.render.bind(this)
|
|
@@ -33,7 +51,7 @@ export default class FileInput extends UIPlugin {
|
|
|
this.handleClick = this.handleClick.bind(this)
|
|
|
}
|
|
|
|
|
|
- addFiles (files) {
|
|
|
+ addFiles(files: File[]): void {
|
|
|
const descriptors = files.map((file) => ({
|
|
|
source: this.id,
|
|
|
name: file.name,
|
|
@@ -48,9 +66,9 @@ export default class FileInput extends UIPlugin {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- handleInputChange (event) {
|
|
|
+ private handleInputChange(event: Event) {
|
|
|
this.uppy.log('[FileInput] Something selected through input...')
|
|
|
- const files = toArray(event.target.files)
|
|
|
+ const files = toArray((event.target as HTMLFileInputElement).files)
|
|
|
this.addFiles(files)
|
|
|
|
|
|
// We clear the input after a file is selected, because otherwise
|
|
@@ -59,14 +77,15 @@ export default class FileInput extends UIPlugin {
|
|
|
// ___Why not use value="" on <input/> instead?
|
|
|
// Because if we use that method of clearing the input,
|
|
|
// Chrome will not trigger change if we drop the same file twice (Issue #768).
|
|
|
+ // @ts-expect-error yes
|
|
|
event.target.value = null // eslint-disable-line no-param-reassign
|
|
|
}
|
|
|
|
|
|
- handleClick () {
|
|
|
- this.input.click()
|
|
|
+ private handleClick() {
|
|
|
+ this.input!.click()
|
|
|
}
|
|
|
|
|
|
- render () {
|
|
|
+ render(): ComponentChild {
|
|
|
/* http://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/ */
|
|
|
const hiddenInputStyle = {
|
|
|
width: '0.1px',
|
|
@@ -75,25 +94,29 @@ export default class FileInput extends UIPlugin {
|
|
|
overflow: 'hidden',
|
|
|
position: 'absolute',
|
|
|
zIndex: -1,
|
|
|
- }
|
|
|
+ } satisfies JSX.IntrinsicElements['input']['style']
|
|
|
|
|
|
const { restrictions } = this.uppy.opts
|
|
|
- const accept = restrictions.allowedFileTypes ? restrictions.allowedFileTypes.join(',') : null
|
|
|
+ const accept =
|
|
|
+ restrictions.allowedFileTypes ?
|
|
|
+ restrictions.allowedFileTypes.join(',')
|
|
|
+ : undefined
|
|
|
|
|
|
return (
|
|
|
<div className="uppy-FileInput-container">
|
|
|
<input
|
|
|
className="uppy-FileInput-input"
|
|
|
- style={this.opts.pretty && hiddenInputStyle}
|
|
|
+ style={this.opts.pretty ? hiddenInputStyle : undefined}
|
|
|
type="file"
|
|
|
name={this.opts.inputName}
|
|
|
onChange={this.handleInputChange}
|
|
|
multiple={restrictions.maxNumberOfFiles !== 1}
|
|
|
accept={accept}
|
|
|
- ref={(input) => { this.input = input }}
|
|
|
+ ref={(input) => {
|
|
|
+ this.input = input as HTMLFileInputElement
|
|
|
+ }}
|
|
|
/>
|
|
|
- {this.opts.pretty
|
|
|
- && (
|
|
|
+ {this.opts.pretty && (
|
|
|
<button
|
|
|
className="uppy-FileInput-btn"
|
|
|
type="button"
|
|
@@ -101,19 +124,19 @@ export default class FileInput extends UIPlugin {
|
|
|
>
|
|
|
{this.i18n('chooseFiles')}
|
|
|
</button>
|
|
|
- )}
|
|
|
+ )}
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- install () {
|
|
|
+ install(): void {
|
|
|
const { target } = this.opts
|
|
|
if (target) {
|
|
|
this.mount(target, this)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- uninstall () {
|
|
|
+ uninstall(): void {
|
|
|
this.unmount()
|
|
|
}
|
|
|
}
|