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,56 @@
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<M extends Meta, B extends Body>

Check warning on line 13 in packages/@uppy/file-input/src/FileInput.tsx

View workflow job for this annotation

GitHub Actions / Lint JavaScript/TypeScript

'M' is defined but never used

Check warning on line 13 in packages/@uppy/file-input/src/FileInput.tsx

View workflow job for this annotation

GitHub Actions / Lint JavaScript/TypeScript

'B' is defined but never used
extends UIPluginOptions {
mifi marked this conversation as resolved.
Show resolved Hide resolved
pretty?: boolean
inputName?: string
}
// Default options, must be kept in sync with @uppy/react/src/FileInput.js.
const defaultOptions = {
pretty: true,
inputName: 'files[]',
}

type Opts<M extends Meta, B extends Body> = DefinePluginOpts<
FileInputOptions<M, B>,
keyof typeof defaultOptions
>
mifi marked this conversation as resolved.
Show resolved Hide resolved

export default class FileInput extends UIPlugin {
export default class FileInput<M extends Meta, B extends Body> extends UIPlugin<
Opts<M, B>,
mifi marked this conversation as resolved.
Show resolved Hide resolved
M,
B
> {
static VERSION = packageJson.version

constructor (uppy, opts) {
super(uppy, opts)
input: HTMLInputElement | null

constructor(uppy: Uppy<M, B>, opts?: FileInputOptions<M, B>) {
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 +65,9 @@
}
}

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 HTMLInputElement).files ?? [])
mifi marked this conversation as resolved.
Show resolved Hide resolved
this.addFiles(files)

// We clear the input after a file is selected, because otherwise
Expand All @@ -59,14 +76,15 @@
// ___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 {
aduh95 marked this conversation as resolved.
Show resolved Hide resolved
/* http://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/ */
const hiddenInputStyle = {
width: '0.1px',
Expand All @@ -75,45 +93,49 @@
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
}}
/>
{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'
35 changes: 35 additions & 0 deletions packages/@uppy/file-input/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"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"
}
]
}
30 changes: 30 additions & 0 deletions packages/@uppy/file-input/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"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"
}
]
}
Loading