@dxos/react-ui-form 0.9.0 → 0.9.1-staging.ee54ba693a
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/dist/lib/browser/index.mjs +2337 -1919
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +2337 -1919
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/annotations.d.ts +47 -0
- package/dist/types/src/annotations.d.ts.map +1 -0
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +3 -3
- package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +23 -110
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +48 -101
- package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.theme.d.ts +252 -0
- package/dist/types/src/components/Form/Form.theme.d.ts.map +1 -0
- package/dist/types/src/components/Form/Form.theme.test.d.ts +2 -0
- package/dist/types/src/components/Form/Form.theme.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormControls.d.ts +75 -0
- package/dist/types/src/components/Form/FormControls.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/FormField.d.ts +44 -0
- package/dist/types/src/components/Form/FormField/FormField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/FormFieldHeader.d.ts +27 -0
- package/dist/types/src/components/Form/FormField/FormFieldHeader.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/FormRow.d.ts +85 -0
- package/dist/types/src/components/Form/FormField/FormRow.d.ts.map +1 -0
- package/dist/types/src/components/Form/{FormFieldComponent.stories.d.ts → FormField/FormRow.stories.d.ts} +6 -3
- package/dist/types/src/components/Form/FormField/FormRow.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/{fields → FormField/fields/ArrayField}/ArrayField.d.ts +2 -2
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.d.ts +12 -0
- package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/AutofillField/AutofillField.d.ts +12 -0
- package/dist/types/src/components/Form/FormField/fields/AutofillField/AutofillField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/AutofillField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/AutofillField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts.map +1 -0
- package/dist/types/src/components/{Settings/Settings.stories.d.ts → Form/FormField/fields/BooleanField/BooleanField.stories.d.ts} +1 -2
- package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/ComboboxField/ComboboxField.d.ts +12 -0
- package/dist/types/src/components/Form/FormField/fields/ComboboxField/ComboboxField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/ComboboxField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/ComboboxField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts +5 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.d.ts +2 -2
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts +15 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.test.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/PasswordField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/InlineRefField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts +16 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts +92 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts +3 -0
- package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts +29 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts +5 -0
- package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.d.ts +2 -2
- package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts +88 -0
- package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts +2 -0
- package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/{fields → FormField/fields}/index.d.ts +4 -1
- package/dist/types/src/components/Form/FormField/fields/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/index.d.ts +6 -0
- package/dist/types/src/components/Form/FormField/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/presentation.d.ts +22 -0
- package/dist/types/src/components/Form/FormField/presentation.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts +30 -0
- package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldSet/FormFieldSetContainer.d.ts +22 -0
- package/dist/types/src/components/Form/FormFieldSet/FormFieldSetContainer.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormFieldSet/index.d.ts +3 -0
- package/dist/types/src/components/Form/FormFieldSet/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.d.ts +2 -0
- package/dist/types/src/components/Form/FormLayout/FormLayout.d.ts.map +1 -0
- package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.d.ts +5 -5
- package/dist/types/src/components/Form/FormLayout/FormLayout.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormLayout/FormLayout.stories.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormLayout/FormLayout.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormLayout/index.d.ts +3 -0
- package/dist/types/src/components/Form/FormLayout/index.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormLayout/parser.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormLayout/parser.test.d.ts.map +1 -0
- package/dist/types/src/components/Form/index.d.ts +3 -5
- package/dist/types/src/components/Form/index.d.ts.map +1 -1
- package/dist/types/src/components/Form/meta-tags.d.ts +1 -12
- package/dist/types/src/components/Form/meta-tags.d.ts.map +1 -1
- package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -1
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +6 -23
- package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -1
- package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +2 -1
- package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -1
- package/dist/types/src/components/RefEditor/RefEditor.stories.d.ts +2 -2
- package/dist/types/src/components/RefEditor/RefEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +2 -2
- package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useAsyncFieldEffect.d.ts +24 -0
- package/dist/types/src/hooks/useAsyncFieldEffect.d.ts.map +1 -0
- package/dist/types/src/hooks/useFormContext.d.ts +42 -0
- package/dist/types/src/hooks/useFormContext.d.ts.map +1 -0
- package/dist/types/src/hooks/useFormHandler.d.ts +9 -6
- package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/{components/testing.d.ts → testing/TestLayout.d.ts} +2 -2
- package/dist/types/src/testing/TestLayout.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +3 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/schema.d.ts +40 -0
- package/dist/types/src/testing/schema.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +161 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +1 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/omit.d.ts +12 -0
- package/dist/types/src/util/omit.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -41
- package/src/annotations.ts +63 -0
- package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.test.tsx +1 -1
- package/src/components/FieldEditor/FieldEditor.tsx +10 -6
- package/src/components/Form/DESIGN.md +24 -0
- package/src/components/Form/Form.stories.tsx +260 -61
- package/src/components/Form/Form.theme.test.ts +33 -0
- package/src/components/Form/Form.theme.ts +86 -0
- package/src/components/Form/Form.tsx +30 -453
- package/src/components/Form/FormControls.tsx +377 -0
- package/src/components/Form/{FormField.tsx → FormField/FormField.tsx} +98 -71
- package/src/components/Form/FormField/FormFieldHeader.tsx +68 -0
- package/src/components/Form/FormField/FormRow.stories.tsx +97 -0
- package/src/components/Form/FormField/FormRow.tsx +298 -0
- package/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.tsx +119 -0
- package/src/components/Form/FormField/fields/ArrayField/ArrayField.tsx +328 -0
- package/src/components/Form/FormField/fields/ArrayField/index.ts +5 -0
- package/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.tsx +59 -0
- package/src/components/Form/FormField/fields/AsyncSelectField/index.ts +5 -0
- package/src/components/Form/FormField/fields/AutofillField/AutofillField.tsx +67 -0
- package/src/components/Form/FormField/fields/AutofillField/index.ts +5 -0
- package/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.tsx +52 -0
- package/src/components/Form/FormField/fields/BooleanField/BooleanField.tsx +28 -0
- package/src/components/Form/FormField/fields/BooleanField/index.ts +5 -0
- package/src/components/Form/FormField/fields/ComboboxField/ComboboxField.tsx +104 -0
- package/src/components/Form/FormField/fields/ComboboxField/index.ts +5 -0
- package/src/components/Form/FormField/fields/DateField/DateField.stories.tsx +60 -0
- package/src/components/Form/{fields → FormField/fields/DateField}/DateField.tsx +12 -10
- package/src/components/Form/FormField/fields/DateField/index.ts +5 -0
- package/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.tsx +53 -0
- package/src/components/Form/{fields → FormField/fields/GeoPointField}/GeoPointField.tsx +19 -21
- package/src/components/Form/FormField/fields/GeoPointField/index.ts +5 -0
- package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.tsx +8 -8
- package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.tsx +41 -41
- package/src/components/Form/FormField/fields/MarkdownField/index.ts +5 -0
- package/src/components/Form/FormField/fields/NumberField/NumberField.stories.tsx +52 -0
- package/src/components/Form/FormField/fields/NumberField/NumberField.test.ts +29 -0
- package/src/components/Form/FormField/fields/NumberField/NumberField.tsx +140 -0
- package/src/components/Form/FormField/fields/NumberField/index.ts +5 -0
- package/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.tsx +53 -0
- package/src/components/Form/FormField/fields/PasswordField/PasswordField.tsx +41 -0
- package/src/components/Form/FormField/fields/PasswordField/index.ts +5 -0
- package/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.tsx +21 -14
- package/src/components/Form/FormField/fields/RefField/RefField.stories.tsx +97 -0
- package/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.ts +10 -1
- package/src/components/Form/{fields → FormField/fields/RefField}/RefField.tsx +55 -47
- package/src/components/Form/FormField/fields/RefField/index.ts +6 -0
- package/src/components/Form/FormField/fields/SelectField/SelectField.stories.tsx +53 -0
- package/src/components/Form/FormField/fields/SelectField/SelectField.tsx +136 -0
- package/src/components/Form/FormField/fields/SelectField/index.ts +5 -0
- package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.tsx +5 -5
- package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.tsx +56 -54
- package/src/components/Form/FormField/fields/SelectOptionField/index.ts +5 -0
- package/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.tsx +53 -0
- package/src/components/Form/{fields → FormField/fields/TextAreaField}/TextAreaField.tsx +6 -4
- package/src/components/Form/FormField/fields/TextAreaField/index.ts +5 -0
- package/src/components/Form/FormField/fields/TextField/TextField.stories.tsx +52 -0
- package/src/components/Form/{fields → FormField/fields/TextField}/TextField.tsx +6 -4
- package/src/components/Form/FormField/fields/TextField/index.ts +5 -0
- package/src/components/Form/FormField/fields/TupleField/TupleField.stories.tsx +55 -0
- package/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.tsx +4 -2
- package/src/components/Form/FormField/fields/TupleField/index.ts +5 -0
- package/src/components/Form/{fields → FormField/fields}/index.ts +4 -1
- package/src/components/Form/FormField/index.ts +10 -0
- package/src/components/Form/FormField/presentation.tsx +32 -0
- package/src/components/Form/{FormFieldSet.tsx → FormFieldSet/FormFieldSet.tsx} +53 -90
- package/src/components/Form/FormFieldSet/FormFieldSetContainer.tsx +93 -0
- package/src/components/Form/FormFieldSet/index.ts +6 -0
- package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.tsx +11 -9
- package/src/components/Form/{Layout → FormLayout}/FormLayout.tsx +29 -18
- package/src/components/Form/FormLayout/index.ts +6 -0
- package/src/components/Form/index.ts +3 -5
- package/src/components/Form/meta-tags.test.ts +1 -1
- package/src/components/Form/meta-tags.ts +1 -1
- package/src/components/ObjectForm/ObjectForm.tsx +15 -14
- package/src/components/ObjectPicker/ObjectPicker.tsx +20 -27
- package/src/components/ObjectProperties/ObjectProperties.stories.tsx +2 -2
- package/src/components/ObjectProperties/ObjectProperties.test.tsx +1 -1
- package/src/components/ObjectProperties/ObjectProperties.tsx +13 -8
- package/src/components/RefEditor/RefEditor.stories.tsx +2 -3
- package/src/components/RefEditor/RefEditor.tsx +1 -1
- package/src/components/ViewEditor/ViewEditor.stories.tsx +6 -7
- package/src/components/ViewEditor/ViewEditor.test.tsx +9 -3
- package/src/components/ViewEditor/ViewEditor.tsx +98 -128
- package/src/components/index.ts +0 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useAsyncFieldEffect.ts +81 -0
- package/src/hooks/useFormContext.ts +89 -0
- package/src/hooks/useFormHandler.ts +12 -10
- package/src/index.ts +2 -0
- package/src/{components/testing.tsx → testing/TestLayout.tsx} +16 -13
- package/src/testing/index.ts +7 -0
- package/src/testing/schema.ts +59 -0
- package/src/types.ts +186 -0
- package/src/util/index.ts +1 -1
- package/src/util/omit.ts +61 -0
- package/src/util/properties.test.ts +110 -28
- package/src/util/refs.ts +1 -1
- package/src/vitest-setup.ts +40 -0
- package/dist/types/src/components/Form/FormField.d.ts +0 -52
- package/dist/types/src/components/Form/FormField.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormFieldComponent.d.ts +0 -98
- package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormFieldSet.d.ts +0 -26
- package/dist/types/src/components/Form/FormFieldSet.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormTooltipsContext.d.ts +0 -19
- package/dist/types/src/components/Form/FormTooltipsContext.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/FormLayout.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/FormLayout.stories.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/FormLayout.stories.test.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/FormLayout.test.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/annotation.d.ts +0 -30
- package/dist/types/src/components/Form/Layout/annotation.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/index.d.ts +0 -4
- package/dist/types/src/components/Form/Layout/index.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/parser.d.ts.map +0 -1
- package/dist/types/src/components/Form/Layout/parser.test.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/BooleanField.d.ts +0 -4
- package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/DateField.d.ts +0 -4
- package/dist/types/src/components/Form/fields/DateField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/GeoPointField.d.ts +0 -5
- package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/InlineRefField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/NumberField.d.ts +0 -4
- package/dist/types/src/components/Form/fields/NumberField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/RefField.d.ts +0 -34
- package/dist/types/src/components/Form/fields/RefField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/RefField.test.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/SelectField.d.ts +0 -13
- package/dist/types/src/components/Form/fields/SelectField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +0 -5
- package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/TextAreaField.d.ts +0 -4
- package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/TextField.d.ts +0 -4
- package/dist/types/src/components/Form/fields/TextField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/TupleField.d.ts.map +0 -1
- package/dist/types/src/components/Form/fields/index.d.ts.map +0 -1
- package/dist/types/src/components/Settings/Settings.d.ts +0 -51
- package/dist/types/src/components/Settings/Settings.d.ts.map +0 -1
- package/dist/types/src/components/Settings/Settings.stories.d.ts.map +0 -1
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +0 -43
- package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +0 -1
- package/dist/types/src/components/Settings/SettingsItem.d.ts +0 -16
- package/dist/types/src/components/Settings/SettingsItem.d.ts.map +0 -1
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts +0 -18
- package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +0 -1
- package/dist/types/src/components/Settings/index.d.ts +0 -4
- package/dist/types/src/components/Settings/index.d.ts.map +0 -1
- package/dist/types/src/components/testing.d.ts.map +0 -1
- package/dist/types/src/util/field-type.d.ts +0 -19
- package/dist/types/src/util/field-type.d.ts.map +0 -1
- package/src/components/Form/AUDIT.md +0 -17
- package/src/components/Form/FormFieldComponent.stories.tsx +0 -65
- package/src/components/Form/FormFieldComponent.tsx +0 -253
- package/src/components/Form/FormTooltipsContext.ts +0 -25
- package/src/components/Form/Layout/annotation.ts +0 -38
- package/src/components/Form/Layout/index.ts +0 -7
- package/src/components/Form/README.md +0 -3
- package/src/components/Form/fields/ArrayField.tsx +0 -173
- package/src/components/Form/fields/BooleanField.tsx +0 -22
- package/src/components/Form/fields/NumberField.tsx +0 -76
- package/src/components/Form/fields/SelectField.tsx +0 -77
- package/src/components/Settings/AUDIT.md +0 -51
- package/src/components/Settings/Settings.stories.tsx +0 -104
- package/src/components/Settings/Settings.tsx +0 -81
- package/src/components/Settings/SettingsFieldSet.tsx +0 -257
- package/src/components/Settings/SettingsItem.tsx +0 -58
- package/src/components/Settings/SettingsSelectField.tsx +0 -59
- package/src/components/Settings/index.ts +0 -7
- package/src/util/field-type.ts +0 -60
- /package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.d.ts +0 -0
- /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.d.ts +0 -0
- /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.d.ts +0 -0
- /package/dist/types/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.d.ts +0 -0
- /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.d.ts +0 -0
- /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.test.d.ts +0 -0
- /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.d.ts +0 -0
- /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.test.d.ts +0 -0
- /package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.tsx +0 -0
- /package/src/components/Form/{Layout → FormLayout}/FormLayout.test.ts +0 -0
- /package/src/components/Form/{Layout → FormLayout}/parser.test.ts +0 -0
- /package/src/components/Form/{Layout → FormLayout}/parser.ts +0 -0
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { createContext, useContext } from 'react';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A standalone context for the `tooltips` flag (Form.Root's only label
|
|
9
|
-
* decoration today: a JSON-path hover tooltip rendered by
|
|
10
|
-
* `FormFieldLabel`).
|
|
11
|
-
*
|
|
12
|
-
* Lives in its own module so that `FormFieldComponent.tsx` -- imported at
|
|
13
|
-
* the top of `Form.tsx` -- can read the flag without re-importing from
|
|
14
|
-
* `Form.tsx`. That round-trip used to create a circular module-eval
|
|
15
|
-
* dependency that intermittently hit a TDZ ("Cannot access 'FormFieldLabel'
|
|
16
|
-
* before initialization") in browser-mode storybook tests.
|
|
17
|
-
*
|
|
18
|
-
* Defaults to `true` both when `Form.Root` doesn't pass an explicit value
|
|
19
|
-
* AND when there is no enclosing `Form.Root` (e.g. `FormFieldWrapper`
|
|
20
|
-
* stories that render an input without a Form provider).
|
|
21
|
-
*/
|
|
22
|
-
export const FormTooltipsContext = createContext<boolean>(true);
|
|
23
|
-
|
|
24
|
-
/** Returns whether the enclosing `Form.Root` has field tooltips enabled. */
|
|
25
|
-
export const useFormTooltips = (): boolean => useContext(FormTooltipsContext);
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2026 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { createAnnotationHelper } from '@dxos/echo/internal';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Annotation carrying one or more named `FormLayout` DSL templates that
|
|
9
|
-
* control how `Form.FieldSet` / `Form.Layout` arrange a schema's fields.
|
|
10
|
-
* Callers select a variant via the `name` prop; the implicit name is
|
|
11
|
-
* `DEFAULT_LAYOUT_NAME` (`'default'`).
|
|
12
|
-
*
|
|
13
|
-
* Templates use a minimal XML grammar — see `parser.ts`. Example:
|
|
14
|
-
*
|
|
15
|
-
* FormLayoutAnnotation.set({
|
|
16
|
-
* default: `
|
|
17
|
-
* <grid cols="2">
|
|
18
|
-
* <field name="origin"/>
|
|
19
|
-
* <field name="destination"/>
|
|
20
|
-
* <field name="provider" span="2"/>
|
|
21
|
-
* </grid>
|
|
22
|
-
* `,
|
|
23
|
-
* card: `
|
|
24
|
-
* <grid cols="1">
|
|
25
|
-
* <field name="provider"/>
|
|
26
|
-
* <field name="number"/>
|
|
27
|
-
* </grid>
|
|
28
|
-
* `,
|
|
29
|
-
* })
|
|
30
|
-
*/
|
|
31
|
-
export const FormLayoutAnnotationId = Symbol.for('@dxos/react-ui-form/annotation/Layout');
|
|
32
|
-
|
|
33
|
-
export type FormLayoutMap = Record<string, string>;
|
|
34
|
-
|
|
35
|
-
export const FormLayoutAnnotation = createAnnotationHelper<FormLayoutMap>(FormLayoutAnnotationId);
|
|
36
|
-
|
|
37
|
-
/** Name used when no explicit variant is requested. */
|
|
38
|
-
export const DEFAULT_LAYOUT_NAME = 'default';
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import * as Option from 'effect/Option';
|
|
6
|
-
import * as SchemaAST from 'effect/SchemaAST';
|
|
7
|
-
import React, { useCallback } from 'react';
|
|
8
|
-
|
|
9
|
-
import { Ref } from '@dxos/echo';
|
|
10
|
-
import { SchemaEx } from '@dxos/effect';
|
|
11
|
-
import { useTranslation } from '@dxos/react-ui';
|
|
12
|
-
|
|
13
|
-
import { translationKey } from '#translations';
|
|
14
|
-
|
|
15
|
-
import { getFormProperties } from '../../../util';
|
|
16
|
-
import { useFormValues } from '../Form';
|
|
17
|
-
import { FormField, IconBlock, type FormFieldProps } from '../FormField';
|
|
18
|
-
import { FormFieldLabel, type FormFieldStateProps } from '../FormFieldComponent';
|
|
19
|
-
|
|
20
|
-
export type ArrayFieldProps = {
|
|
21
|
-
label: string;
|
|
22
|
-
fieldProps: FormFieldStateProps;
|
|
23
|
-
} & FormFieldProps;
|
|
24
|
-
|
|
25
|
-
export const ArrayField = ({
|
|
26
|
-
type,
|
|
27
|
-
path,
|
|
28
|
-
label,
|
|
29
|
-
readonly,
|
|
30
|
-
layout,
|
|
31
|
-
fieldProps: inputProps,
|
|
32
|
-
...props
|
|
33
|
-
}: ArrayFieldProps) => {
|
|
34
|
-
const { t } = useTranslation(translationKey);
|
|
35
|
-
const elementType = SchemaEx.getArrayElementType(type);
|
|
36
|
-
const { onValueChange } = inputProps;
|
|
37
|
-
const values = useFormValues(ArrayField.displayName, path, () => []);
|
|
38
|
-
|
|
39
|
-
const getDefaultObjectValue = (typeNode: SchemaAST.AST): any => {
|
|
40
|
-
const baseNode = SchemaEx.findNode(typeNode, SchemaEx.isDiscriminatedUnion);
|
|
41
|
-
const typeLiteral = baseNode
|
|
42
|
-
? SchemaEx.getDiscriminatedType(baseNode, {})
|
|
43
|
-
: SchemaEx.findNode(typeNode, SchemaAST.isTypeLiteral);
|
|
44
|
-
if (!typeLiteral) {
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return Object.fromEntries(
|
|
49
|
-
getFormProperties(typeLiteral).map((prop) => {
|
|
50
|
-
const defaultValue = SchemaAST.getDefaultAnnotation(prop.type).pipe((annotation) =>
|
|
51
|
-
Option.getOrUndefined(annotation),
|
|
52
|
-
);
|
|
53
|
-
return [prop.name, defaultValue];
|
|
54
|
-
}),
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleAdd = useCallback(() => {
|
|
59
|
-
const defaultValue =
|
|
60
|
-
SchemaEx.isNestedType(type) && elementType ? getDefaultObjectValue(elementType) : getDefaultValue(elementType);
|
|
61
|
-
// `values` is `undefined` on first render for arrays whose parent path
|
|
62
|
-
// hasn't been materialised in the form values yet (e.g. `package.repos`
|
|
63
|
-
// when the form starts with no `package`). `useFormValues`'s default-
|
|
64
|
-
// value effect would eventually backfill it to `[]`, but until then the
|
|
65
|
-
// old `values && ...` guard silently swallowed the click. Treat a
|
|
66
|
-
// missing array as empty so Add always produces `[defaultValue]`.
|
|
67
|
-
onValueChange(type, [...(values ?? []), defaultValue]);
|
|
68
|
-
}, [onValueChange, type, elementType, values]);
|
|
69
|
-
|
|
70
|
-
const handleDelete = useCallback(
|
|
71
|
-
(idx: number) => {
|
|
72
|
-
onValueChange(
|
|
73
|
-
type,
|
|
74
|
-
values?.filter((_, i) => i !== idx),
|
|
75
|
-
);
|
|
76
|
-
},
|
|
77
|
-
[onValueChange, type, values],
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
if (!elementType || ((readonly || layout === 'static') && values && values.length < 1)) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const renderItemAsObject = elementType && SchemaEx.isNestedType(elementType) && !Ref.isRefType(elementType);
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<>
|
|
88
|
-
{(layout !== 'static' || (values && values.length > 0)) && (
|
|
89
|
-
<div className='flex items-center gap-2'>
|
|
90
|
-
<div className='flex-1 min-w-0'>
|
|
91
|
-
<FormFieldLabel readonly={readonly} label={label} path={SchemaEx.createJsonPath(path ?? [])} asChild />
|
|
92
|
-
</div>
|
|
93
|
-
{!readonly && layout !== 'static' && (
|
|
94
|
-
<IconBlock inline icon='ph--plus--regular' label={t('add-item.button')} onClick={handleAdd} />
|
|
95
|
-
)}
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
98
|
-
|
|
99
|
-
<div className='flex flex-col'>
|
|
100
|
-
{values?.map((_, index) => {
|
|
101
|
-
const isLast = index === values.length - 1;
|
|
102
|
-
|
|
103
|
-
// Object items: each row contains a recursively-rendered FormField
|
|
104
|
-
// (multiple sub-rows for the object's fields) wrapped in a border,
|
|
105
|
-
// with the delete button bottom-aligned next to it.
|
|
106
|
-
// Scalar items: a single-row inline FormField with a center-aligned
|
|
107
|
-
// delete button. Refs and primitive arrays use this layout.
|
|
108
|
-
const fieldField = (
|
|
109
|
-
<FormField
|
|
110
|
-
{...props}
|
|
111
|
-
autoFocus={isLast}
|
|
112
|
-
type={elementType}
|
|
113
|
-
// Suppress the per-item header for object items only — the recursive
|
|
114
|
-
// form already renders labels for each sub-field. Scalar items
|
|
115
|
-
// (refs, primitives) keep the parent name so inline-layout
|
|
116
|
-
// children (e.g. RefField) have a real label to use as a
|
|
117
|
-
// fallback placeholder.
|
|
118
|
-
{...(renderItemAsObject && { name: null })}
|
|
119
|
-
path={[...(path ?? []), index]}
|
|
120
|
-
readonly={readonly || layout === 'static'}
|
|
121
|
-
layout={renderItemAsObject ? (layout === 'static' ? 'static' : undefined) : 'inline'}
|
|
122
|
-
/>
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<div key={index} className='grid grid-cols-[1fr_min-content] items-center mb-1 last:mb-form-gap'>
|
|
127
|
-
{fieldField}
|
|
128
|
-
{!readonly && layout !== 'static' && (
|
|
129
|
-
<IconBlock
|
|
130
|
-
inline={!renderItemAsObject}
|
|
131
|
-
icon='ph--x--regular'
|
|
132
|
-
label={t('remove-item.button')}
|
|
133
|
-
onClick={() => handleDelete(index)}
|
|
134
|
-
/>
|
|
135
|
-
)}
|
|
136
|
-
</div>
|
|
137
|
-
);
|
|
138
|
-
})}
|
|
139
|
-
</div>
|
|
140
|
-
</>
|
|
141
|
-
);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
ArrayField.displayName = 'Form.ArrayField';
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Returns the default empty value for a given AST.
|
|
148
|
-
* Used for initializing new array values etc.
|
|
149
|
-
*/
|
|
150
|
-
// TODO(wittjosiah): Factor out?
|
|
151
|
-
export const getDefaultValue = (ast?: SchemaAST.AST): any => {
|
|
152
|
-
switch (ast?._tag) {
|
|
153
|
-
case 'StringKeyword': {
|
|
154
|
-
return '';
|
|
155
|
-
}
|
|
156
|
-
case 'NumberKeyword': {
|
|
157
|
-
return 0;
|
|
158
|
-
}
|
|
159
|
-
case 'BooleanKeyword': {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
case 'Suspend': {
|
|
163
|
-
return getDefaultValue(ast.f());
|
|
164
|
-
}
|
|
165
|
-
default: {
|
|
166
|
-
if (ast && SchemaEx.isNestedType(ast)) {
|
|
167
|
-
return {};
|
|
168
|
-
} else {
|
|
169
|
-
throw new Error(`Unsupported type: ${ast?._tag}`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React, { useCallback } from 'react';
|
|
6
|
-
|
|
7
|
-
import { Input, type SwitchProps } from '@dxos/react-ui';
|
|
8
|
-
|
|
9
|
-
import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
|
|
10
|
-
|
|
11
|
-
export const BooleanField = ({ type, readonly, onValueChange, ...props }: FormFieldComponentProps<boolean>) => {
|
|
12
|
-
const handleChange = useCallback<NonNullable<SwitchProps['onCheckedChange']>>(
|
|
13
|
-
(value) => onValueChange?.(type, value),
|
|
14
|
-
[type, onValueChange],
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<FormFieldWrapper<boolean> readonly={readonly} {...props}>
|
|
19
|
-
{({ value }) => <Input.Switch disabled={!!readonly} checked={value} onCheckedChange={handleChange} />}
|
|
20
|
-
</FormFieldWrapper>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
6
|
-
|
|
7
|
-
import { Input, type TextInputProps } from '@dxos/react-ui';
|
|
8
|
-
import { safeParseFloat } from '@dxos/util';
|
|
9
|
-
|
|
10
|
-
import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
|
|
11
|
-
|
|
12
|
-
export const NumberField = ({
|
|
13
|
-
type,
|
|
14
|
-
readonly,
|
|
15
|
-
placeholder,
|
|
16
|
-
getValue,
|
|
17
|
-
onValueChange,
|
|
18
|
-
onBlur,
|
|
19
|
-
...props
|
|
20
|
-
}: FormFieldComponentProps<number>) => {
|
|
21
|
-
// Track raw string input so the user can clear the field before typing a new number.
|
|
22
|
-
// We only commit to onValueChange when the raw string parses to a valid number.
|
|
23
|
-
const [raw, setRaw] = useState<string>(() => {
|
|
24
|
-
const v = getValue();
|
|
25
|
-
return v !== undefined ? String(v) : '';
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Sync display when an external change updates the committed value (e.g. reactive form
|
|
29
|
-
// calculations). Only overwrite raw when the external value differs from what raw parses
|
|
30
|
-
// to, preserving partial edits like "1." which correctly parse to 1.
|
|
31
|
-
const externalValue = getValue();
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (externalValue !== safeParseFloat(raw)) {
|
|
34
|
-
setRaw(externalValue !== undefined ? String(externalValue) : '');
|
|
35
|
-
}
|
|
36
|
-
}, [externalValue]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
37
|
-
|
|
38
|
-
const handleChange = useCallback<NonNullable<TextInputProps['onChange']>>(
|
|
39
|
-
(event) => {
|
|
40
|
-
const value = event.target.value;
|
|
41
|
-
setRaw(value);
|
|
42
|
-
const parsed = safeParseFloat(value);
|
|
43
|
-
if (parsed !== undefined) {
|
|
44
|
-
onValueChange(type, parsed);
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
[type, onValueChange],
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const handleBlur = useCallback(
|
|
51
|
-
(event: React.FocusEvent<HTMLElement>) => {
|
|
52
|
-
// If the field was left empty or invalid, reset to the last committed value.
|
|
53
|
-
if (safeParseFloat(raw) === undefined) {
|
|
54
|
-
const committed = getValue();
|
|
55
|
-
setRaw(committed !== undefined ? String(committed) : '');
|
|
56
|
-
}
|
|
57
|
-
onBlur(event);
|
|
58
|
-
},
|
|
59
|
-
[raw, getValue, onBlur],
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<FormFieldWrapper<number> readonly={readonly} getValue={getValue} {...props}>
|
|
64
|
-
{() => (
|
|
65
|
-
<Input.TextInput
|
|
66
|
-
type='number'
|
|
67
|
-
disabled={!!readonly}
|
|
68
|
-
placeholder={placeholder}
|
|
69
|
-
value={raw}
|
|
70
|
-
onChange={handleChange}
|
|
71
|
-
onBlur={handleBlur}
|
|
72
|
-
/>
|
|
73
|
-
)}
|
|
74
|
-
</FormFieldWrapper>
|
|
75
|
-
);
|
|
76
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React, { useCallback } from 'react';
|
|
6
|
-
|
|
7
|
-
import { Icon, Input, Select, type SelectRootProps } from '@dxos/react-ui';
|
|
8
|
-
import { getStyles } from '@dxos/ui-theme';
|
|
9
|
-
|
|
10
|
-
import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
|
|
11
|
-
|
|
12
|
-
export type SelectFieldOptions = FormFieldComponentProps & {
|
|
13
|
-
options?: Array<{ value: string | number; label?: string; secondaryLabel?: string; icon?: string; iconHue?: string }>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const SelectField = ({
|
|
17
|
-
type,
|
|
18
|
-
readonly,
|
|
19
|
-
label,
|
|
20
|
-
jsonPath,
|
|
21
|
-
layout,
|
|
22
|
-
placeholder,
|
|
23
|
-
options,
|
|
24
|
-
getStatus,
|
|
25
|
-
getValue,
|
|
26
|
-
onValueChange,
|
|
27
|
-
}: SelectFieldOptions) => {
|
|
28
|
-
const { status, error } = getStatus();
|
|
29
|
-
const value = getValue() as string | undefined;
|
|
30
|
-
|
|
31
|
-
const handleValueChange = useCallback<NonNullable<SelectRootProps['onValueChange']>>(
|
|
32
|
-
(value) => onValueChange(type, value),
|
|
33
|
-
[type, onValueChange],
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
if ((readonly || layout === 'static') && value == null) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Input.Root validationValence={status}>
|
|
42
|
-
{layout !== 'inline' && <FormFieldLabel error={error} readonly={readonly} label={label} path={jsonPath} />}
|
|
43
|
-
{layout === 'static' ? (
|
|
44
|
-
<p>{options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)}</p>
|
|
45
|
-
) : (
|
|
46
|
-
<Select.Root value={value} onValueChange={handleValueChange}>
|
|
47
|
-
{/* TODO(burdon): Placeholder not working? */}
|
|
48
|
-
<Select.TriggerButton classNames='w-full' disabled={!!readonly} placeholder={placeholder} />
|
|
49
|
-
<Select.Portal>
|
|
50
|
-
<Select.Content>
|
|
51
|
-
<Select.Viewport>
|
|
52
|
-
{options?.map(({ value, label, secondaryLabel, icon, iconHue }) => (
|
|
53
|
-
// NOTE: Numeric values are converted to and from strings.
|
|
54
|
-
<Select.Option key={String(value)} value={String(value)}>
|
|
55
|
-
<span className='flex items-center flex-row gap-2'>
|
|
56
|
-
{icon && <Icon icon={icon} classNames={getIconHueStyles(iconHue)} />}
|
|
57
|
-
{label ?? String(value)}
|
|
58
|
-
{secondaryLabel && <span className='text-subdued text-xs'>{secondaryLabel}</span>}
|
|
59
|
-
</span>
|
|
60
|
-
</Select.Option>
|
|
61
|
-
))}
|
|
62
|
-
</Select.Viewport>
|
|
63
|
-
<Select.Arrow />
|
|
64
|
-
</Select.Content>
|
|
65
|
-
</Select.Portal>
|
|
66
|
-
</Select.Root>
|
|
67
|
-
)}
|
|
68
|
-
{layout === 'full' && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
|
|
69
|
-
</Input.Root>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const getIconHueStyles = (iconHue?: string): string | undefined => {
|
|
74
|
-
const styles = iconHue ? getStyles(iconHue) : undefined;
|
|
75
|
-
|
|
76
|
-
return styles?.fg;
|
|
77
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Plugin Settings Audit
|
|
2
|
-
|
|
3
|
-
Tracks which plugin settings panels use schema-driven `Settings.FieldSet` and which still hand-roll their controls.
|
|
4
|
-
|
|
5
|
-
The target shape for a plugin settings panel is:
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
<SettingsForm.Viewport>
|
|
9
|
-
<SettingsForm.Section title={t('settings.title', { ns: meta.id })}>
|
|
10
|
-
<SettingsForm.FieldSet
|
|
11
|
-
readonly={!onSettingsChange}
|
|
12
|
-
schema={Settings.Settings}
|
|
13
|
-
values={settings}
|
|
14
|
-
onValuesChanged={(values) => onSettingsChange?.(() => values)}
|
|
15
|
-
/>
|
|
16
|
-
</SettingsForm.Section>
|
|
17
|
-
</SettingsForm.Viewport>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Field labels and descriptions come from `.annotations({ title, description })` on each schema field. Use `fieldMap` for runtime-driven option lists (model pickers, etc.). Use the `visible` callback to gate fields on environment or sibling values.
|
|
21
|
-
|
|
22
|
-
## FieldSet adopters
|
|
23
|
-
|
|
24
|
-
| Plugin | Notes |
|
|
25
|
-
| ---------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
26
|
-
| `plugin-assistant` | Nested `modelDefaults` struct; `fieldMap` provides per-provider model selectors via `createSelectField`. |
|
|
27
|
-
| `plugin-crx` | Two booleans. |
|
|
28
|
-
| `plugin-deck` | Five booleans; `enableNativeRedirect` hidden via `visible` when `isSocket`. |
|
|
29
|
-
| `plugin-inbox` | Single boolean. |
|
|
30
|
-
| `plugin-markdown` | Original reference adopter. `snippets` text field gated via `visible`/`fieldMap`. |
|
|
31
|
-
| `plugin-meeting` | Single boolean. |
|
|
32
|
-
| `plugin-observability` | Boolean; info `Message.Root` banner kept above `FieldSet`. |
|
|
33
|
-
| `plugin-presenter` | Single boolean. |
|
|
34
|
-
| `plugin-sample` | Single boolean. |
|
|
35
|
-
| `plugin-script` | Mixed: auth `Button` retained as a manual `SettingsForm.Item`; `editorInputMode` rendered by `FieldSet`. |
|
|
36
|
-
| `plugin-sketch` | Boolean + `gridType` literal union (rendered as a Select — was previously a Switch). |
|
|
37
|
-
|
|
38
|
-
## Skipped
|
|
39
|
-
|
|
40
|
-
| Plugin | Reason |
|
|
41
|
-
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
42
|
-
| `plugin-debug` | Action buttons (download diagnostics, download logs, repair), `Toast`, and a storage-adapter selector wired to `client.config` rather than the plugin settings atom. |
|
|
43
|
-
| `plugin-space` | Renders a list of spaces with per-space "open settings" buttons — not bound to any schema field. |
|
|
44
|
-
| `plugin-spacetime` | Section is currently empty; nothing to render. |
|
|
45
|
-
| `plugin-thread` | Settings schema is `Schema.Struct({})` — nothing to render. |
|
|
46
|
-
|
|
47
|
-
## When to extend `SettingsFieldSet` vs. add a custom field
|
|
48
|
-
|
|
49
|
-
- **Extend `SettingsFieldSet`** when the rendering rule applies generally to a schema construct (e.g. nested structs recursing into sibling fields, literal unions becoming Selects). Keep auto-detection in `detectFieldType`.
|
|
50
|
-
- **Use `fieldMap`** when the schema can't fully describe the rendering — runtime-driven option lists, custom inputs, or override of the auto-rendered control. Use the typed form `SettingsFieldMap<T>` (or `satisfies SettingsFieldMap<Settings>`) so the entries are checked against the values shape.
|
|
51
|
-
- **Drop back to manual `SettingsForm.Item`** when the panel needs UI that isn't bound to a settings field at all (action buttons, info banners, lists of external entities). These coexist as siblings of `FieldSet` inside the same `Section`.
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
-
import * as Schema from 'effect/Schema';
|
|
7
|
-
import React from 'react';
|
|
8
|
-
|
|
9
|
-
import { random } from '@dxos/random';
|
|
10
|
-
import { Button, Input } from '@dxos/react-ui';
|
|
11
|
-
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
|
-
|
|
13
|
-
import { translations } from '#translations';
|
|
14
|
-
|
|
15
|
-
import { Settings } from './Settings';
|
|
16
|
-
|
|
17
|
-
random.seed(132);
|
|
18
|
-
|
|
19
|
-
const DefaultStory = () => {
|
|
20
|
-
return (
|
|
21
|
-
<Settings.Viewport>
|
|
22
|
-
<Settings.Section title='Settings' description={random.lorem.paragraphs(1)}>
|
|
23
|
-
<Settings.Item title={random.lorem.sentence(2)} description={random.lorem.paragraphs(1)}>
|
|
24
|
-
<Input.TextInput placeholder='Input' />
|
|
25
|
-
</Settings.Item>
|
|
26
|
-
<Settings.Item title={random.lorem.sentence(2)} description={random.lorem.paragraphs(2)}>
|
|
27
|
-
<Input.Switch />
|
|
28
|
-
</Settings.Item>
|
|
29
|
-
<Settings.Item title={random.lorem.sentence(3)} description={random.lorem.paragraphs(2)}>
|
|
30
|
-
<Button>Test</Button>
|
|
31
|
-
</Settings.Item>
|
|
32
|
-
</Settings.Section>
|
|
33
|
-
<Settings.Section title='Panel Example'>
|
|
34
|
-
<Settings.Panel>
|
|
35
|
-
<h3 className='text-lg mb-2'>Members</h3>
|
|
36
|
-
<p className='text-description'>Content inside a panel.</p>
|
|
37
|
-
</Settings.Panel>
|
|
38
|
-
</Settings.Section>
|
|
39
|
-
</Settings.Viewport>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const meta = {
|
|
44
|
-
title: 'ui/react-ui-form/Settings',
|
|
45
|
-
render: DefaultStory,
|
|
46
|
-
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
47
|
-
parameters: {
|
|
48
|
-
layout: 'fullscreen',
|
|
49
|
-
translations,
|
|
50
|
-
},
|
|
51
|
-
} satisfies Meta;
|
|
52
|
-
|
|
53
|
-
export default meta;
|
|
54
|
-
|
|
55
|
-
type Story = StoryObj<typeof meta>;
|
|
56
|
-
|
|
57
|
-
export const Default: Story = {};
|
|
58
|
-
|
|
59
|
-
const TestViewModes = ['preview', 'readonly', 'source'] as const;
|
|
60
|
-
const TestViewMode = Schema.Union(...TestViewModes.map((mode) => Schema.Literal(mode)));
|
|
61
|
-
|
|
62
|
-
const TestSettings = Schema.mutable(
|
|
63
|
-
Schema.Struct({
|
|
64
|
-
viewMode: TestViewMode.annotations({ title: 'View mode', description: 'Default document view mode.' }),
|
|
65
|
-
toolbar: Schema.optional(
|
|
66
|
-
Schema.Boolean.annotations({ title: 'Show toolbar', description: 'Display formatting toolbar.' }),
|
|
67
|
-
),
|
|
68
|
-
fontSize: Schema.optional(
|
|
69
|
-
Schema.Number.annotations({ title: 'Font size', description: 'Editor font size in pixels.' }),
|
|
70
|
-
),
|
|
71
|
-
placeholder: Schema.optional(
|
|
72
|
-
Schema.String.annotations({ title: 'Placeholder', description: 'Default placeholder text.' }),
|
|
73
|
-
),
|
|
74
|
-
debug: Schema.optional(Schema.Boolean.annotations({ title: 'Debug mode', description: 'Enable debug features.' })),
|
|
75
|
-
}),
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
type TestSettings = Schema.Schema.Type<typeof TestSettings>;
|
|
79
|
-
|
|
80
|
-
const FieldSetStory = () => {
|
|
81
|
-
const [values, setValues] = React.useState<TestSettings>({
|
|
82
|
-
viewMode: 'preview',
|
|
83
|
-
toolbar: true,
|
|
84
|
-
fontSize: 14,
|
|
85
|
-
debug: false,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<Settings.Viewport>
|
|
90
|
-
<Settings.Section title='Plugin Settings (Auto-generated)'>
|
|
91
|
-
<Settings.FieldSet
|
|
92
|
-
schema={TestSettings}
|
|
93
|
-
values={values}
|
|
94
|
-
onValuesChanged={setValues}
|
|
95
|
-
visible={(path, values) => path !== 'placeholder' || !!values.debug}
|
|
96
|
-
/>
|
|
97
|
-
</Settings.Section>
|
|
98
|
-
</Settings.Viewport>
|
|
99
|
-
);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
export const FieldSet: Story = {
|
|
103
|
-
render: FieldSetStory,
|
|
104
|
-
};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React, { type PropsWithChildren } from 'react';
|
|
6
|
-
|
|
7
|
-
import { type Label, ScrollArea, type ThemedClassName, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
|
-
import { composable, composableProps } from '@dxos/react-ui';
|
|
9
|
-
import { mx } from '@dxos/ui-theme';
|
|
10
|
-
|
|
11
|
-
import { translationKey } from '#translations';
|
|
12
|
-
|
|
13
|
-
import { SettingsFieldSet } from './SettingsFieldSet';
|
|
14
|
-
import { SettingsItem, SettingsPanel } from './SettingsItem';
|
|
15
|
-
|
|
16
|
-
const SETTINGS_ROOT_NAME = 'Settings.Root';
|
|
17
|
-
const SETTINGS_VIEWPORT_NAME = 'Settings.Viewport';
|
|
18
|
-
const SETTINGS_SECTION_NAME = 'Settings.Section';
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
// Root (headless — no styling, no scroll).
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
type SettingsRootProps = ThemedClassName<PropsWithChildren>;
|
|
25
|
-
|
|
26
|
-
const SettingsRoot = ({ children, classNames }: SettingsRootProps) => {
|
|
27
|
-
return <div className={mx('flex flex-col gap-2', classNames)}>{children}</div>;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
SettingsRoot.displayName = SETTINGS_ROOT_NAME;
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
// Viewport (scroll area + padding + document layout).
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
const SettingsViewport = composable<HTMLDivElement>(({ children, ...props }, forwardedRef) => {
|
|
37
|
-
return (
|
|
38
|
-
<ScrollArea.Root {...composableProps(props)} orientation='vertical' centered thin ref={forwardedRef}>
|
|
39
|
-
<ScrollArea.Viewport classNames='px-4 pointer-coarse:px-2'>
|
|
40
|
-
<div className='dx-document flex flex-col gap-2 py-4'>{children}</div>
|
|
41
|
-
</ScrollArea.Viewport>
|
|
42
|
-
</ScrollArea.Root>
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
SettingsViewport.displayName = SETTINGS_VIEWPORT_NAME;
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
// Section (title + optional description + children with spacing).
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
type SettingsSectionProps = PropsWithChildren<{
|
|
53
|
-
title: Label;
|
|
54
|
-
description?: Label;
|
|
55
|
-
}>;
|
|
56
|
-
|
|
57
|
-
const SettingsSection = ({ title, description, children }: SettingsSectionProps) => {
|
|
58
|
-
const { t } = useTranslation(translationKey);
|
|
59
|
-
return (
|
|
60
|
-
<>
|
|
61
|
-
<h2 className='px-trim-md mt-trim-md text-xl'>{toLocalizedString(title, t)}</h2>
|
|
62
|
-
{description && <p className='px-trim-md text-description'>{toLocalizedString(description, t)}</p>}
|
|
63
|
-
<div className='w-full pt-trim-md space-y-trim-md'>{children}</div>
|
|
64
|
-
</>
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
SettingsSection.displayName = SETTINGS_SECTION_NAME;
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
// Settings
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
export const Settings = {
|
|
75
|
-
Root: SettingsRoot,
|
|
76
|
-
Viewport: SettingsViewport,
|
|
77
|
-
Section: SettingsSection,
|
|
78
|
-
Panel: SettingsPanel,
|
|
79
|
-
Item: SettingsItem,
|
|
80
|
-
FieldSet: SettingsFieldSet,
|
|
81
|
-
};
|