瀏覽代碼

[Dashboard] Allow setting the input type when editing files in Dashboard plugin (#2147)

* Added possibility of specifying form field type.

* remove log statements

* Change to allow providing custom render function

* Add Types and Docs.

* Pass Uppy-styled CSS class names, so developers can leverege them when adding their custom inputs

@goto-bus-stop as we’ve discussed, what do you think?

* Fix var name

* dashboard: make typings for `render()` stricter

so people will get type errors if they try to return React elements or
raw DOM nodes.

Co-authored-by: Artur Paikin <artur@arturpaikin.com>
Co-authored-by: Renée Kooi <renee@kooi.me>
Leonardo Galli 5 年之前
父節點
當前提交
8735c896a5

+ 25 - 14
packages/@uppy/dashboard/src/components/FileCard/index.js

@@ -29,11 +29,11 @@ class FileCard extends Component {
     }
   }
 
-  tempStoreMeta = (ev, name) => {
+  updateMeta = (newVal, name) => {
     this.setState({
       formState: {
         ...this.state.formState,
-        [name]: ev.target.value
+        [name]: newVal
       }
     })
   }
@@ -49,24 +49,35 @@ class FileCard extends Component {
 
   renderMetaFields = () => {
     const metaFields = this.props.metaFields || []
+    const fieldCSSClasses = {
+      text: 'uppy-u-reset uppy-c-textInput uppy-Dashboard-FileCard-input'
+    }
 
     return metaFields.map((field) => {
       const id = `uppy-Dashboard-FileCard-input-${field.id}`
       return (
         <fieldset key={field.id} class="uppy-Dashboard-FileCard-fieldset">
           <label class="uppy-Dashboard-FileCard-label" for={id}>{field.name}</label>
-          <input
-            class="uppy-u-reset uppy-c-textInput uppy-Dashboard-FileCard-input"
-            id={id}
-            type="text"
-            value={this.state.formState[field.id]}
-            placeholder={field.placeholder}
-            onkeyup={this.saveOnEnter}
-            onkeydown={this.saveOnEnter}
-            onkeypress={this.saveOnEnter}
-            oninput={ev => this.tempStoreMeta(ev, field.id)}
-            data-uppy-super-focusable
-          />
+          {field.render !== undefined
+            ? field.render({
+              value: this.state.formState[field.id],
+              onChange: (newVal) => this.updateMeta(newVal, field.id),
+              fieldCSSClasses: fieldCSSClasses
+            }, h)
+            : (
+              <input
+                class={fieldCSSClasses.text}
+                id={id}
+                type={field.type || 'text'}
+                value={this.state.formState[field.id]}
+                placeholder={field.placeholder}
+                onkeyup={this.saveOnEnter}
+                onkeydown={this.saveOnEnter}
+                onkeypress={this.saveOnEnter}
+                oninput={ev => this.updateMeta(ev.target.value, field.id)}
+                data-uppy-super-focusable
+              />
+            )}
         </fieldset>
       )
     })

+ 2 - 0
packages/@uppy/dashboard/types/index.d.ts

@@ -1,11 +1,13 @@
 import Uppy = require('@uppy/core')
 import StatusBar = require('@uppy/status-bar')
 import DashboardLocale = require('./generatedLocale')
+import Preact = require('preact')
 
 interface MetaField {
   id: string
   name: string
   placeholder?: string
+  render?(field: {value: string, onChange(newVal: string): void}, h: typeof Preact.h): Preact.VNode
 }
 
 declare module Dashboard {

+ 18 - 0
packages/@uppy/dashboard/types/index.test-d.ts

@@ -25,6 +25,24 @@ import Dashboard = require('../')
         id: 'license',
         name: 'License',
         placeholder: 'Creative Commons, Apache 2.0, ...'
+      },
+      {
+        id: 'public',
+        name: 'Public',
+        render ({ value, onChange }, h) {
+          expectType<string>(value)
+          expectType<(val: string) => void>(onChange)
+          // `h` should be the Preact `h`
+          expectError(h([], 'error'))
+          return h('input', {
+            type: 'checkbox',
+            checked: value === 'yes',
+            onChange: (event) => {
+              expectType<Event>(event)
+              onChange((event.target as HTMLInputElement).checked ? 'yes' : 'no')
+            }
+          })
+        }
       }
     ]
   })

+ 9 - 2
website/src/docs/dashboard.md

@@ -198,7 +198,11 @@ An array of UI field objects that will be shown when a user clicks the “edit
 
 - `id`, the name of the meta field. Note: this will also be used in CSS/HTML as part of the `id` attribute, so it’s better to [avoid using characters like periods, semicolons, etc](https://stackoverflow.com/a/79022).
 - `name`, the label shown in the interface.
-- `placeholder`, the text shown when no value is set in the field.
+- `placeholder`, the text shown when no value is set in the field. (Not needed when a custom render function is provided)
+
+Optionally, you can specify `render: ({value, onChange}, h) => void`, a function for rendering a custom form element.
+It gets passed `({value, onChange}, h)` where `value` is the current value of the meta field, `onChange: (newVal) => void` is a function saving the new value and `h` is the `createElement` function from [preact](https://preactjs.com/guide/v10/api-reference#h--createelement).
+`h` can be useful when using uppy from plain JavaScript, where you cannot write JSX.
 
 ```js
 .use(Dashboard, {
@@ -206,7 +210,10 @@ An array of UI field objects that will be shown when a user clicks the “edit
   metaFields: [
     { id: 'name', name: 'Name', placeholder: 'file name' },
     { id: 'license', name: 'License', placeholder: 'specify license' },
-    { id: 'caption', name: 'Caption', placeholder: 'describe what the image is about' }
+    { id: 'caption', name: 'Caption', placeholder: 'describe what the image is about' },
+    { id: 'public', name: 'Public', render: function({value, onChange}, h) {
+      return h('input', { type: 'checkbox', onChange: (ev) => onChange(ev.target.checked ? 'on' : 'off'), defaultChecked: value === 'on' })
+    } }
   ]
 })
 ```