Skip to content

Commit

Permalink
@uppy/file-input: refactor to TypeScript (#4954)
Browse files Browse the repository at this point in the history
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
Co-authored-by: Merlijn Vos <merlijn@soverin.net>
  • Loading branch information
3 people authored Feb 24, 2024
1 parent 0fd1a2a commit 1fe7297
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 32 deletions.
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/ */
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'
File renamed without changes.
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",
},
],
}

0 comments on commit 1fe7297

Please sign in to comment.