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/file-input: refactor to TypeScript #4954

Merged
merged 13 commits into from
Feb 24, 2024
1 change: 1 addition & 0 deletions packages/@uppy/file-input/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
Original file line number Diff line number Diff line change
@@ -1,39 +1,57 @@
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)
this.handleInputChange = this.handleInputChange.bind(this)
this.handleClick = this.handleClick.bind(this)
}

addFiles (files) {
addFiles(files: File[]): void {
const descriptors = files.map((file) => ({
source: this.id,
name: file.name,
Expand All @@ -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
Expand All @@ -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/ */
aduh95 marked this conversation as resolved.
Show resolved Hide resolved
const hiddenInputStyle = {
width: '0.1px',
Expand All @@ -75,45 +94,49 @@ 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"
onClick={this.handleClick}
>
{this.i18n('chooseFiles')}
</button>
)}
)}
</div>
)
}

install () {
install(): void {
const { target } = this.opts
if (target) {
this.mount(target, this)
}
}

uninstall () {
uninstall(): void {
this.unmount()
}
}
1 change: 0 additions & 1 deletion packages/@uppy/file-input/src/index.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/@uppy/file-input/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './FileInput.tsx'
25 changes: 25 additions & 0 deletions packages/@uppy/file-input/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
21 changes: 21 additions & 0 deletions packages/@uppy/file-input/tsconfig.json
Original file line number Diff line number Diff line change
@@ -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",
},
],
}