Ver código fonte

@uppy/form: migrate to TS (#4937)

Co-authored-by: Antoine du Hamel <antoine@transloadit.com>
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
Merlijn Vos 1 ano atrás
pai
commit
10c085301a

+ 1 - 0
packages/@uppy/form/.npmignore

@@ -0,0 +1 @@
+tsconfig.*

+ 0 - 144
packages/@uppy/form/src/index.js

@@ -1,144 +0,0 @@
-import BasePlugin from '@uppy/core/lib/BasePlugin.js'
-import findDOMElement from '@uppy/utils/lib/findDOMElement'
-import toArray from '@uppy/utils/lib/toArray'
-
-import getFormData from 'get-form-data'
-
-import packageJson from '../package.json'
-
-/**
- * Form
- */
-export default class Form extends BasePlugin {
-  static VERSION = packageJson.version
-
-  /** @type {HTMLFormElement} */
-  form // TODO: make this private (or at least, mark it as readonly)
-
-  constructor (uppy, opts) {
-    super(uppy, opts)
-    this.type = 'acquirer'
-    this.id = this.opts.id || 'Form'
-    this.title = 'Form'
-
-    // set default options
-    const defaultOptions = {
-      target: null,
-      resultName: 'uppyResult',
-      getMetaFromForm: true,
-      addResultToForm: true,
-      submitOnSuccess: false,
-      triggerUploadOnSubmit: false,
-    }
-
-    // merge default options with the ones set by user
-    this.opts = { ...defaultOptions, ...opts }
-
-    this.handleFormSubmit = this.handleFormSubmit.bind(this)
-    this.handleUploadStart = this.handleUploadStart.bind(this)
-    this.handleSuccess = this.handleSuccess.bind(this)
-    this.addResultToForm = this.addResultToForm.bind(this)
-    this.getMetaFromForm = this.getMetaFromForm.bind(this)
-  }
-
-  handleUploadStart () {
-    if (this.opts.getMetaFromForm) {
-      this.getMetaFromForm()
-    }
-  }
-
-  handleSuccess (result) {
-    if (this.opts.addResultToForm) {
-      this.addResultToForm(result)
-    }
-
-    if (this.opts.submitOnSuccess) {
-      this.form.requestSubmit()
-    }
-  }
-
-  handleFormSubmit (ev) {
-    if (this.opts.triggerUploadOnSubmit) {
-      ev.preventDefault()
-      const elements = toArray(ev.target.elements)
-      const disabledByUppy = []
-      elements.forEach((el) => {
-        const isButton = el.tagName === 'BUTTON' || (el.tagName === 'INPUT' && el.type === 'submit')
-        if (isButton && !el.disabled) {
-          el.disabled = true // eslint-disable-line no-param-reassign
-          disabledByUppy.push(el)
-        }
-      })
-      this.uppy.upload().then(() => {
-        disabledByUppy.forEach((button) => {
-          button.disabled = false // eslint-disable-line no-param-reassign
-        })
-      }, (err) => {
-        disabledByUppy.forEach((button) => {
-          button.disabled = false // eslint-disable-line no-param-reassign
-        })
-        return Promise.reject(err)
-      }).catch((err) => {
-        this.uppy.log(err.stack || err.message || err)
-      })
-    }
-  }
-
-  addResultToForm (result) {
-    this.uppy.log('[Form] Adding result to the original form:')
-    this.uppy.log(result)
-
-    let resultInput = this.form.querySelector(`[name="${this.opts.resultName}"]`)
-    if (resultInput) {
-      // Append new result to the previous result array.
-      // If the previous result is empty, or not an array,
-      // set it to an empty array.
-      let updatedResult
-      try {
-        updatedResult = JSON.parse(resultInput.value)
-      } catch (err) {
-        // Nothing, since we check for array below anyway
-      }
-
-      if (!Array.isArray(updatedResult)) {
-        updatedResult = []
-      }
-      updatedResult.push(result)
-      resultInput.value = JSON.stringify(updatedResult)
-      return
-    }
-
-    resultInput = document.createElement('input')
-    resultInput.name = this.opts.resultName
-    resultInput.type = 'hidden'
-    resultInput.value = JSON.stringify([result])
-
-    this.form.appendChild(resultInput)
-  }
-
-  getMetaFromForm () {
-    const formMeta = getFormData(this.form)
-    // We want to exclude meta the the Form plugin itself has added
-    // See https://github.com/transloadit/uppy/issues/1637
-    delete formMeta[this.opts.resultName]
-    this.uppy.setMeta(formMeta)
-  }
-
-  install () {
-    this.form = findDOMElement(this.opts.target)
-    if (!this.form || this.form.nodeName !== 'FORM') {
-      this.uppy.log('Form plugin requires a <form> target element passed in options to operate, none was found', 'error')
-      return
-    }
-
-    this.form.addEventListener('submit', this.handleFormSubmit)
-    this.uppy.on('upload', this.handleUploadStart)
-    this.uppy.on('complete', this.handleSuccess)
-  }
-
-  uninstall () {
-    this.form.removeEventListener('submit', this.handleFormSubmit)
-    this.uppy.off('upload', this.handleUploadStart)
-    this.uppy.off('complete', this.handleSuccess)
-  }
-}

+ 174 - 0
packages/@uppy/form/src/index.ts

@@ -0,0 +1,174 @@
+import BasePlugin, { type DefinePluginOpts } from '@uppy/core/lib/BasePlugin.js'
+import findDOMElement from '@uppy/utils/lib/findDOMElement'
+import toArray from '@uppy/utils/lib/toArray'
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore untyped
+import getFormData from 'get-form-data'
+
+import type { UIPluginOptions, Uppy, UppyEventMap } from '@uppy/core'
+import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
+// 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'
+
+type Result<M extends Meta, B extends Body> = Parameters<
+  UppyEventMap<M, B>['complete']
+>[0]
+
+export interface FormOptions extends UIPluginOptions {
+  resultName?: string
+  getMetaFromForm?: boolean
+  addResultToForm?: boolean
+  submitOnSuccess?: boolean
+  triggerUploadOnSubmit?: boolean
+}
+
+const defaultOptions = {
+  resultName: 'uppyResult',
+  getMetaFromForm: true,
+  addResultToForm: true,
+  submitOnSuccess: false,
+  triggerUploadOnSubmit: false,
+}
+
+type Opts = DefinePluginOpts<FormOptions, keyof typeof defaultOptions>
+
+function assertHTMLFormElement(input: Node | null): HTMLFormElement {
+  if (input == null || input.nodeName !== 'FORM') {
+    throw new Error('ASSERTION FAILED: the target is not a <form> element', {
+      cause: input,
+    })
+  }
+  return input as any
+}
+
+export default class Form<M extends Meta, B extends Body> extends BasePlugin<
+  Opts,
+  M,
+  B
+> {
+  static VERSION = packageJson.version
+
+  form: HTMLFormElement // TODO: make this private (or at least, mark it as readonly)
+
+  constructor(uppy: Uppy<M, B>, opts?: FormOptions) {
+    super(uppy, { ...defaultOptions, ...opts })
+    this.type = 'acquirer'
+    this.id = this.opts.id || 'Form'
+
+    this.handleFormSubmit = this.handleFormSubmit.bind(this)
+    this.handleUploadStart = this.handleUploadStart.bind(this)
+    this.handleSuccess = this.handleSuccess.bind(this)
+    this.addResultToForm = this.addResultToForm.bind(this)
+    this.getMetaFromForm = this.getMetaFromForm.bind(this)
+  }
+
+  handleUploadStart(): void {
+    if (this.opts.getMetaFromForm) {
+      this.getMetaFromForm()
+    }
+  }
+
+  handleSuccess(result: Result<M, B>): void {
+    if (this.opts.addResultToForm) {
+      this.addResultToForm(result)
+    }
+
+    if (this.opts.submitOnSuccess) {
+      this.form.requestSubmit()
+    }
+  }
+
+  handleFormSubmit(ev: Event): void {
+    if (this.opts.triggerUploadOnSubmit) {
+      ev.preventDefault()
+      const elements = toArray((ev.target as HTMLFormElement).elements)
+      const disabledByUppy: HTMLButtonElement[] = []
+      elements.forEach((el) => {
+        const isButton =
+          el.tagName === 'BUTTON' ||
+          (el.tagName === 'INPUT' &&
+            (el as HTMLButtonElement).type === 'submit')
+        if (isButton && !(el as HTMLButtonElement).disabled) {
+          ;(el as HTMLButtonElement).disabled = true // eslint-disable-line no-param-reassign
+          disabledByUppy.push(el as HTMLButtonElement)
+        }
+      })
+      this.uppy
+        .upload()
+        .then(
+          () => {
+            disabledByUppy.forEach((button) => {
+              button.disabled = false // eslint-disable-line no-param-reassign
+            })
+          },
+          (err) => {
+            disabledByUppy.forEach((button) => {
+              button.disabled = false // eslint-disable-line no-param-reassign
+            })
+            return Promise.reject(err)
+          },
+        )
+        .catch((err) => {
+          this.uppy.log(err.stack || err.message || err)
+        })
+    }
+  }
+
+  addResultToForm(result: Result<M, B>): void {
+    this.uppy.log('[Form] Adding result to the original form:')
+    this.uppy.log(result)
+
+    let resultInput: HTMLInputElement | null = this.form.querySelector(
+      `[name="${this.opts.resultName}"]`,
+    )
+    if (resultInput) {
+      // Append new result to the previous result array.
+      // If the previous result is empty, or not an array,
+      // set it to an empty array.
+      let updatedResult
+      try {
+        updatedResult = JSON.parse(resultInput.value)
+      } catch (err) {
+        // Nothing, since we check for array below anyway
+      }
+
+      if (!Array.isArray(updatedResult)) {
+        updatedResult = []
+      }
+      updatedResult.push(result)
+      resultInput.value = JSON.stringify(updatedResult)
+      return
+    }
+
+    resultInput = document.createElement('input')
+    resultInput.name = this.opts.resultName
+    resultInput.type = 'hidden'
+    resultInput.value = JSON.stringify([result])
+
+    this.form.appendChild(resultInput)
+  }
+
+  getMetaFromForm(): void {
+    const formMeta = getFormData(this.form)
+    // We want to exclude meta the the Form plugin itself has added
+    // See https://github.com/transloadit/uppy/issues/1637
+    delete formMeta[this.opts.resultName]
+    this.uppy.setMeta(formMeta)
+  }
+
+  install(): void {
+    this.form = assertHTMLFormElement(findDOMElement(this.opts.target))
+
+    this.form.addEventListener('submit', this.handleFormSubmit)
+    this.uppy.on('upload', this.handleUploadStart)
+    this.uppy.on('complete', this.handleSuccess)
+  }
+
+  uninstall(): void {
+    this.form.removeEventListener('submit', this.handleFormSubmit)
+    this.uppy.off('upload', this.handleUploadStart)
+    this.uppy.off('complete', this.handleSuccess)
+  }
+}

+ 25 - 0
packages/@uppy/form/tsconfig.build.json

@@ -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 - 0
packages/@uppy/form/tsconfig.json

@@ -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",
+    },
+  ],
+}