@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-form",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1-staging.ee54ba693a",
|
|
4
4
|
"description": "Data components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"imports": {
|
|
15
|
-
"#translations": "./src/translations.ts"
|
|
15
|
+
"#translations": "./src/translations.ts",
|
|
16
|
+
"#types": "./src/types.ts"
|
|
16
17
|
},
|
|
17
18
|
"exports": {
|
|
18
19
|
".": {
|
|
@@ -43,52 +44,53 @@
|
|
|
43
44
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
44
45
|
"date-fns": "^3.6.0",
|
|
45
46
|
"tabster": "^8.5.5",
|
|
46
|
-
"@dxos/
|
|
47
|
-
"@dxos/echo-
|
|
48
|
-
"@dxos/echo
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/echo-react": "0.9.
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/react-
|
|
57
|
-
"@dxos/react-ui-
|
|
58
|
-
"@dxos/react-
|
|
59
|
-
"@dxos/react-ui-
|
|
60
|
-
"@dxos/react-ui-
|
|
61
|
-
"@dxos/
|
|
62
|
-
"@dxos/
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/ui
|
|
66
|
-
"@dxos/util": "0.9.
|
|
47
|
+
"@dxos/async": "0.9.1-staging.ee54ba693a",
|
|
48
|
+
"@dxos/echo-doc": "0.9.1-staging.ee54ba693a",
|
|
49
|
+
"@dxos/echo": "0.9.1-staging.ee54ba693a",
|
|
50
|
+
"@dxos/echo-protocol": "0.9.1-staging.ee54ba693a",
|
|
51
|
+
"@dxos/echo-react": "0.9.1-staging.ee54ba693a",
|
|
52
|
+
"@dxos/effect": "0.9.1-staging.ee54ba693a",
|
|
53
|
+
"@dxos/invariant": "0.9.1-staging.ee54ba693a",
|
|
54
|
+
"@dxos/keys": "0.9.1-staging.ee54ba693a",
|
|
55
|
+
"@dxos/lit-ui": "0.9.1-staging.ee54ba693a",
|
|
56
|
+
"@dxos/log": "0.9.1-staging.ee54ba693a",
|
|
57
|
+
"@dxos/react-client": "0.9.1-staging.ee54ba693a",
|
|
58
|
+
"@dxos/react-ui-components": "0.9.1-staging.ee54ba693a",
|
|
59
|
+
"@dxos/react-ui-editor": "0.9.1-staging.ee54ba693a",
|
|
60
|
+
"@dxos/react-ui-list": "0.9.1-staging.ee54ba693a",
|
|
61
|
+
"@dxos/react-ui-markdown": "0.9.1-staging.ee54ba693a",
|
|
62
|
+
"@dxos/react-ui-pickers": "0.9.1-staging.ee54ba693a",
|
|
63
|
+
"@dxos/schema": "0.9.1-staging.ee54ba693a",
|
|
64
|
+
"@dxos/types": "0.9.1-staging.ee54ba693a",
|
|
65
|
+
"@dxos/react-ui-search": "0.9.1-staging.ee54ba693a",
|
|
66
|
+
"@dxos/ui": "0.9.1-staging.ee54ba693a",
|
|
67
|
+
"@dxos/util": "0.9.1-staging.ee54ba693a",
|
|
68
|
+
"@dxos/ui-editor": "0.9.1-staging.ee54ba693a"
|
|
67
69
|
},
|
|
68
70
|
"devDependencies": {
|
|
69
|
-
"@types/react": "~19.2.
|
|
71
|
+
"@types/react": "~19.2.17",
|
|
70
72
|
"@types/react-dom": "~19.2.3",
|
|
71
|
-
"effect": "3.21.
|
|
73
|
+
"effect": "3.21.4",
|
|
72
74
|
"fast-check": "^3.19.0",
|
|
73
|
-
"react": "~19.2.
|
|
74
|
-
"react-dom": "~19.2.
|
|
75
|
+
"react": "~19.2.7",
|
|
76
|
+
"react-dom": "~19.2.7",
|
|
75
77
|
"vite": "^8.0.16",
|
|
76
|
-
"@dxos/
|
|
77
|
-
"@dxos/
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/react-
|
|
81
|
-
"@dxos/react-ui-syntax-highlighter": "0.9.
|
|
82
|
-
"@dxos/
|
|
83
|
-
"@dxos/ui-types": "0.9.
|
|
84
|
-
"@dxos/
|
|
78
|
+
"@dxos/protocols": "0.9.1-staging.ee54ba693a",
|
|
79
|
+
"@dxos/react-client": "0.9.1-staging.ee54ba693a",
|
|
80
|
+
"@dxos/effect-proto": "0.9.1-staging.ee54ba693a",
|
|
81
|
+
"@dxos/random": "0.9.1-staging.ee54ba693a",
|
|
82
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a",
|
|
83
|
+
"@dxos/react-ui-syntax-highlighter": "0.9.1-staging.ee54ba693a",
|
|
84
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
|
|
85
|
+
"@dxos/ui-types": "0.9.1-staging.ee54ba693a",
|
|
86
|
+
"@dxos/storybook-utils": "0.9.1-staging.ee54ba693a"
|
|
85
87
|
},
|
|
86
88
|
"peerDependencies": {
|
|
87
|
-
"effect": "3.21.
|
|
88
|
-
"react": "~19.2.
|
|
89
|
-
"react-dom": "~19.2.
|
|
90
|
-
"@dxos/
|
|
91
|
-
"@dxos/ui
|
|
89
|
+
"effect": "3.21.4",
|
|
90
|
+
"react": "~19.2.7",
|
|
91
|
+
"react-dom": "~19.2.7",
|
|
92
|
+
"@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
|
|
93
|
+
"@dxos/react-ui": "0.9.1-staging.ee54ba693a"
|
|
92
94
|
},
|
|
93
95
|
"publishConfig": {
|
|
94
96
|
"access": "public"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { createAnnotationHelper } from '@dxos/echo/internal';
|
|
8
|
+
|
|
9
|
+
/** One selectable option produced by an {@link OptionsLookup}. */
|
|
10
|
+
export type OptionsLookupEntry = { value: string; label?: string; secondaryLabel?: string; icon?: string };
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Loads a select field's options dynamically from a declared subset of the form values, so a select can
|
|
14
|
+
* depend on a sibling field (e.g. publications for a typed handle). `deps` are the field names the loader
|
|
15
|
+
* reads; the form re-runs it only when one of those values changes. The returned Effect must be
|
|
16
|
+
* self-contained (`R = never`): it provides its own dependencies (network layer, etc.) in the closure.
|
|
17
|
+
* Construct via {@link optionsLookup} for typed `deps`/`values`. Pass `{ combobox: true }` to render
|
|
18
|
+
* an editable combobox (type-to-search) instead of a constrained select.
|
|
19
|
+
*/
|
|
20
|
+
export type OptionsLookup = {
|
|
21
|
+
readonly deps: readonly string[];
|
|
22
|
+
readonly load: (values: any) => Effect.Effect<readonly OptionsLookupEntry[], unknown>;
|
|
23
|
+
readonly combobox?: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const OptionsLookupAnnotationId = Symbol.for('@dxos/schema/annotation/OptionsLookup');
|
|
27
|
+
export const OptionsLookupAnnotation = createAnnotationHelper<OptionsLookup>(OptionsLookupAnnotationId);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Builds an {@link OptionsLookup} typed against a schema's value type `Values`: `deps` is checked
|
|
31
|
+
* against its field names, and `load` receives only those fields, narrowed. Pass `{ combobox: true }` to
|
|
32
|
+
* render an editable combobox.
|
|
33
|
+
*/
|
|
34
|
+
export const optionsLookup =
|
|
35
|
+
<Values>() =>
|
|
36
|
+
<const Deps extends readonly (keyof Values & string)[]>(
|
|
37
|
+
deps: Deps,
|
|
38
|
+
load: (values: Pick<Values, Deps[number]>) => Effect.Effect<readonly OptionsLookupEntry[], unknown>,
|
|
39
|
+
options?: { combobox?: boolean },
|
|
40
|
+
): OptionsLookup => ({ deps, load, combobox: options?.combobox });
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Derives a (text) field's value from a declared subset of the form values, so a field can be pre-filled
|
|
44
|
+
* from a sibling (e.g. a feed name fetched from a typed URL). `deps` are the field names the derivation
|
|
45
|
+
* reads; the form re-runs it only when one of those changes. The returned Effect must be self-contained
|
|
46
|
+
* (`R = never`); `undefined` means "no value to fill". The form pre-fills only while the user has not
|
|
47
|
+
* typed their own value, so a manual edit is never clobbered. Construct via {@link autofill}.
|
|
48
|
+
*/
|
|
49
|
+
export type Autofill = {
|
|
50
|
+
readonly deps: readonly string[];
|
|
51
|
+
readonly derive: (values: any) => Effect.Effect<string | undefined, unknown>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const AutofillAnnotationId = Symbol.for('@dxos/schema/annotation/Autofill');
|
|
55
|
+
export const AutofillAnnotation = createAnnotationHelper<Autofill>(AutofillAnnotationId);
|
|
56
|
+
|
|
57
|
+
/** Builds an {@link Autofill} typed against a schema's value type `Values` (see {@link optionsLookup}). */
|
|
58
|
+
export const autofill =
|
|
59
|
+
<Values>() =>
|
|
60
|
+
<const Deps extends readonly (keyof Values & string)[]>(
|
|
61
|
+
deps: Deps,
|
|
62
|
+
derive: (values: Pick<Values, Deps[number]>) => Effect.Effect<string | undefined, unknown>,
|
|
63
|
+
): Autofill => ({ deps, derive });
|
|
@@ -14,7 +14,7 @@ import { Example } from '@dxos/schema/testing';
|
|
|
14
14
|
|
|
15
15
|
import { translations } from '#translations';
|
|
16
16
|
|
|
17
|
-
import { FIELD_EDITOR_DEBUG_SYMBOL, TestLayout } from '
|
|
17
|
+
import { FIELD_EDITOR_DEBUG_SYMBOL, TestLayout } from '../../testing';
|
|
18
18
|
import { FieldEditor, type FieldEditorProps } from './FieldEditor';
|
|
19
19
|
|
|
20
20
|
export type FieldEditorDebugObjects = {
|
|
@@ -8,7 +8,7 @@ import { afterEach, describe, expect, test } from 'vitest';
|
|
|
8
8
|
|
|
9
9
|
import { ProjectionModel } from '@dxos/schema';
|
|
10
10
|
|
|
11
|
-
import { FIELD_EDITOR_DEBUG_SYMBOL } from '
|
|
11
|
+
import { FIELD_EDITOR_DEBUG_SYMBOL } from '../../testing';
|
|
12
12
|
import * as stories from './FieldEditor.stories';
|
|
13
13
|
import { type FieldEditorDebugObjects } from './FieldEditor.stories';
|
|
14
14
|
|
|
@@ -17,21 +17,22 @@ import {
|
|
|
17
17
|
} from '@dxos/schema';
|
|
18
18
|
|
|
19
19
|
import { translationKey } from '#translations';
|
|
20
|
+
import { type FormFieldMap } from '#types';
|
|
20
21
|
|
|
21
22
|
import { getFormProperties } from '../../util';
|
|
22
|
-
import { Form, type
|
|
23
|
+
import { Form, type FormRootProps, SelectField, SelectOptionField } from '../Form';
|
|
23
24
|
|
|
24
|
-
export type FieldEditorProps = {
|
|
25
|
+
export type FieldEditorProps = Pick<FormRootProps<any>, 'readonly'> & {
|
|
25
26
|
projection: ProjectionModel;
|
|
26
27
|
field: View.FieldType;
|
|
27
28
|
registry?: Registry.Registry;
|
|
28
29
|
view?: Obj.Unknown;
|
|
29
30
|
onSave: () => void;
|
|
30
31
|
onCancel?: () => void;
|
|
31
|
-
}
|
|
32
|
+
};
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
|
-
* Displays a Form representing the metadata for a
|
|
35
|
+
* Displays a Form representing the metadata for a `Field` within a given `View`.
|
|
35
36
|
*/
|
|
36
37
|
export const FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCancel }: FieldEditorProps) => {
|
|
37
38
|
const { t } = useTranslation(translationKey);
|
|
@@ -57,7 +58,10 @@ export const FieldEditor = ({ readonly, projection, field, registry, view, onSav
|
|
|
57
58
|
|
|
58
59
|
const [referenceSchema, setReferenceSchema] = useState<Type.Type>();
|
|
59
60
|
useEffect(() => {
|
|
60
|
-
|
|
61
|
+
// A React state setter invokes a function argument as an updater. A class-based `Type.Type` is
|
|
62
|
+
// itself a function, so it must be stored via an updater lambda — passing it directly makes React
|
|
63
|
+
// call it as `Organization(prev)`, throwing "Class constructor … cannot be invoked without 'new'".
|
|
64
|
+
setReferenceSchema(() => schemas.find((schema) => Type.getTypename(schema) === props?.referenceSchema));
|
|
61
65
|
}, [schemas, props?.referenceSchema]);
|
|
62
66
|
|
|
63
67
|
// TODO(burdon): Need to wrap otherwise throws error:
|
|
@@ -190,7 +194,7 @@ export const FieldEditor = ({ readonly, projection, field, registry, view, onSav
|
|
|
190
194
|
readonly={readonly}
|
|
191
195
|
schema={fieldSchema}
|
|
192
196
|
values={props}
|
|
193
|
-
|
|
197
|
+
filter={propIsNotType}
|
|
194
198
|
sort={['property', 'format']}
|
|
195
199
|
onValuesChanged={handleValuesChanged}
|
|
196
200
|
onValidate={handleValidate}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `@dxos/react-ui-form` — Design
|
|
2
|
+
|
|
3
|
+
Schema-driven forms. Give `Form.Root` an Effect `schema` + `values`; the field set renders typed
|
|
4
|
+
controls automatically. Bespoke controls drop in via `Form.Row` or a per-path `fieldMap`.
|
|
5
|
+
|
|
6
|
+
## Component hierarchy
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
Form.Root context: schema, values, validation, onValuesChanged
|
|
10
|
+
└─ Form.Viewport scroll chrome
|
|
11
|
+
└─ Form.Content
|
|
12
|
+
├─ Form.Section titled group of fields
|
|
13
|
+
│ ├─ Form.FieldSet schema-driven field set
|
|
14
|
+
│ │ └─ FormFieldSetContainer group wrapper: FormFieldHeader (label + collapse) over the body
|
|
15
|
+
│ │ └─ FormField one per schema property; dispatches by type:
|
|
16
|
+
│ │ ├─ ArrayField array → FormFieldHeader + item rows
|
|
17
|
+
│ │ ├─ Form.FieldSet nested object → recurses (its own FormFieldSetContainer)
|
|
18
|
+
│ │ └─ Form.Row scalar → label + description + the control (<field>)
|
|
19
|
+
│ └─ Form.Row OR a hand-written row (label + description + any control)
|
|
20
|
+
├─ Form.Layout alternative to FieldSet: lays fields out per a parsed layout spec
|
|
21
|
+
└─ Form.Actions
|
|
22
|
+
└─ Form.Submit
|
|
23
|
+
Form.Error
|
|
24
|
+
```
|
|
@@ -3,80 +3,38 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
6
7
|
import * as Schema from 'effect/Schema';
|
|
7
|
-
import React, { useCallback, useState } from 'react';
|
|
8
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
+
import { Annotation, Filter, Format, Obj, Ref, Tag, Type } from '@dxos/echo';
|
|
10
11
|
import { type AnyProperties } from '@dxos/echo/internal';
|
|
11
12
|
import { log } from '@dxos/log';
|
|
12
|
-
import { useSpaces } from '@dxos/react-client/echo';
|
|
13
|
+
import { useQuery, useSpaces } from '@dxos/react-client/echo';
|
|
13
14
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
14
15
|
import { Tooltip } from '@dxos/react-ui';
|
|
15
16
|
import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
17
|
+
import { Text } from '@dxos/schema';
|
|
16
18
|
|
|
17
19
|
import { translations } from '#translations';
|
|
18
20
|
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
name: Schema.String.pipe(Schema.minLength(1)).annotations({ title: 'Full name' }),
|
|
24
|
-
}).pipe(Type.makeObject(DXN.make('com.example.type.organization', '0.1.0')));
|
|
25
|
-
|
|
26
|
-
export type Organization = Type.InstanceType<typeof Organization>;
|
|
27
|
-
|
|
28
|
-
const Person = Schema.Struct({
|
|
29
|
-
name: Schema.String.pipe(Schema.minLength(1)).annotations({ title: 'Full name' }),
|
|
30
|
-
ignore: Schema.String.pipe(Annotation.FormInputAnnotation.set(false), Schema.optional),
|
|
31
|
-
active: Schema.optional(Schema.Boolean.annotations({ title: 'Active' })),
|
|
32
|
-
address: Schema.optional(
|
|
33
|
-
Schema.Struct({
|
|
34
|
-
street: Schema.String,
|
|
35
|
-
city: Schema.String,
|
|
36
|
-
// TODO(burdon): Constrain input control.
|
|
37
|
-
state: Schema.String.pipe(Schema.minLength(2), Schema.maxLength(2)).annotations({
|
|
38
|
-
title: 'State',
|
|
39
|
-
description: 'State code',
|
|
40
|
-
}),
|
|
41
|
-
zip: Schema.Number.annotations({ title: 'ZIP Code' }),
|
|
42
|
-
}).annotations({ title: 'Address' }),
|
|
43
|
-
),
|
|
44
|
-
employer: Schema.optional(Ref.Ref(Organization).annotations({ title: 'Employer' })),
|
|
45
|
-
tags: Schema.optional(Schema.Array(Ref.Ref(Tag.Tag)).annotations({ title: 'Tags' })),
|
|
46
|
-
status: Schema.optional(Schema.Literal('active', 'inactive').annotations({ title: 'Status' })),
|
|
47
|
-
notes: Schema.optional(Format.Text.annotations({ title: 'Notes' })),
|
|
48
|
-
location: Schema.optional(Format.GeoPoint.annotations({ title: 'Location' })),
|
|
49
|
-
birthday: Schema.optional(Format.DateOnly.annotations({ title: 'Birthday' })),
|
|
50
|
-
meetingAt: Schema.optional(Format.DateTime.annotations({ title: 'Next meeting' })),
|
|
51
|
-
reminderAt: Schema.optional(Format.TimeOnly.annotations({ title: 'Reminder time' })),
|
|
52
|
-
tasks: Schema.optional(Schema.Array(Schema.String).annotations({ title: 'Tasks' })),
|
|
53
|
-
locations: Schema.optional(Schema.Array(Format.GeoPoint).annotations({ title: 'Locations' })),
|
|
54
|
-
identities: Schema.optional(
|
|
55
|
-
Schema.Array(
|
|
56
|
-
Schema.Struct({
|
|
57
|
-
type: Schema.String.annotations({ title: 'Type' }),
|
|
58
|
-
value: Schema.String.annotations({ title: 'Value' }),
|
|
59
|
-
}).annotations({ title: 'Identities' }),
|
|
60
|
-
).annotations({
|
|
61
|
-
title: 'Identities',
|
|
62
|
-
}),
|
|
63
|
-
),
|
|
64
|
-
}).pipe(Type.makeObject(DXN.make('org.dxos.type.person', '0.1.0')));
|
|
21
|
+
import { AutofillAnnotation, OptionsLookupAnnotation, autofill, optionsLookup } from '../../annotations';
|
|
22
|
+
import { Organization, Person, TestLayout } from '../../testing';
|
|
23
|
+
import { type ExcludeId, omitId } from '../../util';
|
|
24
|
+
import { Form, type FormRootProps } from './Form';
|
|
65
25
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
type DefaultStoryProps<T extends AnyProperties> = {
|
|
69
|
-
schema?: Schema.Schema<T>;
|
|
70
|
-
} & FormRootProps<T>;
|
|
26
|
+
type StoryArgs<T extends AnyProperties> = FormRootProps<T> & { json?: boolean };
|
|
71
27
|
|
|
72
28
|
const DefaultStory = <T extends AnyProperties = AnyProperties>({
|
|
73
29
|
schema,
|
|
74
30
|
values: valuesProp,
|
|
31
|
+
json = true,
|
|
75
32
|
...props
|
|
76
|
-
}:
|
|
33
|
+
}: StoryArgs<T>) => {
|
|
77
34
|
const [values, setValues] = useState<Partial<T>>(valuesProp ?? {});
|
|
78
35
|
const spaces = useSpaces();
|
|
79
36
|
const space = spaces[0];
|
|
37
|
+
|
|
80
38
|
const handleSave = useCallback<NonNullable<FormRootProps<T>['onSave']>>((values) => {
|
|
81
39
|
log.info('save', { values, meta });
|
|
82
40
|
setValues(values);
|
|
@@ -93,7 +51,7 @@ const DefaultStory = <T extends AnyProperties = AnyProperties>({
|
|
|
93
51
|
|
|
94
52
|
return (
|
|
95
53
|
<Tooltip.Provider>
|
|
96
|
-
<TestLayout json={{ values, schema: schema?.ast }}>
|
|
54
|
+
<TestLayout json={json ? { values, schema: schema?.ast } : undefined}>
|
|
97
55
|
<Form.Root
|
|
98
56
|
schema={schema}
|
|
99
57
|
defaultValues={values}
|
|
@@ -104,7 +62,7 @@ const DefaultStory = <T extends AnyProperties = AnyProperties>({
|
|
|
104
62
|
>
|
|
105
63
|
<Form.Viewport scroll>
|
|
106
64
|
<Form.Content>
|
|
107
|
-
<Form.Section
|
|
65
|
+
<Form.Section title='Section' description='This is a [section description](https://dxos.org).' />
|
|
108
66
|
<Form.FieldSet />
|
|
109
67
|
<Form.Actions />
|
|
110
68
|
</Form.Content>
|
|
@@ -125,11 +83,12 @@ const meta = {
|
|
|
125
83
|
withClientProvider({
|
|
126
84
|
createIdentity: true,
|
|
127
85
|
createSpace: true,
|
|
128
|
-
types: [Tag.Tag, Organization, Person],
|
|
86
|
+
types: [Tag.Tag, Organization, Person, Text.Text],
|
|
129
87
|
onCreateSpace: ({ space }) => {
|
|
130
88
|
[
|
|
131
89
|
...Array.from({ length: 3 }).map((_, i) => Obj.make(Tag.Tag, { label: `Tag ${i}` })),
|
|
132
90
|
...Array.from({ length: 50 }).map((_, i) => Obj.make(Organization, { name: `Organization ${i}` })),
|
|
91
|
+
Obj.make(Text.Text, { content: '# Brief\n\nEdit this **inline** markdown text.' }),
|
|
133
92
|
].map((obj) => space.db.add(obj));
|
|
134
93
|
},
|
|
135
94
|
}),
|
|
@@ -138,12 +97,10 @@ const meta = {
|
|
|
138
97
|
layout: 'fullscreen',
|
|
139
98
|
translations,
|
|
140
99
|
},
|
|
141
|
-
} satisfies Meta<
|
|
100
|
+
} satisfies Meta<StoryArgs<any>>;
|
|
142
101
|
|
|
143
102
|
export default meta;
|
|
144
103
|
|
|
145
|
-
type Story<T extends AnyProperties> = StoryObj<DefaultStoryProps<T>>;
|
|
146
|
-
|
|
147
104
|
const PersonSchema = Type.getSchema(Person);
|
|
148
105
|
|
|
149
106
|
const values: Partial<Person> = {
|
|
@@ -155,6 +112,8 @@ const values: Partial<Person> = {
|
|
|
155
112
|
reminderAt: '09:00:00',
|
|
156
113
|
};
|
|
157
114
|
|
|
115
|
+
type Story<T extends AnyProperties> = StoryObj<StoryArgs<T>>;
|
|
116
|
+
|
|
158
117
|
/**
|
|
159
118
|
* Build a data-entry surface by handing an Effect schema to `Form.Root` — the form derives its fields,
|
|
160
119
|
* types, validation, and selects from the schema, so you don't hand-wire one control per property.
|
|
@@ -192,6 +151,246 @@ export const Static: Story<ExcludeId<typeof PersonSchema>> = {
|
|
|
192
151
|
},
|
|
193
152
|
};
|
|
194
153
|
|
|
154
|
+
const SettingsSchema = Schema.mutable(
|
|
155
|
+
Schema.Struct({
|
|
156
|
+
viewMode: Schema.Literal('preview', 'readonly', 'source').annotations({
|
|
157
|
+
title: 'Default view mode',
|
|
158
|
+
description: 'Set whether documents open in editing or read-only mode.',
|
|
159
|
+
}),
|
|
160
|
+
toolbar: Schema.optional(
|
|
161
|
+
Schema.Boolean.annotations({
|
|
162
|
+
title: 'Show toolbar',
|
|
163
|
+
description: 'Display a formatting toolbar above the editor.',
|
|
164
|
+
}),
|
|
165
|
+
),
|
|
166
|
+
fontSize: Schema.optional(
|
|
167
|
+
Schema.Number.annotations({ title: 'Font size', description: 'Editor font size, in pixels.' }),
|
|
168
|
+
),
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
export const Variants: Story<Schema.Schema.Type<typeof SettingsSchema>> = {
|
|
173
|
+
render: (args) => (
|
|
174
|
+
<div className='grid grid-cols-2 w-full'>
|
|
175
|
+
<DefaultStory {...args} />
|
|
176
|
+
<DefaultStory {...args} variant='settings' />
|
|
177
|
+
</div>
|
|
178
|
+
),
|
|
179
|
+
args: {
|
|
180
|
+
json: false,
|
|
181
|
+
schema: SettingsSchema,
|
|
182
|
+
values: {
|
|
183
|
+
viewMode: 'preview',
|
|
184
|
+
toolbar: true,
|
|
185
|
+
fontSize: 14,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const InlineMarkdownTextSchema = Schema.mutable(
|
|
191
|
+
Schema.Struct({
|
|
192
|
+
text: Schema.String,
|
|
193
|
+
instructions: Ref.Ref(Text.Text).pipe(
|
|
194
|
+
Format.FormatAnnotation.set(Format.TypeFormat.Markdown),
|
|
195
|
+
Annotation.FormInlineAnnotation.set(true),
|
|
196
|
+
Schema.annotations({
|
|
197
|
+
title: 'Instructions',
|
|
198
|
+
description: 'Ref to a Text object with both markdown and inline-ref annotations.',
|
|
199
|
+
}),
|
|
200
|
+
),
|
|
201
|
+
}),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const InlineMarkdownTextStory = (args: StoryArgs<any>) => {
|
|
205
|
+
const spaces = useSpaces();
|
|
206
|
+
const space = spaces[0];
|
|
207
|
+
const [text] = useQuery(space?.db, Filter.type(Text.Text));
|
|
208
|
+
const values = useMemo(() => (text ? { instructions: Ref.make(text) } : undefined), [text]);
|
|
209
|
+
|
|
210
|
+
if (!space || !values) {
|
|
211
|
+
return <Loading />;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<DefaultStory
|
|
216
|
+
{...args}
|
|
217
|
+
schema={InlineMarkdownTextSchema}
|
|
218
|
+
values={values}
|
|
219
|
+
onCreate={(_type, props) => space.db.add(Obj.make(Text.Text, { content: '', ...props }))}
|
|
220
|
+
/>
|
|
221
|
+
);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Exercises a `Ref<Text>` field carrying both `Format.TypeFormat.Markdown` and
|
|
226
|
+
* `FormInlineAnnotation` — the markdown editor should render inline rather than
|
|
227
|
+
* opening a ref picker or nested struct form.
|
|
228
|
+
*/
|
|
229
|
+
export const InlineMarkdownText: Story<any> = {
|
|
230
|
+
render: (args) => <InlineMarkdownTextStory {...args} />,
|
|
231
|
+
args: {
|
|
232
|
+
autoSave: true,
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
195
236
|
export const Empty: Story<ExcludeId<typeof PersonSchema>> = {
|
|
196
237
|
args: {},
|
|
197
238
|
};
|
|
239
|
+
|
|
240
|
+
// Demonstrates the value-driven dynamic-field annotations (here backed by in-memory Effects with an
|
|
241
|
+
// artificial delay rather than network calls, so the story is deterministic): a select whose options
|
|
242
|
+
// derive from the `query` field, and a text field auto-filled from the `url` field. Each annotation
|
|
243
|
+
// declares the fields it depends on, so it only re-runs when one of those changes. Structural validation
|
|
244
|
+
// is the schema's own job (`Format.URL`).
|
|
245
|
+
const isValidUrl = Schema.is(Format.URL);
|
|
246
|
+
|
|
247
|
+
// Base struct (no dynamic annotations) — its value type drives the typed `deps`/`values` below.
|
|
248
|
+
const DynamicFieldsBase = Schema.Struct({
|
|
249
|
+
query: Schema.String.annotations({ title: 'Query', description: 'Type to load the choices below.' }),
|
|
250
|
+
choice: Schema.optional(Schema.String),
|
|
251
|
+
tag: Schema.optional(Schema.String),
|
|
252
|
+
url: Format.URL.annotations({ title: 'URL', description: 'A valid URL auto-fills the name below.' }),
|
|
253
|
+
name: Schema.optional(Schema.String),
|
|
254
|
+
});
|
|
255
|
+
type DynamicFieldsValues = Schema.Schema.Type<typeof DynamicFieldsBase>;
|
|
256
|
+
|
|
257
|
+
const TAG_VOCABULARY = ['react', 'effect', 'schema', 'echo', 'composer'];
|
|
258
|
+
|
|
259
|
+
const DynamicFieldsSchema = Schema.mutable(
|
|
260
|
+
Schema.Struct({
|
|
261
|
+
...DynamicFieldsBase.fields,
|
|
262
|
+
choice: Schema.optional(
|
|
263
|
+
Schema.String.pipe(
|
|
264
|
+
OptionsLookupAnnotation.set(
|
|
265
|
+
optionsLookup<DynamicFieldsValues>()(['query'], ({ query }) =>
|
|
266
|
+
(query && query.length > 0
|
|
267
|
+
? Effect.succeed(
|
|
268
|
+
[1, 2, 3].map((index) => ({ value: `${query}-${index}`, label: `${query} choice ${index}` })),
|
|
269
|
+
)
|
|
270
|
+
: Effect.succeed([])
|
|
271
|
+
).pipe(Effect.delay('600 millis')),
|
|
272
|
+
),
|
|
273
|
+
),
|
|
274
|
+
Schema.annotations({ title: 'Choice', description: 'Options load from the query (after a delay).' }),
|
|
275
|
+
),
|
|
276
|
+
),
|
|
277
|
+
// Combobox: the field's own value is the query; the typed text is the auto-selected first option.
|
|
278
|
+
tag: Schema.optional(
|
|
279
|
+
Schema.String.pipe(
|
|
280
|
+
OptionsLookupAnnotation.set(
|
|
281
|
+
optionsLookup<DynamicFieldsValues>()(
|
|
282
|
+
// No deps: the pool is fetched once; the combobox filters it by the typed text client-side.
|
|
283
|
+
[],
|
|
284
|
+
() =>
|
|
285
|
+
Effect.succeed(TAG_VOCABULARY.map((value) => ({ value, label: value }))).pipe(Effect.delay('400 millis')),
|
|
286
|
+
{ combobox: true },
|
|
287
|
+
),
|
|
288
|
+
),
|
|
289
|
+
Schema.annotations({ title: 'Tag', description: 'Combobox: type to filter; your text stays selectable.' }),
|
|
290
|
+
),
|
|
291
|
+
),
|
|
292
|
+
name: Schema.optional(
|
|
293
|
+
Schema.String.pipe(
|
|
294
|
+
// Only derive a value once the URL is structurally valid, and only after the artificial wait —
|
|
295
|
+
// an incomplete/invalid URL produces nothing.
|
|
296
|
+
AutofillAnnotation.set(
|
|
297
|
+
autofill<DynamicFieldsValues>()(['url'], ({ url }) =>
|
|
298
|
+
isValidUrl(url)
|
|
299
|
+
? Effect.succeed(`Feed for ${url}`).pipe(Effect.delay('800 millis'))
|
|
300
|
+
: Effect.succeed(undefined),
|
|
301
|
+
),
|
|
302
|
+
),
|
|
303
|
+
Schema.annotations({ title: 'Name', description: 'Auto-filled from a valid URL (editable).' }),
|
|
304
|
+
),
|
|
305
|
+
),
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Exercises the dynamic-field annotations: `OptionsLookupAnnotation` (select options loaded from a
|
|
311
|
+
* sibling) and `AutofillAnnotation` (value derived from a sibling, gated on validity and delayed). Each
|
|
312
|
+
* runs a self-contained Effect from the current form values.
|
|
313
|
+
*/
|
|
314
|
+
export const DynamicFields: Story<Schema.Schema.Type<typeof DynamicFieldsSchema>> = {
|
|
315
|
+
args: {
|
|
316
|
+
json: true,
|
|
317
|
+
schema: DynamicFieldsSchema,
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// Discriminated-union create form mirroring the magazine create-feed schema: a `type` selector picks the
|
|
322
|
+
// member, whose fields then render — `standard-site` (handle combobox → publication select) or `rss`
|
|
323
|
+
// (URL → auto-filled name). Backed by in-memory Effects so the story is deterministic. Regression harness
|
|
324
|
+
// for union create forms (e.g. the `omitId` union-flattening bug).
|
|
325
|
+
const HANDLE_SUGGESTIONS = ['dxos.org', 'alice.bsky.social', 'bob.example.com'];
|
|
326
|
+
|
|
327
|
+
const StandardSiteCreateBase = Schema.Struct({
|
|
328
|
+
type: Schema.Literal('standard-site'),
|
|
329
|
+
handle: Schema.String.annotations({ title: 'Handle', description: 'atproto handle, e.g. dxos.org.' }),
|
|
330
|
+
// No `name`: the feed name is taken from the selected publication.
|
|
331
|
+
publication: Schema.String.annotations({ title: 'Publication', description: 'Choose a publication.' }),
|
|
332
|
+
});
|
|
333
|
+
type StandardSiteValues = Schema.Schema.Type<typeof StandardSiteCreateBase>;
|
|
334
|
+
|
|
335
|
+
const StandardSiteCreate = Schema.Struct({
|
|
336
|
+
...StandardSiteCreateBase.fields,
|
|
337
|
+
handle: StandardSiteCreateBase.fields.handle.pipe(
|
|
338
|
+
OptionsLookupAnnotation.set(
|
|
339
|
+
optionsLookup<StandardSiteValues>()(
|
|
340
|
+
['handle'],
|
|
341
|
+
() =>
|
|
342
|
+
Effect.succeed(HANDLE_SUGGESTIONS.map((value) => ({ value, label: value }))).pipe(Effect.delay('300 millis')),
|
|
343
|
+
{ combobox: true },
|
|
344
|
+
),
|
|
345
|
+
),
|
|
346
|
+
),
|
|
347
|
+
publication: StandardSiteCreateBase.fields.publication.pipe(
|
|
348
|
+
OptionsLookupAnnotation.set(
|
|
349
|
+
optionsLookup<StandardSiteValues>()(['handle'], ({ handle }) =>
|
|
350
|
+
Effect.succeed(
|
|
351
|
+
handle
|
|
352
|
+
? [
|
|
353
|
+
{ value: `at://${handle}/pub/blog`, label: `${handle} — Blog` },
|
|
354
|
+
{ value: `at://${handle}/pub/notes`, label: `${handle} — Notes` },
|
|
355
|
+
]
|
|
356
|
+
: [],
|
|
357
|
+
).pipe(Effect.delay('300 millis')),
|
|
358
|
+
),
|
|
359
|
+
),
|
|
360
|
+
),
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
const RssCreateBase = Schema.Struct({
|
|
364
|
+
type: Schema.Literal('rss'),
|
|
365
|
+
url: Format.URL.annotations({ title: 'URL', description: 'RSS feed URL.' }),
|
|
366
|
+
name: Schema.optional(Schema.String.annotations({ title: 'Name' })),
|
|
367
|
+
});
|
|
368
|
+
type RssValues = Schema.Schema.Type<typeof RssCreateBase>;
|
|
369
|
+
|
|
370
|
+
const RssCreate = Schema.Struct({
|
|
371
|
+
...RssCreateBase.fields,
|
|
372
|
+
name: Schema.optional(
|
|
373
|
+
Schema.String.pipe(
|
|
374
|
+
AutofillAnnotation.set(
|
|
375
|
+
autofill<RssValues>()(['url'], ({ url }) =>
|
|
376
|
+
isValidUrl(url)
|
|
377
|
+
? Effect.succeed(`Feed for ${url}`).pipe(Effect.delay('500 millis'))
|
|
378
|
+
: Effect.succeed(undefined),
|
|
379
|
+
),
|
|
380
|
+
),
|
|
381
|
+
).annotations({ title: 'Name' }),
|
|
382
|
+
),
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const CreateFeedSchema = Schema.Union(StandardSiteCreate, RssCreate);
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* A discriminated-union create form: selecting `type` reveals that member's fields (combobox + select for
|
|
389
|
+
* `standard-site`, URL + autofill for `rss`). Mirrors the magazine create-feed schema.
|
|
390
|
+
*/
|
|
391
|
+
export const DiscriminatedUnion: Story<Schema.Schema.Type<typeof CreateFeedSchema>> = {
|
|
392
|
+
args: {
|
|
393
|
+
json: true,
|
|
394
|
+
schema: CreateFeedSchema,
|
|
395
|
+
},
|
|
396
|
+
};
|