@overmap-ai/forms 1.0.15 → 1.0.17-master.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/pre-commit +6 -0
- package/.prettierrc.json +10 -0
- package/.storybook/StoryDecorator.tsx +22 -0
- package/.storybook/main.ts +20 -0
- package/.storybook/palettes/green.css +66 -0
- package/.storybook/palettes/red.css +66 -0
- package/.storybook/preview.css +39 -0
- package/.storybook/preview.tsx +31 -0
- package/.storybook/tailwind-theme/accentPalette.css +181 -0
- package/.storybook/tailwind-theme/backgrounds.css +11 -0
- package/.storybook/tailwind-theme/basePalette.css +178 -0
- package/dev/publish-alpha.sh +13 -0
- package/dev/publish-patch.sh +3 -0
- package/dist/ColorPicker/ColorPicker.d.ts +10 -0
- package/dist/ColorPicker/index.d.ts +1 -0
- package/dist/FileBadge/FileBadge.d.ts +7 -0
- package/dist/FileBadge/index.d.ts +1 -0
- package/dist/FileCard/FileCard.d.ts +8 -0
- package/dist/FileCard/index.d.ts +1 -0
- package/dist/FileIcon/FileIcon.d.ts +4 -0
- package/dist/FileIcon/index.d.ts +1 -0
- package/dist/FileViewer/FileViewerProvider.d.ts +2 -0
- package/dist/FileViewer/context.d.ts +4 -0
- package/dist/FileViewer/index.d.ts +3 -0
- package/dist/FileViewer/typings.d.ts +5 -0
- package/dist/ImageCard/ImageCard.d.ts +9 -0
- package/dist/ImageCard/index.d.ts +1 -0
- package/dist/ImageMarkup/ImageMarkup.d.ts +14 -0
- package/dist/ImageMarkup/index.d.ts +1 -0
- package/dist/ImageViewer/ImageViewer.d.ts +7 -0
- package/dist/ImageViewer/constants.d.ts +1 -0
- package/dist/ImageViewer/index.d.ts +2 -0
- package/dist/PDFViewer/PDFViewer.d.ts +7 -0
- package/dist/PDFViewer/constants.d.ts +1 -0
- package/dist/PDFViewer/index.d.ts +2 -0
- package/dist/SpreadsheetViewer/SpreadsheetViewer.d.ts +7 -0
- package/dist/SpreadsheetViewer/constants.d.ts +1 -0
- package/dist/SpreadsheetViewer/index.d.ts +2 -0
- package/dist/{builder → forms/builder}/DropDispatch.d.ts +2 -2
- package/dist/forms/builder/FieldActions.d.ts +13 -0
- package/dist/forms/builder/FieldBuilder.d.ts +10 -0
- package/dist/forms/builder/FieldSectionWithActions.d.ts +10 -0
- package/dist/forms/builder/FieldWithActions.d.ts +9 -0
- package/dist/forms/builder/FieldsEditor.d.ts +5 -0
- package/dist/forms/builder/FormBuilder.d.ts +25 -0
- package/dist/forms/builder/constants.d.ts +18 -0
- package/dist/forms/builder/hooks.d.ts +7 -0
- package/dist/forms/builder/index.d.ts +2 -0
- package/dist/{builder → forms/builder}/typings.d.ts +2 -1
- package/dist/forms/builder/utils.d.ts +23 -0
- package/dist/forms/constants.d.ts +3 -0
- package/dist/forms/constantsJsx.d.ts +9 -0
- package/dist/{fields → forms/fields}/BaseField/BaseField.d.ts +23 -10
- package/dist/forms/fields/BaseField/hooks.d.ts +388 -0
- package/dist/forms/fields/BaseField/index.d.ts +4 -0
- package/dist/{fields → forms/fields}/BaseField/layouts.d.ts +11 -5
- package/dist/{fields → forms/fields}/BaseField/typings.d.ts +2 -2
- package/dist/{fields → forms/fields}/BooleanField/BooleanField.d.ts +12 -6
- package/dist/forms/fields/BooleanField/BooleanInput.d.ts +3 -0
- package/dist/forms/fields/BooleanField/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/CustomField/CustomField.d.ts +12 -6
- package/dist/{fields → forms/fields}/CustomField/FieldInputClonerField/FieldInputCloner.d.ts +2 -3
- package/dist/{fields → forms/fields}/CustomField/FieldInputClonerField/FieldInputClonerField.d.ts +3 -3
- package/dist/forms/fields/CustomField/FieldInputClonerField/index.d.ts +3 -0
- package/dist/forms/fields/CustomField/FieldInputClonerField/typings.d.ts +5 -0
- package/dist/forms/fields/CustomField/index.d.ts +1 -0
- package/dist/forms/fields/DateField/DateField.d.ts +22 -0
- package/dist/forms/fields/DateField/DateInput.d.ts +3 -0
- package/dist/forms/fields/DateField/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/FieldSection/FieldSection.d.ts +13 -9
- package/dist/forms/fields/FieldSection/FieldSectionLayout.d.ts +6 -0
- package/dist/forms/fields/FieldSection/index.d.ts +1 -0
- package/dist/forms/fields/MultiStringField/MultiStringField.d.ts +40 -0
- package/dist/forms/fields/MultiStringField/MultiStringInput.d.ts +7 -0
- package/dist/forms/fields/MultiStringField/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/NumberField/NumberField.d.ts +27 -10
- package/dist/forms/fields/NumberField/NumberInput.d.ts +3 -0
- package/dist/forms/fields/NumberField/index.d.ts +2 -0
- package/dist/forms/fields/QrField/QrField.d.ts +21 -0
- package/dist/forms/fields/QrField/QrInput.d.ts +9 -0
- package/dist/forms/fields/QrField/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/SelectField/BaseSelectField.d.ts +12 -5
- package/dist/{fields → forms/fields}/SelectField/MultiSelectField.d.ts +13 -6
- package/dist/forms/fields/SelectField/MultiSelectInput.d.ts +3 -0
- package/dist/{fields → forms/fields}/SelectField/SelectField.d.ts +14 -7
- package/dist/forms/fields/SelectField/SelectInput.d.ts +3 -0
- package/dist/forms/fields/SelectField/index.d.ts +4 -0
- package/dist/forms/fields/StringOrTextFields/StringField/StringField.d.ts +26 -0
- package/dist/forms/fields/StringOrTextFields/StringField/StringInput.d.ts +3 -0
- package/dist/forms/fields/StringOrTextFields/StringField/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/StringOrTextFields/StringOrTextField.d.ts +13 -8
- package/dist/forms/fields/StringOrTextFields/TextField/TextField.d.ts +22 -0
- package/dist/forms/fields/StringOrTextFields/TextField/TextInput.d.ts +3 -0
- package/dist/forms/fields/StringOrTextFields/TextField/index.d.ts +2 -0
- package/dist/forms/fields/StringOrTextFields/index.d.ts +2 -0
- package/dist/{fields → forms/fields}/UploadField/UploadField.d.ts +24 -9
- package/dist/forms/fields/UploadField/UploadInput.d.ts +3 -0
- package/dist/forms/fields/UploadField/index.d.ts +2 -0
- package/dist/forms/fields/constants.d.ts +106 -0
- package/dist/forms/fields/hooks.d.ts +6 -0
- package/dist/forms/fields/index.d.ts +12 -0
- package/dist/{fields → forms/fields}/typings.d.ts +9 -6
- package/dist/{fields → forms/fields}/utils.d.ts +7 -3
- package/dist/forms/index.d.ts +5 -0
- package/dist/{renderer → forms/renderer}/FormRenderer/FormRenderer.d.ts +4 -3
- package/dist/{renderer → forms/renderer}/PatchForm/Field.d.ts +5 -3
- package/dist/{renderer → forms/renderer}/PatchForm/Provider.d.ts +8 -4
- package/dist/forms/renderer/PatchForm/index.d.ts +2 -0
- package/dist/forms/renderer/index.d.ts +2 -0
- package/dist/forms/typings.d.ts +105 -0
- package/dist/forms/utils.d.ts +7 -0
- package/dist/forms.js +4450 -2478
- package/dist/forms.umd.cjs +44 -2777
- package/dist/index.d.ts +11 -3
- package/eslint.config.js +56 -0
- package/package.json +96 -94
- package/src/ColorPicker/ColorPicker.tsx +47 -0
- package/src/ColorPicker/index.ts +1 -0
- package/src/FileBadge/FileBadge.tsx +27 -0
- package/src/FileBadge/index.ts +1 -0
- package/src/FileCard/FileCard.stories.tsx +69 -0
- package/src/FileCard/FileCard.tsx +53 -0
- package/src/FileCard/index.ts +1 -0
- package/src/FileIcon/FileIcon.tsx +31 -0
- package/src/FileIcon/index.ts +1 -0
- package/src/FileViewer/FileViewerProvider.stories.tsx +50 -0
- package/src/FileViewer/FileViewerProvider.tsx +72 -0
- package/src/FileViewer/context.ts +11 -0
- package/src/FileViewer/index.ts +3 -0
- package/src/FileViewer/typings.ts +5 -0
- package/src/ImageCard/ImageCard.stories.tsx +94 -0
- package/src/ImageCard/ImageCard.tsx +82 -0
- package/src/ImageCard/index.ts +1 -0
- package/src/ImageMarkup/ImageMarkup.stories.tsx +65 -0
- package/src/ImageMarkup/ImageMarkup.tsx +268 -0
- package/src/ImageMarkup/index.ts +1 -0
- package/src/ImageViewer/ImageViewer.stories.tsx +57 -0
- package/src/ImageViewer/ImageViewer.tsx +124 -0
- package/src/ImageViewer/constants.ts +1 -0
- package/src/ImageViewer/index.ts +2 -0
- package/src/PDFViewer/PDFViewer.stories.tsx +55 -0
- package/src/PDFViewer/PDFViewer.tsx +170 -0
- package/src/PDFViewer/constants.ts +1 -0
- package/src/PDFViewer/index.ts +2 -0
- package/src/SpreadsheetViewer/SpreadsheetViewer.stories.tsx +55 -0
- package/src/SpreadsheetViewer/SpreadsheetViewer.tsx +162 -0
- package/src/SpreadsheetViewer/constants.ts +8 -0
- package/src/SpreadsheetViewer/index.ts +2 -0
- package/src/forms/builder/DropDispatch.ts +84 -0
- package/src/forms/builder/FieldActions.tsx +155 -0
- package/src/forms/builder/FieldBuilder.tsx +386 -0
- package/src/forms/builder/FieldSectionWithActions.tsx +260 -0
- package/src/forms/builder/FieldWithActions.tsx +129 -0
- package/src/forms/builder/FieldsEditor.tsx +180 -0
- package/src/forms/builder/FormBuilder.stories.tsx +105 -0
- package/src/forms/builder/FormBuilder.tsx +237 -0
- package/src/forms/builder/constants.ts +18 -0
- package/src/forms/builder/hooks.tsx +24 -0
- package/src/forms/builder/index.ts +2 -0
- package/src/forms/builder/typings.ts +18 -0
- package/src/forms/builder/utils.ts +229 -0
- package/src/forms/constants.ts +9 -0
- package/src/forms/constantsJsx.tsx +67 -0
- package/src/forms/fields/BaseField/BaseField.ts +152 -0
- package/src/forms/fields/BaseField/hooks.tsx +60 -0
- package/src/forms/fields/BaseField/index.ts +4 -0
- package/src/forms/fields/BaseField/layouts.tsx +100 -0
- package/src/forms/fields/BaseField/typings.ts +9 -0
- package/src/forms/fields/BooleanField/BooleanField.tsx +48 -0
- package/src/forms/fields/BooleanField/BooleanInput.tsx +54 -0
- package/src/forms/fields/BooleanField/index.ts +2 -0
- package/src/forms/fields/CustomField/CustomField.tsx +45 -0
- package/src/forms/fields/CustomField/FieldInputClonerField/FieldInputCloner.tsx +25 -0
- package/src/forms/fields/CustomField/FieldInputClonerField/FieldInputClonerField.tsx +26 -0
- package/src/forms/fields/CustomField/FieldInputClonerField/index.ts +3 -0
- package/src/forms/fields/CustomField/FieldInputClonerField/typings.ts +8 -0
- package/src/forms/fields/CustomField/index.ts +1 -0
- package/src/forms/fields/DateField/DateField.tsx +42 -0
- package/src/forms/fields/DateField/DateInput.tsx +39 -0
- package/src/forms/fields/DateField/index.ts +2 -0
- package/src/forms/fields/FieldSection/FieldSection.tsx +173 -0
- package/src/forms/fields/FieldSection/FieldSectionLayout.tsx +56 -0
- package/src/forms/fields/FieldSection/index.ts +1 -0
- package/src/forms/fields/MultiStringField/MultiStringField.tsx +90 -0
- package/src/forms/fields/MultiStringField/MultiStringInput.tsx +207 -0
- package/src/forms/fields/MultiStringField/index.ts +2 -0
- package/src/forms/fields/NumberField/NumberField.tsx +173 -0
- package/src/forms/fields/NumberField/NumberInput.tsx +44 -0
- package/src/forms/fields/NumberField/index.ts +2 -0
- package/src/forms/fields/QrField/QrField.tsx +38 -0
- package/src/forms/fields/QrField/QrInput.module.sass +5 -0
- package/src/forms/fields/QrField/QrInput.tsx +144 -0
- package/src/forms/fields/QrField/index.ts +2 -0
- package/src/forms/fields/SelectField/BaseSelectField.ts +73 -0
- package/src/forms/fields/SelectField/MultiSelectField.tsx +53 -0
- package/src/forms/fields/SelectField/MultiSelectInput.tsx +80 -0
- package/src/forms/fields/SelectField/SelectField.tsx +49 -0
- package/src/forms/fields/SelectField/SelectInput.tsx +69 -0
- package/src/forms/fields/SelectField/index.ts +4 -0
- package/src/forms/fields/StringOrTextFields/StringField/StringField.tsx +61 -0
- package/src/forms/fields/StringOrTextFields/StringField/StringInput.tsx +41 -0
- package/src/forms/fields/StringOrTextFields/StringField/index.ts +2 -0
- package/src/forms/fields/StringOrTextFields/StringOrTextField.ts +143 -0
- package/src/forms/fields/StringOrTextFields/TextField/TextField.tsx +52 -0
- package/src/forms/fields/StringOrTextFields/TextField/TextInput.tsx +42 -0
- package/src/forms/fields/StringOrTextFields/TextField/index.ts +2 -0
- package/src/forms/fields/StringOrTextFields/index.ts +2 -0
- package/src/forms/fields/UploadField/UploadField.tsx +156 -0
- package/src/forms/fields/UploadField/UploadInput.tsx +220 -0
- package/src/forms/fields/UploadField/index.ts +2 -0
- package/src/forms/fields/UploadField/utils.ts +17 -0
- package/src/forms/fields/constants.ts +43 -0
- package/src/forms/fields/hooks.tsx +26 -0
- package/src/forms/fields/index.ts +12 -0
- package/src/forms/fields/typings.ts +45 -0
- package/src/forms/fields/utils.ts +125 -0
- package/src/forms/index.ts +5 -0
- package/src/forms/renderer/FormRenderer/FormRenderer.stories.tsx +142 -0
- package/src/forms/renderer/FormRenderer/FormRenderer.tsx +135 -0
- package/src/forms/renderer/PatchForm/Field.tsx +41 -0
- package/src/forms/renderer/PatchForm/PatchForm.stories.tsx +91 -0
- package/src/forms/renderer/PatchForm/Provider.tsx +119 -0
- package/src/forms/renderer/PatchForm/index.ts +2 -0
- package/src/forms/renderer/index.ts +2 -0
- package/src/forms/typings.ts +162 -0
- package/src/forms/utils.ts +69 -0
- package/src/index.ts +11 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.ts +8 -0
- package/tsconfig.json +26 -0
- package/vite.config.ts +23 -0
- package/README.md +0 -12
- package/dist/builder/FieldActions.d.ts +0 -12
- package/dist/builder/FieldBuilder.d.ts +0 -24
- package/dist/builder/FieldSectionWithActions.d.ts +0 -10
- package/dist/builder/FieldWithActions.d.ts +0 -11
- package/dist/builder/FieldsEditor.d.ts +0 -2
- package/dist/builder/FormBuilder.d.ts +0 -15
- package/dist/builder/constants.d.ts +0 -1
- package/dist/builder/index.d.ts +0 -2
- package/dist/builder/utils.d.ts +0 -13
- package/dist/fields/BaseField/hooks.d.ts +0 -374
- package/dist/fields/BaseField/index.d.ts +0 -4
- package/dist/fields/BooleanField/BooleanInput.d.ts +0 -4
- package/dist/fields/BooleanField/index.d.ts +0 -2
- package/dist/fields/CustomField/FieldInputClonerField/index.d.ts +0 -3
- package/dist/fields/CustomField/FieldInputClonerField/typings.d.ts +0 -5
- package/dist/fields/CustomField/index.d.ts +0 -1
- package/dist/fields/DateField/DateField.d.ts +0 -16
- package/dist/fields/DateField/DateInput.d.ts +0 -4
- package/dist/fields/DateField/index.d.ts +0 -2
- package/dist/fields/FieldSection/FieldSectionLayout.d.ts +0 -7
- package/dist/fields/FieldSection/index.d.ts +0 -1
- package/dist/fields/MultiStringField/MultiStringField.d.ts +0 -30
- package/dist/fields/MultiStringField/MultiStringInput.d.ts +0 -8
- package/dist/fields/MultiStringField/index.d.ts +0 -2
- package/dist/fields/NumberField/NumberInput.d.ts +0 -4
- package/dist/fields/NumberField/index.d.ts +0 -2
- package/dist/fields/SelectField/MultiSelectInput.d.ts +0 -4
- package/dist/fields/SelectField/SelectInput.d.ts +0 -4
- package/dist/fields/SelectField/index.d.ts +0 -4
- package/dist/fields/StringOrTextFields/StringField/StringField.d.ts +0 -19
- package/dist/fields/StringOrTextFields/StringField/StringInput.d.ts +0 -4
- package/dist/fields/StringOrTextFields/StringField/index.d.ts +0 -2
- package/dist/fields/StringOrTextFields/TextField/TextField.d.ts +0 -16
- package/dist/fields/StringOrTextFields/TextField/TextInput.d.ts +0 -4
- package/dist/fields/StringOrTextFields/TextField/index.d.ts +0 -2
- package/dist/fields/StringOrTextFields/index.d.ts +0 -2
- package/dist/fields/UploadField/UploadInput.d.ts +0 -4
- package/dist/fields/UploadField/index.d.ts +0 -2
- package/dist/fields/constants.d.ts +0 -20
- package/dist/fields/hooks.d.ts +0 -6
- package/dist/fields/index.d.ts +0 -11
- package/dist/forms.js.map +0 -1
- package/dist/forms.umd.cjs.map +0 -1
- package/dist/renderer/FormBrowser/FormBrowser.d.ts +0 -11
- package/dist/renderer/FormSubmissionBrowser/FormSubmissionBrowser.d.ts +0 -28
- package/dist/renderer/FormSubmissionViewer/FormSubmissionViewer.d.ts +0 -17
- package/dist/renderer/PatchForm/index.d.ts +0 -2
- package/dist/renderer/index.d.ts +0 -5
- package/dist/style.css +0 -34
- package/dist/typings.d.ts +0 -17
- package/dist/utils.d.ts +0 -7
- /package/dist/{fields → forms/fields}/UploadField/utils.d.ts +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Button, Menu, RiIcon } from "@overmap-ai/blocks"
|
|
2
|
+
import { memo, useCallback } from "react"
|
|
3
|
+
|
|
4
|
+
import { SEVERITY_COLOR_MAPPING } from "../../constants"
|
|
5
|
+
import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from "../BaseField"
|
|
6
|
+
import { ComponentProps } from "../typings"
|
|
7
|
+
import { SelectField } from "./SelectField"
|
|
8
|
+
|
|
9
|
+
export const SelectInput = memo((props: ComponentProps<SelectField>) => {
|
|
10
|
+
const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props)
|
|
11
|
+
const { onChange, onBlur } = fieldProps
|
|
12
|
+
let [{ helpText, label }] = useFormikInput(props)
|
|
13
|
+
helpText = showInputOnly ? null : helpText
|
|
14
|
+
label = showInputOnly ? "" : label
|
|
15
|
+
|
|
16
|
+
const handleChange = useCallback(
|
|
17
|
+
(value: string | null) => {
|
|
18
|
+
onChange(value)
|
|
19
|
+
onBlur(value)
|
|
20
|
+
},
|
|
21
|
+
[onChange, onBlur],
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const color = severity ? SEVERITY_COLOR_MAPPING[severity] : undefined
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<InputWithLabelAndHelpText helpText={helpText} severity={severity}>
|
|
28
|
+
<InputWithLabel
|
|
29
|
+
size={size}
|
|
30
|
+
severity={severity}
|
|
31
|
+
inputId={inputId}
|
|
32
|
+
labelId={labelId}
|
|
33
|
+
label={label}
|
|
34
|
+
image={showInputOnly ? undefined : field.image}
|
|
35
|
+
>
|
|
36
|
+
<Menu.Root>
|
|
37
|
+
<Menu.ClickTrigger>
|
|
38
|
+
<Button
|
|
39
|
+
{...fieldProps}
|
|
40
|
+
className="!justify-between"
|
|
41
|
+
id={inputId}
|
|
42
|
+
name={fieldProps.name}
|
|
43
|
+
accentColor={color}
|
|
44
|
+
variant="soft"
|
|
45
|
+
{...rest}
|
|
46
|
+
>
|
|
47
|
+
{fieldProps.value ? fieldProps.value : field.placeholder}
|
|
48
|
+
<RiIcon icon="RiArrowDownSLine" />
|
|
49
|
+
</Button>
|
|
50
|
+
</Menu.ClickTrigger>
|
|
51
|
+
<Menu.Content>
|
|
52
|
+
<Menu.SelectGroup value={fieldProps.value} onValueChange={handleChange}>
|
|
53
|
+
{field.options.map((option) => (
|
|
54
|
+
<Menu.SelectItem key={option.value} value={option.value}>
|
|
55
|
+
<Menu.SelectedIndicator>
|
|
56
|
+
<RiIcon icon="RiCheckLine" />
|
|
57
|
+
</Menu.SelectedIndicator>
|
|
58
|
+
{option.label}
|
|
59
|
+
</Menu.SelectItem>
|
|
60
|
+
))}
|
|
61
|
+
</Menu.SelectGroup>
|
|
62
|
+
</Menu.Content>
|
|
63
|
+
</Menu.Root>
|
|
64
|
+
</InputWithLabel>
|
|
65
|
+
</InputWithLabelAndHelpText>
|
|
66
|
+
)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
SelectInput.displayName = "SelectInput"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ReactNode } from "react"
|
|
2
|
+
import { RiInputField } from "react-icons/ri"
|
|
3
|
+
|
|
4
|
+
import { SHORT_TEXT_FIELD_MAX_LENGTH } from "../../../constants"
|
|
5
|
+
import { ISerializedField, SerializedStringField, StringInputType } from "../../../typings"
|
|
6
|
+
import { emptyBaseField } from "../../BaseField"
|
|
7
|
+
import { GetInputProps } from "../../typings"
|
|
8
|
+
import { StringOrTextField, StringOrTextFieldOptions } from "../StringOrTextField"
|
|
9
|
+
import { StringInput } from "./StringInput"
|
|
10
|
+
|
|
11
|
+
export interface StringFieldOptions extends Omit<StringOrTextFieldOptions, "type"> {
|
|
12
|
+
inputType?: StringInputType
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const emptyStringField = {
|
|
16
|
+
...emptyBaseField,
|
|
17
|
+
type: "string",
|
|
18
|
+
maximum_length: SHORT_TEXT_FIELD_MAX_LENGTH,
|
|
19
|
+
input_type: "text",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class StringField extends StringOrTextField<"string"> {
|
|
23
|
+
static readonly fieldTypeName = "Short Text"
|
|
24
|
+
static readonly fieldTypeDescription = `Short text fields can hold up to ${SHORT_TEXT_FIELD_MAX_LENGTH} characters on a single line.`
|
|
25
|
+
public readonly inputType: StringInputType
|
|
26
|
+
|
|
27
|
+
static Icon: typeof RiInputField = RiInputField
|
|
28
|
+
|
|
29
|
+
constructor(options: StringFieldOptions) {
|
|
30
|
+
const { inputType = "text", ...rest } = options
|
|
31
|
+
// the field supports a max length no larger than 500
|
|
32
|
+
const maxLength = options.maxLength
|
|
33
|
+
? Math.min(SHORT_TEXT_FIELD_MAX_LENGTH, options.maxLength)
|
|
34
|
+
: SHORT_TEXT_FIELD_MAX_LENGTH
|
|
35
|
+
// the field supports a min length no larger than the max length
|
|
36
|
+
const minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined
|
|
37
|
+
super({ ...rest, maxLength, minLength, type: "string" })
|
|
38
|
+
|
|
39
|
+
this.inputType = inputType
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
serialize(): SerializedStringField {
|
|
43
|
+
return { ...super._serialize(), input_type: this.inputType }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static deserialize(data: ISerializedField): StringField {
|
|
47
|
+
if (data.type !== "string") throw new Error("Type mismatch.")
|
|
48
|
+
const { maximum_length, minimum_length, input_type, ...rest } = data
|
|
49
|
+
return new StringField({
|
|
50
|
+
...rest,
|
|
51
|
+
maxLength: maximum_length,
|
|
52
|
+
minLength: minimum_length,
|
|
53
|
+
inputType: input_type,
|
|
54
|
+
placeholder: "Enter a short description",
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getInput(props: GetInputProps<this>): ReactNode {
|
|
59
|
+
return <StringInput field={this} {...props} />
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Input } from "@overmap-ai/blocks"
|
|
2
|
+
import { memo } from "react"
|
|
3
|
+
|
|
4
|
+
import { SEVERITY_COLOR_MAPPING } from "../../../constants"
|
|
5
|
+
import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from "../../BaseField"
|
|
6
|
+
import { ComponentProps } from "../../typings"
|
|
7
|
+
import { StringField } from "./StringField"
|
|
8
|
+
|
|
9
|
+
export const StringInput = memo((props: ComponentProps<StringField>) => {
|
|
10
|
+
const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props)
|
|
11
|
+
let [{ helpText, label }] = useFormikInput(props)
|
|
12
|
+
helpText = showInputOnly ? null : helpText
|
|
13
|
+
label = showInputOnly ? "" : label
|
|
14
|
+
|
|
15
|
+
const color = severity ? SEVERITY_COLOR_MAPPING[severity] : undefined
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<InputWithLabelAndHelpText helpText={helpText} severity={severity}>
|
|
19
|
+
<InputWithLabel
|
|
20
|
+
size={size}
|
|
21
|
+
severity={severity}
|
|
22
|
+
inputId={inputId}
|
|
23
|
+
labelId={labelId}
|
|
24
|
+
label={label}
|
|
25
|
+
image={showInputOnly ? undefined : field.image}
|
|
26
|
+
>
|
|
27
|
+
<Input.Root accentColor={color} variant="soft">
|
|
28
|
+
<Input.Field
|
|
29
|
+
{...rest}
|
|
30
|
+
{...fieldProps}
|
|
31
|
+
type={field.inputType}
|
|
32
|
+
id={inputId}
|
|
33
|
+
placeholder={field.placeholder}
|
|
34
|
+
/>
|
|
35
|
+
</Input.Root>
|
|
36
|
+
</InputWithLabel>
|
|
37
|
+
</InputWithLabelAndHelpText>
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
StringInput.displayName = "StringInput"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import get from "lodash.get"
|
|
2
|
+
|
|
3
|
+
import { FormikUserFormRevision } from "../../builder"
|
|
4
|
+
import { LONG_TEXT_FIELD_MAX_LENGTH } from "../../constants"
|
|
5
|
+
import { Form, SerializedStringField } from "../../typings"
|
|
6
|
+
import { BaseField, FieldOptions } from "../BaseField"
|
|
7
|
+
import { NumberField, NumberFieldValue } from "../NumberField"
|
|
8
|
+
import { InputFieldLevelValidator, InputValidator } from "../typings"
|
|
9
|
+
|
|
10
|
+
export interface StringOrTextFieldOptions extends FieldOptions<string> {
|
|
11
|
+
minLength?: NumberFieldValue
|
|
12
|
+
maxLength?: NumberFieldValue
|
|
13
|
+
placeholder?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// NOTE: If changing, also change it in NumberField.ts (avoid circular imports)
|
|
17
|
+
const valueIsFormikUserFormRevision = (form: FormikUserFormRevision | Form): form is FormikUserFormRevision => {
|
|
18
|
+
return "fields" in form
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type SerializedStringOrTextField<TIdentifier extends "string" | "text"> = Omit<SerializedStringField, "type"> & {
|
|
22
|
+
type: TIdentifier
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export abstract class StringOrTextField<TIdentifier extends "string" | "text"> extends BaseField<string, TIdentifier> {
|
|
26
|
+
public readonly minLength?: number
|
|
27
|
+
public readonly maxLength: number
|
|
28
|
+
public readonly placeholder: string
|
|
29
|
+
|
|
30
|
+
protected constructor(options: StringOrTextFieldOptions) {
|
|
31
|
+
const { minLength, maxLength, placeholder = "", ...base } = options
|
|
32
|
+
super(base)
|
|
33
|
+
// lengths must be greater than or equal to 0
|
|
34
|
+
this.minLength = minLength ? Math.max(minLength, 0) : undefined
|
|
35
|
+
this.maxLength = maxLength ? Math.max(maxLength, 0) : LONG_TEXT_FIELD_MAX_LENGTH
|
|
36
|
+
this.placeholder = placeholder
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* This function returns a function that validates that the value given for "minimum length" (when creating a new field) is less than or
|
|
41
|
+
* equal to the value given for "maximum length".
|
|
42
|
+
*/
|
|
43
|
+
static _validateMin: (path: string) => InputValidator<NumberFieldValue> = (path: string) => (value, allValues) => {
|
|
44
|
+
const field = valueIsFormikUserFormRevision(allValues)
|
|
45
|
+
? (get(allValues, path) as SerializedStringField)
|
|
46
|
+
: allValues
|
|
47
|
+
if (typeof field.maximum_length === "number" && typeof value === "number" && field.maximum_length < value) {
|
|
48
|
+
return "Minimum cannot be greater than maximum."
|
|
49
|
+
}
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* This function returns a function that validates that the value given for "maximum length" (when creating a new field) is greater than or
|
|
55
|
+
* equal to the value given for "minimum length".
|
|
56
|
+
*/
|
|
57
|
+
static _validateMax: (path: string) => InputValidator<NumberFieldValue> = (path: string) => (value, allValues) => {
|
|
58
|
+
if (typeof value !== "number") return null
|
|
59
|
+
|
|
60
|
+
const { minimum_length: minimumLength } = valueIsFormikUserFormRevision(allValues)
|
|
61
|
+
? (get(allValues, path) as SerializedStringField)
|
|
62
|
+
: allValues
|
|
63
|
+
|
|
64
|
+
if (typeof minimumLength !== "number") {
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (minimumLength > value) {
|
|
69
|
+
return "Maximum cannot be less than minimum."
|
|
70
|
+
}
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static getFieldCreationSchema(parentPath = "") {
|
|
75
|
+
const path = parentPath && `${parentPath}.`
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
field:
|
|
79
|
+
// min, max
|
|
80
|
+
new NumberField({
|
|
81
|
+
label: "Minimum length",
|
|
82
|
+
description: "Minimum number of characters",
|
|
83
|
+
required: false,
|
|
84
|
+
identifier: `${path}minimum_length`,
|
|
85
|
+
minimum: 0,
|
|
86
|
+
maximum: 100,
|
|
87
|
+
formValidators: [this._validateMin(parentPath)],
|
|
88
|
+
integers: true,
|
|
89
|
+
}),
|
|
90
|
+
showDirectly: false,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
field: new NumberField({
|
|
94
|
+
label: "Maximum length",
|
|
95
|
+
description: "Maximum number of characters",
|
|
96
|
+
required: false,
|
|
97
|
+
identifier: `${path}maximum_length`,
|
|
98
|
+
minimum: 1,
|
|
99
|
+
maximum: LONG_TEXT_FIELD_MAX_LENGTH, // TODO: depends on short vs long text
|
|
100
|
+
formValidators: [this._validateMax(parentPath)],
|
|
101
|
+
// TODO: default: 500 (see: "Short text fields can hold up to 500 characters on a single line.")
|
|
102
|
+
integers: true,
|
|
103
|
+
}),
|
|
104
|
+
showDirectly: false,
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getFieldValidators(): InputFieldLevelValidator<string>[] {
|
|
110
|
+
const validators = super.getFieldValidators()
|
|
111
|
+
|
|
112
|
+
if (this.minLength) {
|
|
113
|
+
validators.push((value) => {
|
|
114
|
+
if (this.minLength && (!value || value.length < this.minLength)) {
|
|
115
|
+
// One exception to this rule:
|
|
116
|
+
if (!this.required && !value) return null
|
|
117
|
+
return `Minimum ${this.minLength} character(s).`
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
if (this.maxLength) {
|
|
122
|
+
validators.push((value) => {
|
|
123
|
+
if (typeof value === "string" && this.maxLength && value.length > this.maxLength) {
|
|
124
|
+
return `Maximum ${this.maxLength} character(s).`
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return validators
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
protected _serialize(): SerializedStringOrTextField<TIdentifier> {
|
|
133
|
+
if (!this.identifier) {
|
|
134
|
+
throw new Error("Field identifier must be set before serializing.")
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
...super._serialize(),
|
|
138
|
+
minimum_length: this.minLength,
|
|
139
|
+
maximum_length: this.maxLength,
|
|
140
|
+
placeholder: this.placeholder,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ReactNode } from "react"
|
|
2
|
+
import { RiAlignJustify } from "react-icons/ri"
|
|
3
|
+
|
|
4
|
+
import { LONG_TEXT_FIELD_MAX_LENGTH } from "../../../constants"
|
|
5
|
+
import { ISerializedField, SerializedTextField } from "../../../typings"
|
|
6
|
+
import { emptyBaseField } from "../../BaseField"
|
|
7
|
+
import { GetInputProps } from "../../typings"
|
|
8
|
+
import { StringOrTextField, StringOrTextFieldOptions } from "../StringOrTextField"
|
|
9
|
+
import { TextInput } from "./TextInput"
|
|
10
|
+
|
|
11
|
+
export type TextFieldOptions = Omit<StringOrTextFieldOptions, "type">
|
|
12
|
+
|
|
13
|
+
export const emptyTextField = {
|
|
14
|
+
...emptyBaseField,
|
|
15
|
+
type: "text",
|
|
16
|
+
maximum_length: LONG_TEXT_FIELD_MAX_LENGTH,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class TextField extends StringOrTextField<"text"> {
|
|
20
|
+
static readonly fieldTypeName = "Paragraph"
|
|
21
|
+
static readonly fieldTypeDescription = `Paragraph fields can hold up to ${LONG_TEXT_FIELD_MAX_LENGTH} characters and can have multiple lines.`
|
|
22
|
+
|
|
23
|
+
static Icon: typeof RiAlignJustify = RiAlignJustify
|
|
24
|
+
|
|
25
|
+
constructor(options: TextFieldOptions) {
|
|
26
|
+
const maxLength = options.maxLength
|
|
27
|
+
? Math.min(LONG_TEXT_FIELD_MAX_LENGTH, options.maxLength)
|
|
28
|
+
: LONG_TEXT_FIELD_MAX_LENGTH
|
|
29
|
+
// the field supports a min length no larger than the max length
|
|
30
|
+
const minLength = options.minLength ? Math.min(options.minLength, maxLength) : undefined
|
|
31
|
+
super({ ...options, maxLength, minLength, type: "text" })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
serialize(): SerializedTextField {
|
|
35
|
+
return super._serialize()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static deserialize(data: ISerializedField) {
|
|
39
|
+
if (data.type !== "text") throw new Error("Type mismatch.")
|
|
40
|
+
const { maximum_length, minimum_length, ...rest } = data
|
|
41
|
+
return new TextField({
|
|
42
|
+
...rest,
|
|
43
|
+
maxLength: maximum_length,
|
|
44
|
+
minLength: minimum_length,
|
|
45
|
+
placeholder: "Enter a description",
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getInput(props: GetInputProps<this>): ReactNode {
|
|
50
|
+
return <TextInput field={this} {...props} />
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { TextArea } from "@overmap-ai/blocks"
|
|
2
|
+
import { memo } from "react"
|
|
3
|
+
|
|
4
|
+
import { SEVERITY_COLOR_MAPPING } from "../../../constants"
|
|
5
|
+
import { InputWithLabel, InputWithLabelAndHelpText, useFormikInput } from "../../BaseField"
|
|
6
|
+
import { ComponentProps } from "../../typings"
|
|
7
|
+
import { TextField } from "./TextField"
|
|
8
|
+
|
|
9
|
+
export const TextInput = memo((props: ComponentProps<TextField>) => {
|
|
10
|
+
const [{ inputId, labelId, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props)
|
|
11
|
+
let [{ helpText, label }] = useFormikInput(props)
|
|
12
|
+
helpText = showInputOnly ? null : helpText
|
|
13
|
+
label = showInputOnly ? "" : label
|
|
14
|
+
|
|
15
|
+
const color = severity ? SEVERITY_COLOR_MAPPING[severity] : undefined
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<InputWithLabelAndHelpText helpText={helpText} severity={severity}>
|
|
19
|
+
<InputWithLabel
|
|
20
|
+
size={size}
|
|
21
|
+
severity={severity}
|
|
22
|
+
inputId={inputId}
|
|
23
|
+
labelId={labelId}
|
|
24
|
+
label={label}
|
|
25
|
+
image={showInputOnly ? undefined : field.image}
|
|
26
|
+
>
|
|
27
|
+
<TextArea
|
|
28
|
+
{...rest}
|
|
29
|
+
{...fieldProps}
|
|
30
|
+
className="field-sizing-content"
|
|
31
|
+
resize="vertical"
|
|
32
|
+
id={inputId}
|
|
33
|
+
placeholder={field.placeholder}
|
|
34
|
+
accentColor={color}
|
|
35
|
+
variant="soft"
|
|
36
|
+
/>
|
|
37
|
+
</InputWithLabel>
|
|
38
|
+
</InputWithLabelAndHelpText>
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
TextInput.displayName = "TextInput"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { ChangeEvent, ReactNode } from "react"
|
|
2
|
+
import { RiUpload2Line } from "react-icons/ri"
|
|
3
|
+
|
|
4
|
+
import { ISerializedField, SerializedUploadField } from "../../typings"
|
|
5
|
+
import { BaseField, ChildFieldOptions, emptyBaseField } from "../BaseField"
|
|
6
|
+
import { maxFileSizeMB } from "../constants"
|
|
7
|
+
import { NumberField } from "../NumberField"
|
|
8
|
+
import { MultiSelectField } from "../SelectField"
|
|
9
|
+
import { GetInputProps, InputFieldLevelValidator } from "../typings"
|
|
10
|
+
import { UploadInput } from "./UploadInput"
|
|
11
|
+
|
|
12
|
+
export interface UploadFieldOptions extends ChildFieldOptions<File[]> {
|
|
13
|
+
extensions?: string[]
|
|
14
|
+
maximum_size?: number | string
|
|
15
|
+
maximum_files?: number | string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const emptyUploadField = {
|
|
19
|
+
...emptyBaseField,
|
|
20
|
+
type: "upload",
|
|
21
|
+
extensions: [],
|
|
22
|
+
maximum_size: undefined,
|
|
23
|
+
maximum_files: 1,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class UploadField extends BaseField<File[], "upload"> {
|
|
27
|
+
static readonly fieldTypeName = "Upload"
|
|
28
|
+
static readonly fieldTypeDescription = "Allows a file to be uploaded."
|
|
29
|
+
|
|
30
|
+
public readonly extensions?: string[]
|
|
31
|
+
public readonly maxFileSize: number | undefined
|
|
32
|
+
public readonly maxFiles: number
|
|
33
|
+
public readonly onlyValidateAfterTouched = false
|
|
34
|
+
|
|
35
|
+
static Icon: typeof RiUpload2Line = RiUpload2Line
|
|
36
|
+
|
|
37
|
+
constructor(options: UploadFieldOptions) {
|
|
38
|
+
const { extensions, maximum_files, maximum_size, ...base } = options
|
|
39
|
+
super({ ...base, type: "upload" })
|
|
40
|
+
|
|
41
|
+
this.maxFileSize = typeof maximum_size === "number" ? maximum_size : undefined
|
|
42
|
+
// if maximum_files is not a number or less than 1, default and clamp to 1
|
|
43
|
+
this.maxFiles = Math.max(typeof maximum_files === "number" ? maximum_files : 1, 1)
|
|
44
|
+
|
|
45
|
+
this.extensions = extensions
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public getValueFromChangeEvent(event: ChangeEvent<HTMLInputElement>): File[] {
|
|
49
|
+
return Array.from(event.target.files || [])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
protected isBlank(value: File[]): boolean {
|
|
53
|
+
return super.isBlank(value) || value.length === 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static getFieldCreationSchema(parentPath = "") {
|
|
57
|
+
const path = parentPath && `${parentPath}.`
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
field: new NumberField({
|
|
61
|
+
label: "How many files can be uploaded?",
|
|
62
|
+
description: "By default, only one file can be uploaded.",
|
|
63
|
+
required: false,
|
|
64
|
+
minimum: 1,
|
|
65
|
+
maximum: 10,
|
|
66
|
+
identifier: `${path}maximum_files`,
|
|
67
|
+
integers: true,
|
|
68
|
+
}),
|
|
69
|
+
showDirectly: false,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
field: new NumberField({
|
|
73
|
+
// TODO: Default value
|
|
74
|
+
label: "What is the maximum size of each file?",
|
|
75
|
+
description: `Maximum file size in megabytes (between 1MB–${maxFileSizeMB}MB).`,
|
|
76
|
+
required: false,
|
|
77
|
+
identifier: `${path}maximum_size`,
|
|
78
|
+
minimum: 1,
|
|
79
|
+
maximum: maxFileSizeMB,
|
|
80
|
+
integers: true,
|
|
81
|
+
}),
|
|
82
|
+
showDirectly: false,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
field: new MultiSelectField({
|
|
86
|
+
label: "Accepted file types",
|
|
87
|
+
description: "Types of allowed files to upload. If left blank, all files will be accepted.",
|
|
88
|
+
required: false,
|
|
89
|
+
identifier: `${path}extensions`,
|
|
90
|
+
options: [
|
|
91
|
+
{
|
|
92
|
+
value: "image/*",
|
|
93
|
+
label: "Images",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
value: "audio/*",
|
|
97
|
+
label: "Audio files",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
value: "video/*",
|
|
101
|
+
label: "Videos",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
value: "text/*",
|
|
105
|
+
label: "Text files",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
value: "application/*",
|
|
109
|
+
label: "Application files (includes PDFs and Word documents)",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
}),
|
|
113
|
+
showDirectly: false,
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getFieldValidators(): InputFieldLevelValidator<File[]>[] {
|
|
119
|
+
const validators = super.getFieldValidators()
|
|
120
|
+
const maxFileSizeInMB = this.maxFileSize ?? maxFileSizeMB
|
|
121
|
+
const maxFileSizeInB = maxFileSizeInMB * 1000 * 1000
|
|
122
|
+
const maxFiles = this.maxFiles || 1
|
|
123
|
+
|
|
124
|
+
validators.push((value) => {
|
|
125
|
+
if (value && value.some((file) => file.size > maxFileSizeInB)) {
|
|
126
|
+
return `Files must be at most ${maxFileSizeInMB}MB.`
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
validators.push((value) => {
|
|
131
|
+
if (value && value.length > maxFiles) {
|
|
132
|
+
return `You can only upload ${maxFiles} files.`
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
return validators
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
serialize(): SerializedUploadField {
|
|
140
|
+
return {
|
|
141
|
+
...super._serialize(),
|
|
142
|
+
extensions: this.extensions,
|
|
143
|
+
maximum_size: this.maxFileSize,
|
|
144
|
+
maximum_files: this.maxFiles,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static deserialize(data: ISerializedField): UploadField {
|
|
149
|
+
if (data.type !== "upload") throw new Error("Type mismatch.")
|
|
150
|
+
return new UploadField(data)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getInput(props: GetInputProps<this>): ReactNode {
|
|
154
|
+
return <UploadInput field={this} {...props} />
|
|
155
|
+
}
|
|
156
|
+
}
|