@dxos/react-ui-form 0.7.5-labs.e27f9b9 → 0.7.5-main.2567c87

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.
Files changed (66) hide show
  1. package/dist/lib/browser/index.mjs +467 -726
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +506 -750
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +467 -726
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  11. package/dist/types/src/components/Form/Defaults.d.ts +6 -5
  12. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/Form.d.ts +21 -12
  14. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/Form.stories.d.ts +1 -2
  16. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Form/Input.d.ts +6 -5
  18. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  19. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +2 -1
  20. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  21. package/dist/types/src/components/Form/custom/TupleInput.d.ts +2 -1
  22. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  23. package/dist/types/src/components/Form/custom/index.d.ts +0 -1
  24. package/dist/types/src/components/Form/custom/index.d.ts.map +1 -1
  25. package/dist/types/src/components/Form/factory.d.ts +2 -2
  26. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  27. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  28. package/dist/types/src/components/deprecated/FormInput.d.ts +0 -5
  29. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  30. package/dist/types/src/hooks/useForm.d.ts +11 -10
  31. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  32. package/dist/types/src/translations.d.ts +0 -6
  33. package/dist/types/src/translations.d.ts.map +1 -1
  34. package/package.json +27 -28
  35. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  36. package/src/components/FieldEditor/FieldEditor.tsx +6 -7
  37. package/src/components/Form/Defaults.tsx +33 -20
  38. package/src/components/Form/Form.stories.tsx +5 -15
  39. package/src/components/Form/Form.tsx +355 -46
  40. package/src/components/Form/Input.tsx +6 -5
  41. package/src/components/Form/custom/GeoPointInput.tsx +15 -6
  42. package/src/components/Form/custom/TupleInput.tsx +9 -5
  43. package/src/components/Form/custom/index.ts +0 -1
  44. package/src/components/Form/factory.tsx +5 -2
  45. package/src/components/ViewEditor/ViewEditor.tsx +2 -5
  46. package/src/components/deprecated/FormInput.tsx +7 -20
  47. package/src/hooks/useForm.ts +49 -57
  48. package/src/translations.ts +0 -8
  49. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  50. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  51. package/dist/types/src/components/Form/FormActions.d.ts +0 -7
  52. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  53. package/dist/types/src/components/Form/FormContent.d.ts +0 -26
  54. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  55. package/dist/types/src/components/Form/FormContext.d.ts +0 -20
  56. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  57. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
  58. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
  59. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -7
  60. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
  61. package/src/components/Form/ArrayField.tsx +0 -111
  62. package/src/components/Form/FormActions.tsx +0 -41
  63. package/src/components/Form/FormContent.tsx +0 -173
  64. package/src/components/Form/FormContext.tsx +0 -48
  65. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -58
  66. package/src/components/Form/custom/SelectOptionsInput.tsx +0 -192
@@ -4,29 +4,30 @@
4
4
 
5
5
  import React, { type FC, type PropsWithChildren } from 'react';
6
6
 
7
- import { type FormatEnum } from '@dxos/echo-schema';
7
+ import { type BaseObject, type FormatEnum, type PropertyKey } from '@dxos/echo-schema';
8
8
  import { type SimpleType } from '@dxos/effect';
9
9
  import { Icon, Tooltip } from '@dxos/react-ui';
10
10
  import { errorText } from '@dxos/react-ui-theme';
11
11
 
12
- import { type FormInputStateProps } from './FormContext';
12
+ import { type FormHandler } from '../../hooks';
13
13
 
14
14
  /**
15
15
  * Props passed to input components.
16
16
  */
17
- export type InputProps = {
17
+ export type InputProps<T extends BaseObject> = {
18
+ property: PropertyKey<T>;
18
19
  type: SimpleType;
19
20
  format?: FormatEnum;
20
21
  label?: string;
21
22
  disabled?: boolean;
22
23
  placeholder?: string;
23
24
  inputOnly?: boolean;
24
- } & FormInputStateProps;
25
+ } & Pick<FormHandler<T>, 'getStatus' | 'getValue' | 'onValueChange' | 'onBlur'>;
25
26
 
26
27
  /**
27
28
  * Form input component.
28
29
  */
29
- export type InputComponent = FC<InputProps>;
30
+ export type InputComponent<T extends BaseObject> = FC<InputProps<T>>;
30
31
 
