@dxos/react-ui-form 0.9.1-main.c7dcc2e112 → 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 +1883 -1539
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1883 -1539
- 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.map +1 -1
- package/dist/types/src/components/Form/Form.d.ts +12 -4
- package/dist/types/src/components/Form/Form.d.ts.map +1 -1
- package/dist/types/src/components/Form/Form.stories.d.ts +46 -65
- 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 +17 -8
- package/dist/types/src/components/Form/FormControls.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/FormField.d.ts +16 -2
- package/dist/types/src/components/Form/FormField/FormField.d.ts.map +1 -1
- 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/FormField/{FormFieldWrapper.stories.d.ts → FormRow.stories.d.ts} +4 -1
- package/dist/types/src/components/Form/FormField/FormRow.stories.d.ts.map +1 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts +1 -0
- package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts.map +1 -1
- 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.map +1 -1
- 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/GeoPointField/GeoPointField.d.ts +1 -1
- package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.d.ts +1 -1
- package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts +11 -0
- package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts.map +1 -1
- 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/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/{Settings/Settings.stories.d.ts → Form/FormField/fields/PasswordField/PasswordField.stories.d.ts} +1 -2
- 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 -1
- package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts +18 -2
- package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/fields/index.d.ts +4 -0
- package/dist/types/src/components/Form/FormField/fields/index.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormField/index.d.ts +4 -3
- package/dist/types/src/components/Form/FormField/index.d.ts.map +1 -1
- 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 +8 -5
- package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts.map +1 -1
- 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 +1 -0
- package/dist/types/src/components/Form/FormFieldSet/index.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormLayout/FormLayout.d.ts +2 -0
- package/dist/types/src/components/Form/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormLayout/FormLayout.stories.d.ts +5 -5
- package/dist/types/src/components/Form/FormLayout/FormLayout.stories.d.ts.map +1 -1
- package/dist/types/src/components/Form/FormLayout/index.d.ts +1 -1
- package/dist/types/src/components/Form/FormLayout/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/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.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 +1 -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 +8 -3
- package/dist/types/src/hooks/useFormContext.d.ts.map +1 -1
- package/dist/types/src/hooks/useFormHandler.d.ts +8 -2
- package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/TestLayout.d.ts +1 -1
- package/dist/types/src/testing/TestLayout.d.ts.map +1 -1
- package/dist/types/src/testing/schema.d.ts +13 -16
- package/dist/types/src/testing/schema.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +50 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +0 -1
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/omit.d.ts +1 -1
- package/dist/types/src/util/omit.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -40
- package/src/annotations.ts +63 -0
- package/src/components/FieldEditor/FieldEditor.tsx +5 -2
- package/src/components/Form/DESIGN.md +24 -0
- package/src/components/Form/Form.stories.tsx +257 -13
- 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 +15 -9
- package/src/components/Form/FormControls.tsx +94 -37
- package/src/components/Form/FormField/FormField.tsx +83 -32
- package/src/components/Form/FormField/FormFieldHeader.tsx +68 -0
- package/src/components/Form/FormField/{FormFieldWrapper.stories.tsx → FormRow.stories.tsx} +34 -9
- package/src/components/Form/FormField/FormRow.tsx +298 -0
- package/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.tsx +25 -9
- package/src/components/Form/FormField/fields/ArrayField/ArrayField.tsx +83 -24
- 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.tsx +5 -6
- 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.tsx +9 -9
- package/src/components/Form/FormField/fields/GeoPointField/GeoPointField.tsx +17 -20
- package/src/components/Form/FormField/fields/MarkdownField/MarkdownField.stories.tsx +2 -2
- package/src/components/Form/FormField/fields/MarkdownField/MarkdownField.tsx +39 -40
- package/src/components/Form/FormField/fields/NumberField/NumberField.test.ts +29 -0
- package/src/components/Form/FormField/fields/NumberField/NumberField.tsx +60 -21
- 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/FormField/fields/RefField/InlineRefField.tsx +16 -10
- package/src/components/Form/FormField/fields/RefField/RefField.test.ts +8 -0
- package/src/components/Form/FormField/fields/RefField/RefField.tsx +50 -23
- package/src/components/Form/FormField/fields/SelectField/SelectField.tsx +104 -47
- package/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.tsx +3 -3
- package/src/components/Form/FormField/fields/TextAreaField/TextAreaField.tsx +3 -3
- package/src/components/Form/FormField/fields/TextField/TextField.tsx +3 -3
- package/src/components/Form/FormField/fields/TupleField/TupleField.tsx +1 -1
- package/src/components/Form/FormField/fields/index.ts +4 -0
- package/src/components/Form/FormField/index.ts +5 -3
- package/src/components/Form/FormField/presentation.tsx +32 -0
- package/src/components/Form/FormFieldSet/FormFieldSet.tsx +49 -70
- package/src/components/Form/FormFieldSet/FormFieldSetContainer.tsx +93 -0
- package/src/components/Form/FormFieldSet/index.ts +1 -0
- package/src/components/Form/FormLayout/FormLayout.stories.tsx +7 -5
- package/src/components/Form/FormLayout/FormLayout.tsx +24 -14
- package/src/components/Form/FormLayout/index.ts +1 -1
- package/src/components/Form/meta-tags.test.ts +1 -1
- package/src/components/ObjectForm/ObjectForm.tsx +2 -2
- package/src/components/ObjectPicker/ObjectPicker.tsx +1 -0
- package/src/components/ObjectProperties/ObjectProperties.stories.tsx +1 -1
- package/src/components/ObjectProperties/ObjectProperties.tsx +12 -8
- package/src/components/RefEditor/RefEditor.stories.tsx +2 -2
- package/src/components/RefEditor/RefEditor.tsx +1 -1
- package/src/components/ViewEditor/ViewEditor.stories.tsx +2 -2
- package/src/components/ViewEditor/ViewEditor.test.tsx +8 -2
- package/src/components/ViewEditor/ViewEditor.tsx +3 -3
- package/src/components/index.ts +0 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useAsyncFieldEffect.ts +81 -0
- package/src/hooks/useFormContext.ts +6 -3
- package/src/hooks/useFormHandler.ts +11 -6
- package/src/index.ts +1 -0
- package/src/testing/TestLayout.tsx +15 -12
- package/src/testing/schema.ts +43 -43
- package/src/types.ts +53 -1
- package/src/util/index.ts +0 -1
- package/src/util/omit.ts +25 -11
- package/src/util/properties.test.ts +110 -28
- package/src/util/refs.ts +1 -1
- package/dist/types/src/components/Form/FormField/FieldHeader.d.ts +0 -19
- package/dist/types/src/components/Form/FormField/FieldHeader.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormField/FormFieldWrapper.d.ts +0 -47
- package/dist/types/src/components/Form/FormField/FormFieldWrapper.d.ts.map +0 -1
- package/dist/types/src/components/Form/FormField/FormFieldWrapper.stories.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/util/field-type.d.ts +0 -19
- package/dist/types/src/util/field-type.d.ts.map +0 -1
- package/src/components/Form/FormField/FieldHeader.tsx +0 -36
- package/src/components/Form/FormField/FormFieldWrapper.tsx +0 -179
- 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
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type VariantProps, mx, tv } from '@dxos/ui-theme';
|
|
6
|
+
|
|
7
|
+
/** Visual variants for {@link Form}. `settings` is the bordered two-column settings-panel look. */
|
|
8
|
+
export type FormVariant = NonNullable<VariantProps<typeof formStyles>['variant']>;
|
|
9
|
+
|
|
10
|
+
/** Non-className behavior flags, keyed by {@link FormVariant}. */
|
|
11
|
+
export type FormBehavior = { showDescription: boolean };
|
|
12
|
+
|
|
13
|
+
const formStyles = tv({
|
|
14
|
+
slots: {
|
|
15
|
+
viewport: '',
|
|
16
|
+
content: '',
|
|
17
|
+
section: 'flex flex-col py-form-section-gap first:pt-0',
|
|
18
|
+
group: 'flex flex-col gap-3 p-trim-md border border-separator rounded-sm',
|
|
19
|
+
sectionHeader: '',
|
|
20
|
+
sectionTitle: 'text-lg',
|
|
21
|
+
sectionDescription: 'text-description',
|
|
22
|
+
fieldSet: '',
|
|
23
|
+
field: '',
|
|
24
|
+
fieldLabel: 'h-8 grid grid-cols-[1fr_auto_auto] items-center select-none',
|
|
25
|
+
fieldLabelText: '',
|
|
26
|
+
fieldDescription: 'text-description',
|
|
27
|
+
fieldControl: '',
|
|
28
|
+
fieldValidation: '',
|
|
29
|
+
// Action bar (cancel/save), equal-width columns flowing horizontally.
|
|
30
|
+
actions: 'grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding',
|
|
31
|
+
// Standalone submit row (full-width primary button).
|
|
32
|
+
submit: 'flex w-full pt-form-padding',
|
|
33
|
+
// Collapsible field-set body: indented column of sub-fields.
|
|
34
|
+
fieldSetBody: 'flex flex-col gap-2 px-2 pb-2',
|
|
35
|
+
// Bordered container wrapping a collapsible nested group, plus its top spacing.
|
|
36
|
+
fieldSetBox: 'border border-subdued-separator rounded-sm',
|
|
37
|
+
fieldSetBoxOuter: 'pt-trim-md',
|
|
38
|
+
},
|
|
39
|
+
variants: {
|
|
40
|
+
variant: {
|
|
41
|
+
default: {},
|
|
42
|
+
settings: {
|
|
43
|
+
content: 'dx-document',
|
|
44
|
+
// Gap on the section spaces its direct children — section title/description and, for action
|
|
45
|
+
// panels, the `Form.Row`s placed directly in the section (which have no `fieldSet` wrapper).
|
|
46
|
+
section: 'py-form-section-gap! gap-trim-md',
|
|
47
|
+
sectionHeader: 'pb-form-section-gap',
|
|
48
|
+
sectionTitle: 'px-trim-md text-xl',
|
|
49
|
+
sectionDescription: 'px-trim-md',
|
|
50
|
+
// No top padding: the section gap already separates the field set from the title above it.
|
|
51
|
+
fieldSet: 'flex flex-col gap-trim-md',
|
|
52
|
+
field: mx(
|
|
53
|
+
'grid',
|
|
54
|
+
'grid-cols-1 [grid-template-areas:"header""description""control""validation"]',
|
|
55
|
+
'md:grid-cols-2 md:[grid-template-areas:"header_header""description_control""validation_validation"]',
|
|
56
|
+
'gap-x-trim-lg gap-y-0 p-trim-md border border-input-separator rounded-md',
|
|
57
|
+
),
|
|
58
|
+
fieldLabel: '[grid-area:header]',
|
|
59
|
+
fieldLabelText: 'text-base-fg text-lg',
|
|
60
|
+
fieldDescription: '[grid-area:description] pt-1 text-description',
|
|
61
|
+
fieldControl: '[grid-area:control] flex justify-end items-start md:text-right pt-3 md:pt-0',
|
|
62
|
+
fieldValidation: '[grid-area:validation]',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
defaultVariants: {
|
|
67
|
+
variant: 'default',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
/** {@link Form} theme template: a tailwind-variants recipe (`styles`) plus non-class `behavior`. */
|
|
72
|
+
export const formTheme = {
|
|
73
|
+
styles: formStyles,
|
|
74
|
+
behavior: {
|
|
75
|
+
default: {
|
|
76
|
+
showDescription: false,
|
|
77
|
+
},
|
|
78
|
+
settings: {
|
|
79
|
+
showDescription: true,
|
|
80
|
+
},
|
|
81
|
+
} satisfies Record<FormVariant, FormBehavior>,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/** Slot names of {@link formTheme.styles}, for `bridgeTv` registration. */
|
|
85
|
+
// Object.keys widens to string[]; the slot names are statically known.
|
|
86
|
+
export const formSlots = Object.keys(formTheme.styles()) as Array<keyof ReturnType<typeof formTheme.styles>>;
|
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
FormContent,
|
|
9
9
|
type FormContentProps,
|
|
10
10
|
FormError,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
FormFieldSetController,
|
|
12
|
+
FormGroup,
|
|
13
|
+
type FormGroupProps,
|
|
14
|
+
FormLayoutController,
|
|
13
15
|
type FormLayoutProps,
|
|
14
16
|
FormRoot,
|
|
15
17
|
type FormRootProps,
|
|
@@ -20,27 +22,31 @@ import {
|
|
|
20
22
|
FormViewport,
|
|
21
23
|
type FormViewportProps,
|
|
22
24
|
} from './FormControls';
|
|
23
|
-
import { FormFieldLabel } from './FormField';
|
|
25
|
+
import { FormFieldLabel, FormRow, type FormRowProps } from './FormField';
|
|
24
26
|
|
|
25
27
|
export const Form = {
|
|
26
28
|
Root: FormRoot,
|
|
27
29
|
Viewport: FormViewport,
|
|
28
30
|
Content: FormContent,
|
|
29
31
|
Section: FormSection,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
Group: FormGroup,
|
|
33
|
+
FieldSet: FormFieldSetController,
|
|
34
|
+
Layout: FormLayoutController,
|
|
32
35
|
Label: FormFieldLabel,
|
|
36
|
+
Row: FormRow,
|
|
33
37
|
Actions: FormActions,
|
|
34
38
|
Submit: FormSubmit,
|
|
35
39
|
Error: FormError,
|
|
36
40
|
};
|
|
37
41
|
|
|
38
42
|
export type {
|
|
39
|
-
|
|
40
|
-
FormViewportProps,
|
|
43
|
+
FormActionsProps,
|
|
41
44
|
FormContentProps,
|
|
42
|
-
|
|
45
|
+
FormGroupProps,
|
|
43
46
|
FormLayoutProps,
|
|
44
|
-
|
|
47
|
+
FormRootProps,
|
|
48
|
+
FormRowProps,
|
|
49
|
+
FormSectionProps,
|
|
45
50
|
FormSubmitProps,
|
|
51
|
+
FormViewportProps,
|
|
46
52
|
};
|
|
@@ -19,7 +19,9 @@ import {
|
|
|
19
19
|
useTranslation,
|
|
20
20
|
withColumn,
|
|
21
21
|
} from '@dxos/react-ui';
|
|
22
|
+
import { MarkdownView } from '@dxos/react-ui-markdown';
|
|
22
23
|
import { mx } from '@dxos/ui-theme';
|
|
24
|
+
import { type Merge } from '@dxos/util';
|
|
23
25
|
|
|
24
26
|
import { translationKey } from '#translations';
|
|
25
27
|
|
|
@@ -32,18 +34,16 @@ import {
|
|
|
32
34
|
useFormHandler,
|
|
33
35
|
useKeyHandler,
|
|
34
36
|
} from '../../hooks';
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from './FormFieldSet';
|
|
39
|
-
import { FormLayout as NaturalFormLayout, type FormLayoutProps as NaturalFormLayoutProps } from './FormLayout';
|
|
37
|
+
import { formTheme } from './Form.theme';
|
|
38
|
+
import { FormFieldSet, type FormFieldSetProps as NaturalFormFieldSetProps } from './FormFieldSet';
|
|
39
|
+
import { FormLayout, type FormLayoutProps as NaturalFormLayoutProps } from './FormLayout';
|
|
40
40
|
|
|
41
41
|
//
|
|
42
42
|
// Root
|
|
43
43
|
//
|
|
44
44
|
|
|
45
|
-
export type FormRootProps<T extends AnyProperties = AnyProperties> =
|
|
46
|
-
{
|
|
45
|
+
export type FormRootProps<T extends AnyProperties = AnyProperties> = Merge<
|
|
46
|
+
PropsWithChildren<{
|
|
47
47
|
/**
|
|
48
48
|
* Called when the form is submitted and passes validation.
|
|
49
49
|
*/
|
|
@@ -53,11 +53,13 @@ export type FormRootProps<T extends AnyProperties = AnyProperties> = PropsWithCh
|
|
|
53
53
|
* Called when the form is canceled to abandon/undo any pending changes.
|
|
54
54
|
*/
|
|
55
55
|
onCancel?: () => void;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
}>,
|
|
57
|
+
Omit<FormContextValue<T>, 'form'>,
|
|
58
|
+
Pick<FormHandlerProps<T>, 'schema' | 'autoSave' | 'values' | 'defaultValues' | 'onValidate' | 'onValuesChanged'>,
|
|
59
|
+
Omit<NaturalFormFieldSetProps<T>, 'schema' | 'path'>
|
|
59
60
|
>;
|
|
60
61
|
|
|
62
|
+
// `variant` (from FormContextValue) flows through `...props` into the context for all parts to read.
|
|
61
63
|
export const FormRoot = <T extends AnyProperties = AnyProperties>({
|
|
62
64
|
children,
|
|
63
65
|
schema,
|
|
@@ -83,19 +85,31 @@ FormRoot.displayName = 'Form.Root';
|
|
|
83
85
|
|
|
84
86
|
const FORM_VIEWPORT_NAME = 'Form.Viewport';
|
|
85
87
|
|
|
86
|
-
export type FormViewportProps = {
|
|
88
|
+
export type FormViewportProps = {
|
|
89
|
+
scroll?: boolean;
|
|
90
|
+
gutter?: ColumnRootProps['gutter'];
|
|
91
|
+
};
|
|
87
92
|
|
|
88
93
|
// The viewing window: owns the gutter Column (chrome/side-padding).
|
|
89
94
|
// Content-height by default; `scroll` makes it fill its parent and scroll (the gutter then hosts the scrollbar).
|
|
90
95
|
export const FormViewport = composable<HTMLDivElement, FormViewportProps>(
|
|
91
|
-
({ children, scroll, gutter = '
|
|
96
|
+
({ children, scroll, gutter = 'sm', ...props }, forwardedRef) => {
|
|
97
|
+
const { variant = 'default' } = useFormContext(FORM_VIEWPORT_NAME);
|
|
98
|
+
const styles = formTheme.styles({ variant });
|
|
92
99
|
// Span the full width when nested inside another Column grid (e.g. Card.Root)
|
|
93
100
|
// instead of landing in a single narrow track.
|
|
94
101
|
const span = '[.dx-column-root_&]:col-span-full';
|
|
95
102
|
if (scroll) {
|
|
96
103
|
return (
|
|
97
104
|
<Column.Root gutter={gutter} classNames={['dx-expander', span]}>
|
|
98
|
-
<ScrollArea.Root
|
|
105
|
+
<ScrollArea.Root
|
|
106
|
+
{...composableProps(props, { classNames: styles.viewport() })}
|
|
107
|
+
orientation='vertical'
|
|
108
|
+
centered
|
|
109
|
+
padding
|
|
110
|
+
thin
|
|
111
|
+
ref={forwardedRef}
|
|
112
|
+
>
|
|
99
113
|
<ScrollArea.Viewport>{children}</ScrollArea.Viewport>
|
|
100
114
|
</ScrollArea.Root>
|
|
101
115
|
</Column.Root>
|
|
@@ -103,7 +117,11 @@ export const FormViewport = composable<HTMLDivElement, FormViewportProps>(
|
|
|
103
117
|
}
|
|
104
118
|
|
|
105
119
|
return (
|
|
106
|
-
<Column.Root
|
|
120
|
+
<Column.Root
|
|
121
|
+
{...composableProps(props, { classNames: ['w-full min-w-0', span, styles.viewport()] })}
|
|
122
|
+
gutter={gutter}
|
|
123
|
+
ref={forwardedRef}
|
|
124
|
+
>
|
|
107
125
|
{children}
|
|
108
126
|
</Column.Root>
|
|
109
127
|
);
|
|
@@ -122,7 +140,8 @@ export type FormContentProps = ThemedClassName<PropsWithChildren<{}>>;
|
|
|
122
140
|
|
|
123
141
|
// The viewed body: centered in the viewport's gutter. Pure body — the gutter Column is owned by `Form.Viewport`.
|
|
124
142
|
export const FormContent = composable<HTMLDivElement, FormContentProps>(({ children, ...props }, forwardedRef) => {
|
|
125
|
-
const { form, testId } = useFormContext(FORM_CONTENT_NAME);
|
|
143
|
+
const { form, testId, variant = 'default' } = useFormContext(FORM_CONTENT_NAME);
|
|
144
|
+
const styles = formTheme.styles({ variant });
|
|
126
145
|
const localRef = useRef<HTMLDivElement>(null);
|
|
127
146
|
const mergedRef = useMergeRefs([forwardedRef, localRef]);
|
|
128
147
|
useKeyHandler(localRef, form);
|
|
@@ -131,7 +150,7 @@ export const FormContent = composable<HTMLDivElement, FormContentProps>(({ child
|
|
|
131
150
|
<div
|
|
132
151
|
{...composableProps(props, {
|
|
133
152
|
role: 'form',
|
|
134
|
-
classNames: mx(withColumn.center(), 'flex flex-col w-full'),
|
|
153
|
+
classNames: mx(withColumn.center(), 'flex flex-col w-full dx-document', styles.content()),
|
|
135
154
|
})}
|
|
136
155
|
data-testid={testId}
|
|
137
156
|
ref={mergedRef}
|
|
@@ -149,15 +168,23 @@ FormContent.displayName = FORM_CONTENT_NAME;
|
|
|
149
168
|
|
|
150
169
|
const FORM_FIELDSET_NAME = 'Form.FieldSet';
|
|
151
170
|
|
|
152
|
-
export type
|
|
153
|
-
|
|
154
|
-
export const FormFieldSet = (props: FormFieldSetProps) => {
|
|
155
|
-
const { form, ...contextProps } = useFormContext(FORM_FIELDSET_NAME);
|
|
171
|
+
export type FormFieldSetControllerProps = ThemedClassName<NaturalFormFieldSetProps<any>>;
|
|
156
172
|
|
|
157
|
-
|
|
173
|
+
/** Context-reading binding for `Form.FieldSet`: pulls the schema + field context off the form and delegates to {@link FormFieldSet}. */
|
|
174
|
+
export const FormFieldSetController = ({ classNames, ...props }: FormFieldSetControllerProps) => {
|
|
175
|
+
const { form, variant = 'default', ...contextProps } = useFormContext(FORM_FIELDSET_NAME);
|
|
176
|
+
const styles = formTheme.styles({ variant });
|
|
177
|
+
return (
|
|
178
|
+
<FormFieldSet
|
|
179
|
+
schema={form.schema}
|
|
180
|
+
classNames={styles.fieldSet({ class: classNames })}
|
|
181
|
+
{...contextProps}
|
|
182
|
+
{...props}
|
|
183
|
+
/>
|
|
184
|
+
);
|
|
158
185
|
};
|
|
159
186
|
|
|
160
|
-
|
|
187
|
+
FormFieldSetController.displayName = FORM_FIELDSET_NAME;
|
|
161
188
|
|
|
162
189
|
//
|
|
163
190
|
// Layout
|
|
@@ -167,17 +194,18 @@ const FORM_LAYOUT_NAME = 'Form.Layout';
|
|
|
167
194
|
|
|
168
195
|
export type FormLayoutProps = Omit<NaturalFormLayoutProps, 'schema'> & { schema?: NaturalFormLayoutProps['schema'] };
|
|
169
196
|
|
|
170
|
-
|
|
197
|
+
/** Context-reading binding for `Form.Layout`: resolves the schema (prop or form) and delegates to {@link FormLayout}. */
|
|
198
|
+
export const FormLayoutController = ({ schema, ...props }: FormLayoutProps) => {
|
|
171
199
|
const { form, ...contextProps } = useFormContext(FORM_LAYOUT_NAME);
|
|
172
200
|
const resolvedSchema = schema ?? form.schema;
|
|
173
201
|
if (!resolvedSchema) {
|
|
174
202
|
return null;
|
|
175
203
|
}
|
|
176
204
|
|
|
177
|
-
return <
|
|
205
|
+
return <FormLayout schema={resolvedSchema} {...contextProps} {...props} />;
|
|
178
206
|
};
|
|
179
207
|
|
|
180
|
-
|
|
208
|
+
FormLayoutController.displayName = FORM_LAYOUT_NAME;
|
|
181
209
|
|
|
182
210
|
//
|
|
183
211
|
// Actions
|
|
@@ -203,9 +231,7 @@ export const FormActions = ({ classNames }: FormActionsProps) => {
|
|
|
203
231
|
// Deprecate FormSubmit ans use FormActions without Cancel button if no callback is supplied.
|
|
204
232
|
|
|
205
233
|
return (
|
|
206
|
-
<div
|
|
207
|
-
className={mx(withColumn.center(), 'grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding', classNames)}
|
|
208
|
-
>
|
|
234
|
+
<div className={mx(withColumn.center(), formTheme.styles().actions(), classNames)}>
|
|
209
235
|
{onCancel && (
|
|
210
236
|
<IconButton
|
|
211
237
|
icon='ph--x--regular'
|
|
@@ -239,17 +265,23 @@ FormActions.displayName = FORM_ACTIONS_NAME;
|
|
|
239
265
|
|
|
240
266
|
const FORM_SECTION_NAME = 'Form.Section';
|
|
241
267
|
|
|
242
|
-
export type FormSectionProps = ThemedClassName<{
|
|
268
|
+
export type FormSectionProps = ThemedClassName<{
|
|
269
|
+
title?: string;
|
|
270
|
+
description?: string;
|
|
271
|
+
}>;
|
|
243
272
|
|
|
244
273
|
export const FormSection = composable<HTMLDivElement, FormSectionProps>(
|
|
245
|
-
({ children,
|
|
274
|
+
({ children, title, description, ...props }, forwardedRef) => {
|
|
275
|
+
const { variant = 'default' } = useFormContext(FORM_SECTION_NAME);
|
|
276
|
+
const styles = formTheme.styles({ variant });
|
|
246
277
|
return (
|
|
247
|
-
<div
|
|
248
|
-
{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
278
|
+
<div {...composableProps(props, { classNames: styles.section() })} ref={forwardedRef}>
|
|
279
|
+
{(title || description) && (
|
|
280
|
+
<div className={styles.sectionHeader()}>
|
|
281
|
+
{title && <h2 className={styles.sectionTitle()}>{title}</h2>}
|
|
282
|
+
{description && <MarkdownView classNames={styles.sectionDescription()} content={description} />}
|
|
283
|
+
</div>
|
|
284
|
+
)}
|
|
253
285
|
{children}
|
|
254
286
|
</div>
|
|
255
287
|
);
|
|
@@ -258,6 +290,31 @@ export const FormSection = composable<HTMLDivElement, FormSectionProps>(
|
|
|
258
290
|
|
|
259
291
|
FormSection.displayName = FORM_SECTION_NAME;
|
|
260
292
|
|
|
293
|
+
//
|
|
294
|
+
// Group
|
|
295
|
+
//
|
|
296
|
+
|
|
297
|
+
const FORM_GROUP_NAME = 'Form.Group';
|
|
298
|
+
|
|
299
|
+
export type FormGroupProps = ThemedClassName<PropsWithChildren>;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* A bordered card grouping related rows/controls (e.g. an entity card in a list).
|
|
303
|
+
* Layout-only and context-free — unlike `Form.FieldSet` it is not schema-driven.
|
|
304
|
+
*/
|
|
305
|
+
export const FormGroup = composable<HTMLDivElement, FormGroupProps>(({ children, ...props }, forwardedRef) => {
|
|
306
|
+
const { variant = 'default' } = useFormContext(FORM_SECTION_NAME);
|
|
307
|
+
const styles = formTheme.styles({ variant });
|
|
308
|
+
|
|
309
|
+
return (
|
|
310
|
+
<div {...composableProps(props, { classNames: styles.group() })} ref={forwardedRef}>
|
|
311
|
+
{children}
|
|
312
|
+
</div>
|
|
313
|
+
);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
FormGroup.displayName = FORM_GROUP_NAME;
|
|
317
|
+
|
|
261
318
|
//
|
|
262
319
|
// Submit
|
|
263
320
|
//
|
|
@@ -279,7 +336,7 @@ export const FormSubmit = ({ classNames, label, icon, disabled }: FormSubmitProp
|
|
|
279
336
|
}
|
|
280
337
|
|
|
281
338
|
return (
|
|
282
|
-
<div className={mx(
|
|
339
|
+
<div className={mx(formTheme.styles().submit(), classNames)}>
|
|
283
340
|
<IconButton
|
|
284
341
|
classNames='w-full'
|
|
285
342
|
type='submit'
|
|
@@ -11,28 +11,27 @@ import React, { useMemo } from 'react';
|
|
|
11
11
|
|
|
12
12
|
import { Annotation, Format } from '@dxos/echo';
|
|
13
13
|
import { SchemaEx } from '@dxos/effect';
|
|
14
|
-
import {
|
|
14
|
+
import { IconButton, IconButtonProps, useTranslation } from '@dxos/react-ui';
|
|
15
15
|
|
|
16
16
|
import { translationKey } from '#translations';
|
|
17
|
-
import {
|
|
18
|
-
type CreateOptions,
|
|
19
|
-
type FormFieldOptions,
|
|
20
|
-
type FormFieldRenderer,
|
|
21
|
-
type FormFieldRendererProps,
|
|
22
|
-
type RefFieldDataProps,
|
|
23
|
-
} from '#types';
|
|
17
|
+
import { type FieldContext, type FormFieldRenderer, type FormFieldRendererProps } from '#types';
|
|
24
18
|
|
|
19
|
+
import { AutofillAnnotation, OptionsLookupAnnotation } from '../../../annotations';
|
|
25
20
|
import { useFormFieldState } from '../../../hooks';
|
|
26
21
|
import { getRefProps } from '../../../util';
|
|
27
22
|
import { FormFieldSet } from '../FormFieldSet';
|
|
28
23
|
import {
|
|
29
24
|
ArrayField,
|
|
25
|
+
AsyncSelectField,
|
|
26
|
+
AutofillField,
|
|
30
27
|
BooleanField,
|
|
28
|
+
ComboboxField,
|
|
31
29
|
DateField,
|
|
32
30
|
GeoPointField,
|
|
33
31
|
InlineRefField,
|
|
34
32
|
MarkdownField,
|
|
35
33
|
NumberField,
|
|
34
|
+
PasswordField,
|
|
36
35
|
RefField,
|
|
37
36
|
SelectField,
|
|
38
37
|
TextAreaField,
|
|
@@ -55,20 +54,35 @@ export type FormFieldProps = {
|
|
|
55
54
|
*/
|
|
56
55
|
name: string | null;
|
|
57
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Explicit label, overriding the `title ?? capitalize(name)` derivation. Used by `ArrayField` to
|
|
59
|
+
* give scalar/ref items the array's resolved title (e.g. `Tags`) rather than re-capitalizing the
|
|
60
|
+
* raw array property name (e.g. `_tags`), since the element type carries no title of its own.
|
|
61
|
+
*/
|
|
62
|
+
label?: string;
|
|
63
|
+
|
|
58
64
|
/**
|
|
59
65
|
* Path to the current object from the root. Used with nested forms.
|
|
60
66
|
*/
|
|
61
67
|
path?: (string | number)[];
|
|
62
68
|
autoFocus?: boolean;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
/** Whether the field is required (non-optional in the schema). Drives the label asterisk. */
|
|
70
|
+
required?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Force a `Ref` field to render its target inline (a nested form) instead of the picker.
|
|
73
|
+
* Set by `ArrayField` for owned-ref arrays (`FormCreateAnnotation`); equivalent to
|
|
74
|
+
* `FormInlineAnnotation` but driven by the parent array rather than the element's own AST.
|
|
75
|
+
*/
|
|
76
|
+
refInline?: boolean;
|
|
77
|
+
} & FieldContext;
|
|
66
78
|
|
|
67
79
|
export const FormField = (props: FormFieldProps) => {
|
|
68
80
|
const {
|
|
69
81
|
type,
|
|
70
82
|
name,
|
|
83
|
+
label: labelProp,
|
|
71
84
|
path,
|
|
85
|
+
required,
|
|
72
86
|
projection,
|
|
73
87
|
fieldMap,
|
|
74
88
|
fieldProvider,
|
|
@@ -85,22 +99,27 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
85
99
|
useType,
|
|
86
100
|
getOptions,
|
|
87
101
|
onCreate,
|
|
102
|
+
resolveCreateEntry,
|
|
103
|
+
refInline,
|
|
88
104
|
} = props;
|
|
89
105
|
const { t } = useTranslation(translationKey);
|
|
90
106
|
const title = SchemaEx.getAnnotation<string>(SchemaAST.TitleAnnotationId)(type);
|
|
91
107
|
const description = SchemaEx.getAnnotation<string>(SchemaAST.DescriptionAnnotationId)(type);
|
|
92
108
|
const examples = SchemaEx.getAnnotation<string[]>(SchemaAST.ExamplesAnnotationId)(type);
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const label = useMemo(() => title ?? (name == null ? '' : String.capitalize(name)), [title, name]);
|
|
110
|
+
const label = useMemo(
|
|
111
|
+
() => labelProp ?? title ?? (name == null ? '' : String.capitalize(name)),
|
|
112
|
+
[labelProp, title, name],
|
|
113
|
+
);
|
|
99
114
|
const placeholder = useMemo(
|
|
100
115
|
() => (examples?.length ? `${t('example.placeholder')}: ${examples[0]}` : (description ?? label)),
|
|
101
|
-
[examples, description, label],
|
|
116
|
+
[examples, description, label, t],
|
|
102
117
|
);
|
|
103
118
|
|
|
119
|
+
// Build the schema for `fieldProvider` only when one is registered, memoized by `type` (the AST) so
|
|
120
|
+
// we don't reconstruct it on every render.
|
|
121
|
+
const providerSchema = useMemo(() => (fieldProvider ? Schema.make(type) : undefined), [fieldProvider, type]);
|
|
122
|
+
|
|
104
123
|
const fieldState = useFormFieldState(FormField.displayName, path);
|
|
105
124
|
const jsonPath = SchemaEx.createJsonPath(path ?? []);
|
|
106
125
|
const fieldProps: FormFieldRendererProps = {
|
|
@@ -108,16 +127,18 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
108
127
|
format: Format.FormatAnnotation.getFromAst(type).pipe((annotation) => Option.getOrUndefined(annotation)),
|
|
109
128
|
readonly,
|
|
110
129
|
label,
|
|
130
|
+
description,
|
|
111
131
|
jsonPath,
|
|
112
132
|
placeholder,
|
|
113
|
-
layout,
|
|
133
|
+
presentation: layout,
|
|
134
|
+
required,
|
|
114
135
|
db,
|
|
115
136
|
...fieldState,
|
|
116
137
|
};
|
|
117
138
|
|
|
118
139
|
// Omit empty fields entirely in read-only mode -- an empty value has nothing
|
|
119
140
|
// to display, so a labelled row with a blank input is just noise. This
|
|
120
|
-
// mirrors what `
|
|
141
|
+
// mirrors what `FormRow` already does for `presentation === 'static'`, but
|
|
121
142
|
// covers every field type (including those that bypass the wrapper:
|
|
122
143
|
// RefField, SelectField, MarkdownField, ...). Container fields
|
|
123
144
|
// (`ArrayField`, nested-struct -> `FormFieldSet`) keep their own
|
|
@@ -136,10 +157,29 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
136
157
|
return <CustomField {...fieldProps} />;
|
|
137
158
|
}
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
160
|
+
if (fieldProvider && providerSchema) {
|
|
161
|
+
const component = fieldProvider({ schema: providerSchema, prop: name ?? '', fieldProps });
|
|
162
|
+
if (component) {
|
|
163
|
+
return component;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//
|
|
168
|
+
// Dynamic, value-driven fields (options/value/validation loaded via a self-contained Effect annotation).
|
|
169
|
+
//
|
|
170
|
+
|
|
171
|
+
const optionsLookup = Option.getOrUndefined(OptionsLookupAnnotation.getFromAst(type));
|
|
172
|
+
if (optionsLookup) {
|
|
173
|
+
return optionsLookup.combobox ? (
|
|
174
|
+
<ComboboxField {...fieldProps} lookup={optionsLookup} />
|
|
175
|
+
) : (
|
|
176
|
+
<AsyncSelectField {...fieldProps} lookup={optionsLookup} />
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const autofill = Option.getOrUndefined(AutofillAnnotation.getFromAst(type));
|
|
181
|
+
if (autofill) {
|
|
182
|
+
return <AutofillField {...fieldProps} autofill={autofill} />;
|
|
143
183
|
}
|
|
144
184
|
|
|
145
185
|
//
|
|
@@ -190,10 +230,21 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
190
230
|
|
|
191
231
|
const refProps = getRefProps(type);
|
|
192
232
|
if (refProps) {
|
|
193
|
-
// Inline a single referenced object's own fields (nested form) instead of a picker.
|
|
194
|
-
|
|
233
|
+
// Inline a single referenced object's own fields (nested form) instead of a picker. `refInline` lets a
|
|
234
|
+
// parent (e.g. an owned-ref `ArrayField`) force this for elements whose own AST carries no annotation.
|
|
235
|
+
const inline =
|
|
236
|
+
refInline || Annotation.FormInlineAnnotation.getFromAst(refProps.ast).pipe(Option.getOrElse(() => false));
|
|
195
237
|
if (inline && !refProps.isArray) {
|
|
196
|
-
return
|
|
238
|
+
return (
|
|
239
|
+
<InlineRefField
|
|
240
|
+
{...fieldProps}
|
|
241
|
+
{...refProps}
|
|
242
|
+
db={db}
|
|
243
|
+
useType={useType}
|
|
244
|
+
onCreate={onCreate}
|
|
245
|
+
resolveCreateEntry={resolveCreateEntry}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
197
248
|
}
|
|
198
249
|
|
|
199
250
|
const isCreateTarget = !createTypename || refProps.typename === createTypename;
|
|
@@ -209,6 +260,7 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
209
260
|
useType={useType}
|
|
210
261
|
getOptions={getOptions}
|
|
211
262
|
onCreate={onCreate}
|
|
263
|
+
resolveCreateEntry={resolveCreateEntry}
|
|
212
264
|
/>
|
|
213
265
|
);
|
|
214
266
|
}
|
|
@@ -243,6 +295,7 @@ export const FormField = (props: FormFieldProps) => {
|
|
|
243
295
|
useType={useType}
|
|
244
296
|
getOptions={getOptions}
|
|
245
297
|
onCreate={onCreate}
|
|
298
|
+
resolveCreateEntry={resolveCreateEntry}
|
|
246
299
|
/>
|
|
247
300
|
);
|
|
248
301
|
}
|
|
@@ -258,12 +311,7 @@ FormField.displayName = 'Form.FormField';
|
|
|
258
311
|
//
|
|
259
312
|
|
|
260
313
|
export const CompactIconButton = (props: IconButtonProps) => {
|
|
261
|
-
return
|
|
262
|
-
// IconBlock defaults to aria-hidden (decorative slot); the button is interactive, so un-hide it.
|
|
263
|
-
<IconBlock aria-hidden={false} classNames='my-[1px]'>
|
|
264
|
-
<IconButton variant='ghost' density='xs' square iconOnly {...props} />
|
|
265
|
-
</IconBlock>
|
|
266
|
-
);
|
|
314
|
+
return <IconButton variant='ghost' iconOnly {...props} />;
|
|
267
315
|
};
|
|
268
316
|
|
|
269
317
|
/**
|
|
@@ -288,6 +336,7 @@ const getFormField = ({
|
|
|
288
336
|
Match.when(Format.TypeFormat.DateTime, () => DateField),
|
|
289
337
|
Match.when(Format.TypeFormat.GeoPoint, () => GeoPointField),
|
|
290
338
|
Match.when(Format.TypeFormat.Markdown, () => MarkdownField),
|
|
339
|
+
Match.when(Format.TypeFormat.Password, () => PasswordField),
|
|
291
340
|
Match.when(Format.TypeFormat.Text, () => TextAreaField),
|
|
292
341
|
Match.when(Format.TypeFormat.Time, () => DateField),
|
|
293
342
|
Match.orElse(() => undefined),
|
|
@@ -310,6 +359,8 @@ const getFormField = ({
|
|
|
310
359
|
case 'BooleanKeyword':
|
|
311
360
|
return BooleanField;
|
|
312
361
|
}
|
|
362
|
+
|
|
363
|
+
return undefined;
|
|
313
364
|
};
|
|
314
365
|
|
|
315
366
|
const getSelectOptions = (ast: SchemaAST.AST): Format.Options[] | undefined => {
|