31
32
  export type InputHeaderProps = PropsWithChildren<{
32
33
  error?: string;
@@ -4,17 +4,26 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { type GeoPoint } from '@dxos/echo-schema';
7
+ import { type BaseObject, type GeoPoint } from '@dxos/echo-schema';
8
8
  import { Input, useTranslation } from '@dxos/react-ui';
9
9
  import { safeParseFloat } from '@dxos/util';
10
10
 
11
11
  import { translationKey } from '../../../translations';
12
12
  import { InputHeader, type InputProps } from '../Input';
13
13
 
14
- export const GeoPointInput = ({ type, label, disabled, getStatus, getValue, onValueChange, onBlur }: InputProps) => {
14
+ export const GeoPointInput = <T extends BaseObject>({
15
+ property,
16
+ type,
17
+ label,
18
+ disabled,
19
+ getStatus,
20
+ getValue,
21
+ onValueChange,
22
+ onBlur,
23
+ }: InputProps<T>) => {
15
24
  const { t } = useTranslation(translationKey);
16
- const { status, error } = getStatus();
17
- const [lng = 0, lat = 0] = getValue<GeoPoint>() ?? [];
25
+ const { status, error } = getStatus?.(property);
26
+ const [lng = 0, lat = 0] = getValue<GeoPoint>(property) ?? [];
18
27
 
19
28
  return (
20
29
  <Input.Root validationValence={status}>
@@ -27,7 +36,7 @@ export const GeoPointInput = ({ type, label, disabled, getStatus, getValue, onVa
27
36
  disabled={disabled}
28
37
  placeholder={t('placeholder longitude')}
29
38
  value={lng}
30
- onChange={(event) => onValueChange(type, [lat, safeParseFloat(event.target.value, 0)])}
39
+ onChange={(event) => onValueChange(property, type, [lat, safeParseFloat(event.target.value, 0)])}
31
40
  onBlur={onBlur}
32
41
  />
33
42
  <Input.TextInput
@@ -35,7 +44,7 @@ export const GeoPointInput = ({ type, label, disabled, getStatus, getValue, onVa
35
44
  disabled={disabled}
36
45
  placeholder={t('placeholder latitude')}
37
46
  value={lat}
38
- onChange={(event) => onValueChange(type, [safeParseFloat(event.target.value, 0), lng])}
47
+ onChange={(event) => onValueChange(property, type, [safeParseFloat(event.target.value, 0), lng])}
39
48
  onBlur={onBlur}
40
49
  />
41
50
  </div>
@@ -4,6 +4,7 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
+ import { type BaseObject } from '@dxos/echo-schema';
7
8
  import { Input } from '@dxos/react-ui';
8
9
  import { mx } from '@dxos/react-ui-theme';
9
10
  import { safeParseFloat } from '@dxos/util';
@@ -12,8 +13,9 @@ import { InputHeader, type InputProps } from '../Input';
12
13
 
13
14
  const gridCols = ['grid-cols-1', 'grid-cols-2', 'grid-cols-3', 'grid-cols-4'];
14
15
 
15
- export const TupleInput = ({
16
+ export const TupleInput = <T extends BaseObject>({
16
17
  binding,
18
+ property,
17
19
  type,
18
20
  label,
19
21
  disabled,
@@ -21,11 +23,11 @@ export const TupleInput = ({
21
23
  getValue,
22
24
  onValueChange,
23
25
  onBlur,
24
- }: InputProps & { binding: string[] }) => {
25
- const { status, error } = getStatus();
26
+ }: InputProps<T> & { binding: string[] }) => {
27
+ const { status, error } = getStatus?.(property);
26
28
 
27
29
  // TODO(burdon): Generalize number/float/string, etc.
28
- const values: Record<string, number> = getValue<Record<string, number>>() ?? {};
30
+ const values: Record<string, number> = getValue<Record<string, number>>(property) ?? {};
29
31
 
30
32
  return (
31
33
  <Input.Root validationValence={status}>
@@ -39,7 +41,9 @@ export const TupleInput = ({
39
41
  type='number'
40
42
  disabled={disabled}
41
43
  value={values[prop]}
42
- onChange={(event) => onValueChange(type, { ...values, [prop]: safeParseFloat(event.target.value, 0) })}
44
+ onChange={(event) =>
45
+ onValueChange(property, type, { ...values, [prop]: safeParseFloat(event.target.value, 0) })
46
+ }
43
47
  onBlur={onBlur}
44
48
  />
45
49
  ))}
@@ -3,5 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './GeoPointInput';
6
- export * from './SelectOptionsInput';
7
6
  export * from './TupleInput';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { FormatEnum } from '@dxos/echo-schema';
5
+ import { type BaseObject, FormatEnum } from '@dxos/echo-schema';
6
6
  import { type SimpleType } from '@dxos/effect';
7
7
 
8
8
  import { BooleanInput, NumberInput, TextInput } from './Defaults';
@@ -12,7 +12,10 @@ import { GeoPointInput } from './custom';
12
12
  /**
13
13
  * Get property input component.
14
14
  */
15
- export const getInputComponent = (type: SimpleType, format?: FormatEnum): InputComponent | undefined => {
15
+ export const getInputComponent = <T extends BaseObject>(
16
+ type: SimpleType,
17
+ format?: FormatEnum,
18
+ ): InputComponent<T> | undefined => {
16
19
  switch (format) {
17
20
  case FormatEnum.LatLng:
18
21
  return GeoPointInput;
@@ -10,6 +10,7 @@ import { IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui
10
10
  import { List } from '@dxos/react-ui-list';
11
11
  import { ghostHover, inputTextLabel, mx } from '@dxos/react-ui-theme';
12
12
  import { FieldSchema, type FieldType, type ViewType, ViewProjection, VIEW_FIELD_LIMIT } from '@dxos/schema';
13
+ import { arrayMove } from '@dxos/util';
13
14
 
14
15
  import { translationKey } from '../../translations';
15
16
  import { FieldEditor } from '../FieldEditor';
@@ -90,11 +91,7 @@ export const ViewEditor = ({
90
91
 
91
92
  const handleMove = useCallback(
92
93
  (fromIndex: number, toIndex: number) => {
93
- // NOTE(ZaymonFC): Using arrayMove here causes a race condition with the kanban model.
94
- const fields = [...view.fields];
95
- const [moved] = fields.splice(fromIndex, 1);
96
- fields.splice(toIndex, 0, moved);
97
- view.fields = fields;
94
+ arrayMove(view.fields, fromIndex, toIndex);
98
95
  },
99
96
  [view.fields],
100
97
  );
@@ -4,21 +4,7 @@
4
4
 
5
5
  import React, { type JSX, type PropsWithChildren } from 'react';
6
6
 
7
- import { Input, type ThemedClassName } from '@dxos/react-ui';
8
- import { mx, textBlockWidth } from '@dxos/react-ui-theme';
9
-
10
- /**
11
- * @deprecated
12
- */
13
- export const DeprecatedFormContainer = ({ children, classNames }: ThemedClassName<PropsWithChildren>) => {
14
- return (
15
- <div role='none' className='w-full p-4 justify-center overflow-x-hidden overflow-y-auto'>
16
- <div role='form' className={mx('flex flex-col', textBlockWidth, classNames)}>
17
- {children}
18
- </div>
19
- </div>
20
- );
21
- };
7
+ import { Input } from '@dxos/react-ui';
22
8
 
23
9
  export type DeprecatedFormInputProps = {
24
10
  label: string;
@@ -29,6 +15,7 @@ export type DeprecatedFormInputProps = {
29
15
  /**
30
16
  * @deprecated
31
17
  */
18
+ // TODO(burdon): Still used in ObservabilitySettings and all settings.
32
19
  export const DeprecatedFormInput = ({
33
20
  label,
34
21
  description,
@@ -39,9 +26,8 @@ export const DeprecatedFormInput = ({
39
26
  <div role='none' className='flex w-full gap-4 py-1'>
40
27
  <Input.Root>
41
28
  <div role='none' className='flex flex-col w-full'>
42
- <Input.Label classNames='flex min-bs-[--rail-action] items-center' style={{ fontSize: 'unset' }}>
43
- {label}
44
- </Input.Label>
29
+ {/* TODO(burdon): Consistent height for controls (e.g., Select, Textbox, and Checkbox are all different). */}
30
+ <Input.Label classNames='flex min-h-[40px] items-center'>{label}</Input.Label>
45
31
  {description && (
46
32
  <Input.DescriptionAndValidation classNames='mbs-0.5'>
47
33
  <Input.Description>{description}</Input.Description>
@@ -50,7 +36,7 @@ export const DeprecatedFormInput = ({
50
36
  </div>
51
37
 
52
38
  <div role='none'>
53
- <div role='none' className='flex min-bs-[--rail-action] items-center'>
39
+ <div role='none' className='flex min-h-[40px] items-center'>
54
40
  {children}
55
41
  </div>
56
42
  </div>
@@ -59,8 +45,9 @@ export const DeprecatedFormInput = ({
59
45
  );
60
46
 
61
47
  if (secondary) {
48
+ // console.log(secondary);
62
49
  return (
63
- <div role='none'>
50
+ <div role='none' className='flex flex-col w-full'>
64
51
  {primary}
65
52
  {secondary}
66
53
  </div>
@@ -2,10 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { type FocusEvent, useCallback, useEffect, useMemo, useState } from 'react';
6
6
 
7
- import { type BaseObject, getValue, setValue } from '@dxos/echo-schema';
8
- import { AST, type S, type SimpleType, type JsonPath, createJsonPath, fromEffectValidationPath } from '@dxos/effect';
7
+ import { type BaseObject, type PropertyKey, getValue, setValue } from '@dxos/echo-schema';
8
+ import { type SimpleType, type S, type JsonPath } from '@dxos/effect';
9
9
  import { invariant } from '@dxos/invariant';
10
10
  import { log } from '@dxos/log';
11
11
  import { validateSchema, type ValidationError } from '@dxos/schema';
@@ -20,9 +20,9 @@ export type FormHandler<T extends BaseObject> = {
20
20
  //
21
21
 
22
22
  values: Partial<T>;
23
- errors: Record<JsonPath, string>;
24
- touched: Record<JsonPath, boolean>;
25
- changed: Record<JsonPath, boolean>;
23
+ errors: Record<PropertyKey<T>, string>;
24
+ touched: Record<PropertyKey<T>, boolean>;
25
+ changed: Record<PropertyKey<T>, boolean>;
26
26
  canSave: boolean;
27
27
  handleSave: () => void;
28
28
 
@@ -30,10 +30,10 @@ export type FormHandler<T extends BaseObject> = {
30
30
  // Form input component helpers.
31
31
  //
32
32
 
33
- getStatus: (path: string | (string | number)[]) => { status?: 'error'; error?: string };
34
- getValue: <V>(path: (string | number)[]) => V | undefined;
35
- onValueChange: <V>(path: (string | number)[], type: SimpleType, value: V) => void;
36
- onTouched: (path: (string | number)[]) => void;
33
+ getStatus: (property: PropertyKey<T>) => { status?: 'error'; error?: string };
34
+ getValue: <V>(property: PropertyKey<T>) => V | undefined;
35
+ onValueChange: <V>(property: PropertyKey<T>, type: SimpleType, value: V) => void;
36
+ onBlur: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
37
37
  };
38
38
 
39
39
  /**
@@ -41,8 +41,9 @@ export type FormHandler<T extends BaseObject> = {
41
41
  */
42
42
  export interface FormOptions<T extends BaseObject> {
43
43
  /**
44
- * Effect schema (Type literal).
44
+ * Effect schema.
45
45
  */
46
+ // TODO(burdon): Change to S.Struct<T>?
46
47
  schema: S.Schema<T>;
47
48
 
48
49
  /**
@@ -88,22 +89,21 @@ export const useForm = <T extends BaseObject>({
88
89
  onValid,
89
90
  onSave,
90
91
  }: FormOptions<T>): FormHandler<T> => {
91
- invariant(AST.isTypeLiteral(schema.ast));
92
-
93
92
  const [values, setValues] = useState<Partial<T>>(initialValues);
94
93
  useEffect(() => {
95
94
  setValues(initialValues);
96
95
  }, [initialValues]);
97
96
 
98
- const [touched, setTouched] = useState<Record<JsonPath, boolean>>(createKeySet(initialValues, false));
99
- const [changed, setChanged] = useState<Record<JsonPath, boolean>>(createKeySet(initialValues, false));
100
- const [errors, setErrors] = useState<Record<JsonPath, string>>({});
97
+ const [touched, setTouched] = useState<Record<PropertyKey<T>, boolean>>(createKeySet(initialValues, false));
98
+ const [changed, setChanged] = useState<Record<PropertyKey<T>, boolean>>(createKeySet(initialValues, false));
99
+ const [errors, setErrors] = useState<Record<PropertyKey<T>, string>>({} as Record<PropertyKey<T>, string>);
101
100
  const [saving, setSaving] = useState(false);
102
101
 
103
102
  //
104
103
  // Validation.
105
104
  //
106
105
 
106
+ // TODO(burdon): Validate each property separately.
107
107
  const validate = useCallback(
108
108
  (values: Partial<T>): values is T => {
109
109
  let errors: ValidationError[] = validateSchema(schema, values) ?? [];
@@ -136,15 +136,8 @@ export const useForm = <T extends BaseObject>({
136
136
  const canSave = useMemo(
137
137
  () =>
138
138
  !saving &&
139
- // Check if any error paths that are touched have errors
140
- !Object.entries(touched).some(
141
- ([path, isTouched]) =>
142
- isTouched &&
143
- Object.keys(errors).some(
144
- (errorPath) => errorPath === path || errorPath.startsWith(`${path}.`) || errorPath.startsWith(`${path}[`),
145
- ),
146
- ),
147
- [touched, errors, saving],
139
+ Object.keys(values).every((property) => touched[property as JsonPath] === false || !errors[property as JsonPath]),
140
+ [values, touched, errors, saving],
148
141
  );
149
142
 
150
143
  const handleSave = useCallback(async () => {
@@ -163,27 +156,19 @@ export const useForm = <T extends BaseObject>({
163
156
  //
164
157
 
165
158
  const getStatus = useCallback<FormHandler<T>['getStatus']>(
166
- (path) => {
167
- const jsonPath = Array.isArray(path) ? createJsonPath(path) : path;
168
- const matchingError = Object.entries(errors).find(
169
- ([errorPath]) =>
170
- errorPath === jsonPath || errorPath.startsWith(`${jsonPath}.`) || errorPath.startsWith(`${jsonPath}[`),
171
- );
172
-
173
- return {
174
- status: matchingError ? 'error' : undefined,
175
- error: matchingError ? matchingError[1] : undefined,
176
- };
177
- },
178
- [errors],
159
+ (property: PropertyKey<T>) => ({
160
+ status: errors[property] ? 'error' : undefined,
161
+ error: errors[property] ? errors[property] : undefined,
162
+ }),
163
+ [touched, errors],
179
164
  );
180
165
 
181
- const getFormValue = <V>(path: (string | number)[]): V | undefined => {
182
- return getValue(values, createJsonPath(path));
166
+ // TODO(burdon): Use path to extract hierarchical value.
167
+ const getFormValue = <V>(property: PropertyKey<T>): V | undefined => {
168
+ return getValue(values, property as any as JsonPath);
183
169
  };
184
170
 
185
- const onValueChange = (path: (string | number)[], type: SimpleType, value: any) => {
186
- const jsonPath = createJsonPath(path);
171
+ const onValueChange = (property: PropertyKey<T>, type: SimpleType, value: any) => {
187
172
  let parsedValue = value;
188
173
  try {
189
174
  if (type === 'number') {
@@ -194,9 +179,9 @@ export const useForm = <T extends BaseObject>({
194
179
  parsedValue = undefined;
195
180
  }
196
181
 
197
- const newValues = { ...setValue(values, jsonPath, parsedValue) };
182
+ const newValues = { ...setValue(values, property as any as JsonPath, parsedValue) };
198
183
  setValues(newValues);
199
- setChanged((prev) => ({ ...prev, [jsonPath]: true }));
184
+ setChanged((prev) => ({ ...prev, [property]: true }));
200
185
  onValuesChanged?.(newValues);
201
186
 
202
187
  const isValid = validate(newValues);
@@ -205,10 +190,19 @@ export const useForm = <T extends BaseObject>({
205
190
  }
206
191
  };
207
192
 
208
- const onTouched = useCallback(
209
- (path: (string | number)[]) => {
210
- const jsonPath = createJsonPath(path);
211
- setTouched((touched) => ({ ...touched, [jsonPath]: true }));
193
+ // TODO(burdon): This is a leaky abstraction: the hook ideally shouldn't get involved in UX.
194
+ const onBlur = useCallback(
195
+ (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
196
+ const { name } = event.target;
197
+ setTouched((touched) => ({ ...touched, [name]: true }));
198
+
199
+ // TODO(Zan): This should be configurable behavior.
200
+ if (event.relatedTarget?.getAttribute('type') === 'submit') {
201
+ // NOTE: We do this here instead of onSave because the blur event is triggered before the submit event
202
+ // and results in the submit button being disabled when the form is invalid.
203
+ setTouched(createKeySet(values, true));
204
+ }
205
+
212
206
  validate(values);
213
207
  },
214
208
  [validate, values],
@@ -227,25 +221,23 @@ export const useForm = <T extends BaseObject>({
227
221
  getStatus,
228
222
  getValue: getFormValue,
229
223
  onValueChange,
230
- onTouched,
224
+ onBlur,
231
225
  } satisfies FormHandler<T>;
232
226
  };
233
227
 
234
- const createKeySet = <T extends BaseObject, V>(obj: T, value: V): Record<JsonPath, V> => {
228
+ const createKeySet = <T extends BaseObject, V>(obj: T, value: V): Record<PropertyKey<T>, V> => {
235
229
  invariant(obj);
236
- return Object.keys(obj).reduce((acc, key) => ({ ...acc, [key]: value }), {} as Record<JsonPath, V>);
230
+ return Object.keys(obj).reduce((acc, key) => ({ ...acc, [key]: value }), {} as Record<PropertyKey<T>, V>);
237
231
  };
238
232
 
239
- const flatMap = (errors: ValidationError[]) => {
233
+ const flatMap = <T extends BaseObject>(errors: ValidationError[]) => {
240
234
  return errors.reduce(
241
235
  (result, { path, message }) => {
242
- // Convert the validation error path format to our JsonPath format
243
- const jsonPath = fromEffectValidationPath(path);
244
- if (!(jsonPath in result)) {
245
- result[jsonPath] = message;
236
+ if (!(path in result)) {
237
+ result[path as PropertyKey<T>] = message;
246
238
  }
247
239
  return result;
248
240
  },
249
- {} as Record<JsonPath, string>,
241
+ {} as Record<PropertyKey<T>, string>,
250
242
  );
251
243
  };
@@ -42,7 +42,6 @@ export default [
42
42
  'format ref': 'Reference',
43
43
  'format regex': 'RegExp',
44
44
  'format string': 'String',
45
- 'format single-select': 'Select',
46
45
  'format text': 'Long text',
47
46
  'format time': 'Time',
48
47
  'format timestamp': 'Timestamp',
@@ -54,13 +53,6 @@ export default [
54
53
  // Placeholders
55
54
  'placeholder latitude': 'Latitude',
56
55
  'placeholder longitude': 'Longitude',
57
-
58
- // SelectOptionsInput
59
- 'select option label': 'Label',
60
- 'select option label placeholder': 'Option label',
61
- 'select option color': 'Color',
62
- 'select option delete': 'Delete',
63
- 'select option add': 'Add option',
64
56
  },
65
57
  },
66
58
  },
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import { type SchemaProperty } from '@dxos/schema';
3
- import { type ComponentLookup } from './Form';
4
- import { type FormInputStateProps } from './FormContext';
5
- import { type InputComponent } from './Input';
6
- type ArrayFieldProps = {
7
- property: SchemaProperty<any>;
8
- readonly?: boolean;
9
- inputProps: FormInputStateProps;
10
- path?: (string | number)[];
11
- Custom?: Partial<Record<string, InputComponent>>;
12
- lookupComponent?: ComponentLookup;
13
- };
14
- export declare const ArrayField: ({ property, readonly, path, inputProps, Custom, lookupComponent }: ArrayFieldProps) => React.JSX.Element | null;
15
- export {};
16
- //# sourceMappingURL=ArrayField.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ArrayField.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/ArrayField.tsx"],"names":[],"mappings":"AAMA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAOpD,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAK3D,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,UAAU,sEAAuE,eAAe,6BA8E5G,CAAC"}
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- export type FormActionsProps = {
3
- readonly?: boolean;
4
- onCancel?: () => void;
5
- };
6
- export declare const FormActions: ({ onCancel, readonly }: FormActionsProps) => React.JSX.Element;
7
- //# sourceMappingURL=FormActions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormActions.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/FormActions.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,WAAW,2BAA4B,gBAAgB,sBAuBnE,CAAC"}
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
- import { S } from '@dxos/echo-schema';
3
- import { type SchemaProperty } from '@dxos/schema';
4
- import { type ComponentLookup } from './Form';
5
- import { type InputComponent } from './Input';
6
- export type FormContentProps = {
7
- schema: S.Schema.All;
8
- path?: (string | number)[];
9
- filter?: (props: SchemaProperty<any>[]) => SchemaProperty<any>[];
10
- sort?: string[];
11
- readonly?: boolean;
12
- lookupComponent?: ComponentLookup;
13
- Custom?: Partial<Record<string, InputComponent>>;
14
- };
15
- export type FormFieldProps = {
16
- property: SchemaProperty<any>;
17
- path?: (string | number)[];
18
- readonly?: boolean;
19
- /** Used to indicate if input should be presented inline (e.g. for array items). */
20
- inline?: boolean;
21
- lookupComponent?: ComponentLookup;
22
- Custom?: Partial<Record<string, InputComponent>>;
23
- };
24
- export declare const FormField: ({ property, path, readonly, inline, lookupComponent, Custom }: FormFieldProps) => React.JSX.Element | null;
25
- export declare const FormFields: ({ schema, path, filter, sort, readonly, lookupComponent, Custom }: FormContentProps) => React.JSX.Element;
26
- //# sourceMappingURL=FormContent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormContent.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/FormContent.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAO,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAKxE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,KAAK,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;IACjE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;CAClD,CAAC;AAEF,eAAO,MAAM,SAAS,kEAAmE,cAAc,6BAqGtG,CAAC;AAEF,eAAO,MAAM,UAAU,sEAAuE,gBAAgB,sBA4B7G,CAAC"}
@@ -1,20 +0,0 @@
1
- import React, { type FocusEvent, type PropsWithChildren } from 'react';
2
- import { type BaseObject } from '@dxos/echo-schema';
3
- import { type SimpleType } from '@dxos/effect';
4
- import { type FormHandler, type FormOptions } from '../../hooks';
5
- type FormContextValue<T extends BaseObject> = FormHandler<T>;
6
- export declare const useFormContext: <T extends BaseObject>() => FormContextValue<T>;
7
- export declare const useFormValues: (path?: (string | number)[]) => any;
8
- export type FormInputStateProps = {
9
- getStatus: () => {
10
- status?: 'error';
11
- error?: string;
12
- };
13
- getValue: <V>() => V | undefined;
14
- onValueChange: (type: SimpleType, value: any) => void;
15
- onBlur: (event: FocusEvent<HTMLElement>) => void;
16
- };
17
- export declare const useInputProps: (path?: (string | number)[]) => FormInputStateProps;
18
- export declare const FormProvider: ({ children, ...formOptions }: PropsWithChildren<FormOptions<any>>) => React.JSX.Element;
19
- export {};
20
- //# sourceMappingURL=FormContext.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FormContext.d.ts","sourceRoot":"","sources":["../../../../../src/components/Form/FormContext.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAA6B,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAGlG,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAW,MAAM,aAAa,CAAC;AAE1E,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AAI7D,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,UAAU,OAAK,gBAAgB,CAAC,CAAC,CAEzE,CAAC;AAEF,eAAO,MAAM,aAAa,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAQ,GAI9D,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACtD,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CAClD,CAAC;AAEF,eAAO,MAAM,aAAa,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAQ,mBAS9D,CAAC;AAEF,eAAO,MAAM,YAAY,iCAAkC,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,sBAG7F,CAAC"}
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import { type InputProps } from '../Input';
3
- export declare const SelectOptionInput: ({ type, label, disabled, getStatus, getValue, onValueChange }: InputProps) => React.JSX.Element;
4
- //# sourceMappingURL=SelectOptionsInput.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SelectOptionsInput.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Form/custom/SelectOptionsInput.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAqE,MAAM,OAAO,CAAC;AAU1F,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxD,eAAO,MAAM,iBAAiB,kEAAmE,UAAU,sBA8K1G,CAAC"}
@@ -1,7 +0,0 @@
1
- import '@dxos-theme';
2
- import { type Meta, type StoryObj } from '@storybook/react';
3
- declare const meta: Meta;
4
- export default meta;
5
- type Story = StoryObj;
6
- export declare const Default: Story;
7
- //# sourceMappingURL=SelectOptionsInput.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SelectOptionsInput.stories.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Form/custom/SelectOptionsInput.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAuC5D,QAAA,MAAM,IAAI,EAAE,IAKX,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAEtB,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC"}