@dxos/react-ui-form 0.7.5-main.9d2a38b → 0.7.5-main.b19bfc8

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 (83) hide show
  1. package/dist/lib/browser/index.mjs +971 -558
  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 +998 -596
  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 +971 -558
  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 +1 -2
  11. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/ArrayField.d.ts +15 -0
  13. package/dist/types/src/components/Form/ArrayField.d.ts.map +1 -0
  14. package/dist/types/src/components/Form/Defaults.d.ts +6 -7
  15. package/dist/types/src/components/Form/Defaults.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/Form.d.ts +12 -21
  17. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  18. package/dist/types/src/components/Form/Form.stories.d.ts +2 -1
  19. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Form/FormActions.d.ts +6 -0
  21. package/dist/types/src/components/Form/FormActions.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/FormContent.d.ts +25 -0
  23. package/dist/types/src/components/Form/FormContent.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/FormContext.d.ts +23 -0
  25. package/dist/types/src/components/Form/FormContext.d.ts.map +1 -0
  26. package/dist/types/src/components/Form/Input.d.ts +7 -8
  27. package/dist/types/src/components/Form/Input.d.ts.map +1 -1
  28. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +1 -3
  29. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +1 -1
  30. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +3 -0
  31. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +1 -0
  32. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +7 -0
  33. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +1 -0
  34. package/dist/types/src/components/Form/custom/TupleInput.d.ts +2 -4
  35. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +1 -1
  36. package/dist/types/src/components/Form/custom/index.d.ts +1 -0
  37. package/dist/types/src/components/Form/custom/index.d.ts.map +1 -1
  38. package/dist/types/src/components/Form/factory.d.ts +2 -2
  39. package/dist/types/src/components/Form/factory.d.ts.map +1 -1
  40. package/dist/types/src/components/Form/index.d.ts +2 -0
  41. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  42. package/dist/types/src/components/ViewEditor/Test.stories.d.ts +1 -2
  43. package/dist/types/src/components/ViewEditor/Test.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -2
  45. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  46. package/dist/types/src/components/deprecated/Form.d.ts +1 -2
  47. package/dist/types/src/components/deprecated/Form.d.ts.map +1 -1
  48. package/dist/types/src/components/deprecated/Form.stories.d.ts +1 -2
  49. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +1 -1
  50. package/dist/types/src/components/deprecated/FormInput.d.ts +6 -1
  51. package/dist/types/src/components/deprecated/FormInput.d.ts.map +1 -1
  52. package/dist/types/src/components/testing.d.ts +3 -3
  53. package/dist/types/src/components/testing.d.ts.map +1 -1
  54. package/dist/types/src/hooks/useForm.d.ts +11 -11
  55. package/dist/types/src/hooks/useForm.d.ts.map +1 -1
  56. package/dist/types/src/translations.d.ts +6 -0
  57. package/dist/types/src/translations.d.ts.map +1 -1
  58. package/dist/types/src/util/field.d.ts.map +1 -1
  59. package/dist/types/src/util/formatting.d.ts.map +1 -1
  60. package/package.json +29 -27
  61. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  62. package/src/components/FieldEditor/FieldEditor.tsx +7 -6
  63. package/src/components/Form/ArrayField.tsx +111 -0
  64. package/src/components/Form/Defaults.tsx +78 -34
  65. package/src/components/Form/Form.stories.tsx +15 -5
  66. package/src/components/Form/Form.tsx +50 -355
  67. package/src/components/Form/FormActions.tsx +41 -0
  68. package/src/components/Form/FormContent.tsx +170 -0
  69. package/src/components/Form/FormContext.tsx +92 -0
  70. package/src/components/Form/Input.tsx +5 -6
  71. package/src/components/Form/custom/GeoPointInput.tsx +44 -23
  72. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +58 -0
  73. package/src/components/Form/custom/SelectOptionsInput.tsx +190 -0
  74. package/src/components/Form/custom/TupleInput.tsx +5 -9
  75. package/src/components/Form/custom/index.ts +1 -0
  76. package/src/components/Form/factory.tsx +6 -7
  77. package/src/components/Form/index.ts +3 -0
  78. package/src/components/ViewEditor/ViewEditor.tsx +7 -4
  79. package/src/components/deprecated/FormInput.tsx +20 -7
  80. package/src/hooks/useForm.ts +63 -49
  81. package/src/translations.ts +9 -1
  82. package/src/util/field.ts +19 -1
  83. package/src/util/formatting.ts +29 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Form.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/deprecated/Form.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAIlE,QAAA,MAAM,YAAY,UAAW,mBAAmB,sBAM/C,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CAQnC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAKnB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC"}
1
+ {"version":3,"file":"Form.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/deprecated/Form.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5D,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAIlE,QAAA,MAAM,YAAY,UAAW,mBAAmB,4CAM/C,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,YAAY,CAQnC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAErD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAKnB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import { type JSX, type PropsWithChildren } from 'react';
2
+ import { type ThemedClassName } from '@dxos/react-ui';
3
+ /**
4
+ * @deprecated
5
+ */
6
+ export declare const DeprecatedFormContainer: ({ children, classNames }: ThemedClassName<PropsWithChildren>) => import("react/jsx-runtime").JSX.Element;
2
7
  export type DeprecatedFormInputProps = {
3
8
  label: string;
4
9
  description?: JSX.Element;
@@ -7,5 +12,5 @@ export type DeprecatedFormInputProps = {
7
12
  /**
8
13
  * @deprecated
9
14
  */
10
- export declare const DeprecatedFormInput: ({ label, description, secondary, children, }: PropsWithChildren<DeprecatedFormInputProps>) => JSX.Element;
15
+ export declare const DeprecatedFormInput: ({ label, description, secondary, children, }: PropsWithChildren<DeprecatedFormInputProps>) => import("react/jsx-runtime").JSX.Element;
11
16
  //# sourceMappingURL=FormInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormInput.d.ts","sourceRoot":"","sources":["../../../../../src/components/deprecated/FormInput.tsx"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,GAAG,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAIhE,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AAEH,eAAO,MAAM,mBAAmB,iDAK7B,iBAAiB,CAAC,wBAAwB,CAAC,gBAkC7C,CAAC"}
1
+ {"version":3,"file":"FormInput.d.ts","sourceRoot":"","sources":["../../../../../src/components/deprecated/FormInput.tsx"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,GAAG,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAS,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAG7D;;GAEG;AACH,eAAO,MAAM,uBAAuB,6BAA8B,eAAe,CAAC,iBAAiB,CAAC,4CAQnG,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,iDAK7B,iBAAiB,CAAC,wBAAwB,CAAC,4CAkC7C,CAAC"}
@@ -1,7 +1,7 @@
1
- import React, { type PropsWithChildren } from 'react';
1
+ import { type PropsWithChildren } from 'react';
2
2
  import { type ThemedClassName } from '@dxos/react-ui';
3
- export declare const TestPanel: ({ classNames, children }: ThemedClassName<PropsWithChildren>) => React.JSX.Element;
3
+ export declare const TestPanel: ({ classNames, children }: ThemedClassName<PropsWithChildren>) => import("react/jsx-runtime").JSX.Element;
4
4
  export declare const TestLayout: ({ classNames, json, children }: ThemedClassName<PropsWithChildren<{
5
5
  json?: any;
6
- }>>) => React.JSX.Element;
6
+ }>>) => import("react/jsx-runtime").JSX.Element;
7
7
  //# sourceMappingURL=testing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../src/components/testing.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,eAAO,MAAM,SAAS,6BAA8B,eAAe,CAAC,iBAAiB,CAAC,sBAIrF,CAAC;AAEF,eAAO,MAAM,UAAU,mCAAoC,eAAe,CAAC,iBAAiB,CAAC;IAAE,IAAI,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC,sBAO5G,CAAC"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../../src/components/testing.tsx"],"names":[],"mappings":"AAIA,OAAc,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,eAAO,MAAM,SAAS,6BAA8B,eAAe,CAAC,iBAAiB,CAAC,4CAIrF,CAAC;AAEF,eAAO,MAAM,UAAU,mCAAoC,eAAe,CAAC,iBAAiB,CAAC;IAAE,IAAI,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC,4CAO5G,CAAC"}
@@ -1,6 +1,5 @@
1
- import { type FocusEvent } from 'react';
2
- import { type BaseObject, type PropertyKey } from '@dxos/echo-schema';
3
- import { type SimpleType, type S } from '@dxos/effect';
1
+ import { type BaseObject } from '@dxos/echo-schema';
2
+ import { type S, type SimpleType, type JsonPath } from '@dxos/effect';
4
3
  import { type ValidationError } from '@dxos/schema';
5
4
  import { type MaybePromise } from '@dxos/util';
6
5
  /**
@@ -8,25 +7,26 @@ import { type MaybePromise } from '@dxos/util';
8
7
  */
9
8
  export type FormHandler<T extends BaseObject> = {
10
9
  values: Partial<T>;
11
- errors: Record<PropertyKey<T>, string>;
12
- touched: Record<PropertyKey<T>, boolean>;
13
- changed: Record<PropertyKey<T>, boolean>;
10
+ errors: Record<JsonPath, string>;
11
+ touched: Record<JsonPath, boolean>;
12
+ changed: Record<JsonPath, boolean>;
14
13
  canSave: boolean;
14
+ formIsValid: boolean;
15
15
  handleSave: () => void;
16
- getStatus: (property: PropertyKey<T>) => {
16
+ getStatus: (path: string | (string | number)[]) => {
17
17
  status?: 'error';
18
18
  error?: string;
19
19
  };
20
- getValue: <V>(property: PropertyKey<T>) => V | undefined;
21
- onValueChange: <V>(property: PropertyKey<T>, type: SimpleType, value: V) => void;
22
- onBlur: (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
20
+ getValue: <V>(path: (string | number)[]) => V | undefined;
21
+ onValueChange: <V>(path: (string | number)[], type: SimpleType, value: V) => void;
22
+ onTouched: (path: (string | number)[]) => void;
23
23
  };
24
24
  /**
25
25
  * Hook options.
26
26
  */
27
27
  export interface FormOptions<T extends BaseObject> {
28
28
  /**
29
- * Effect schema.
29
+ * Effect schema (Type literal).
30
30
  */
31
31
  schema: S.Schema<T>;
32
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAA6C,MAAM,OAAO,CAAC;AAEnF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,CAAC,EAAiB,MAAM,cAAc,CAAC;AAGtE,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,IAAI;IAK9C,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,IAAI,CAAC;IAMvB,SAAS,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9E,QAAQ,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IACzD,aAAa,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACjF,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,KAAK,IAAI,CAAC;CAC7E,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,UAAU;IAC/C;;OAEG;IAEH,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEpB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAE1B;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAE/C;;;;OAIG;IAEH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,eAAe,EAAE,GAAG,SAAS,CAAC;IAE1D;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5E;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;CAC1F;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,UAAU,4EAOzC,WAAW,CAAC,CAAC,CAAC,KAAG,WAAW,CAAC,CAAC,CAuIhC,CAAC"}
1
+ {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAO,KAAK,CAAC,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAA4C,MAAM,cAAc,CAAC;AAGrH,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,IAAI;IAK9C,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IAMvB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxF,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAClF,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,UAAU;IAC/C;;OAEG;IACH,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEpB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAE1B;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAE/C;;;;OAIG;IAEH,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,eAAe,EAAE,GAAG,SAAS,CAAC;IAE1D;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IAE5E;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE;QAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;KAAE,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;CAC1F;AAED;;;GAGG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,UAAU,4EAOzC,WAAW,CAAC,CAAC,CAAC,KAAG,WAAW,CAAC,CAAC,CAmJhC,CAAC"}
@@ -30,6 +30,7 @@ declare const _default: {
30
30
  'format ref': string;
31
31
  'format regex': string;
32
32
  'format string': string;
33
+ 'format single-select': string;
33
34
  'format text': string;
34
35
  'format time': string;
35
36
  'format timestamp': string;
@@ -39,6 +40,11 @@ declare const _default: {
39
40
  'format uuid': string;
40
41
  'placeholder latitude': string;
41
42
  'placeholder longitude': string;
43
+ 'select option label': string;
44
+ 'select option label placeholder': string;
45
+ 'select option color': string;
46
+ 'select option delete': string;
47
+ 'select option add': string;
42
48
  };
43
49
  };
44
50
  }[];
@@ -1 +1 @@
1
- {"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9C,wBAoDE"}
1
+ {"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9C,wBA4DE"}
@@ -1 +1 @@
1
- {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../../src/util/field.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC;CACZ,CAAC;AAEF,eAAO,MAAM,UAAU,4BAA6B,UAAU,QAoE7D,CAAC;AAGF,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,uBAAuB,qBAAsB,4BAA4B,KAAG,MAAM,EAAE,GAAG,SAiCnG,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAc,OAAO,yBAAsD,CAAC;AAGnH,eAAO,MAAM,kBAAkB,SAAU,MAAM,KAAG,eAGhD,CAAC"}
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../../src/util/field.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAe,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,GAAG,CAAC;CACZ,CAAC;AAEF,eAAO,MAAM,UAAU,4BAA6B,UAAU,QAsF7D,CAAC;AAGF,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,uBAAuB,qBAAsB,4BAA4B,KAAG,MAAM,EAAE,GAAG,SAiCnG,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAc,OAAO,yBAAsD,CAAC;AAGnH,eAAO,MAAM,kBAAkB,SAAU,MAAM,KAAG,eAGhD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../../../src/util/formatting.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEzD,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF;;;GAGG;AAGH,eAAO,MAAM,gBAAgB,oCAAiD,gBAAgB,KAAG,MA+DhG,CAAC;AAEF,eAAO,MAAM,gBAAgB,oCAAiD,gBAAgB,KAAG,MA+ChG,CAAC"}
1
+ {"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../../../src/util/formatting.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAe,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEtE,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF;;;GAGG;AAGH,eAAO,MAAM,gBAAgB,oCAAiD,gBAAgB,KAAG,MA4EhG,CAAC;AAEF,eAAO,MAAM,gBAAgB,oCAAiD,gBAAgB,KAAG,MA8DhG,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-form",
3
- "version": "0.7.5-main.9d2a38b",
3
+ "version": "0.7.5-main.b19bfc8",
4
4
  "description": "Data components.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
7
  "license": "MIT",
8
8
  "author": "DXOS.org",
9
+ "type": "module",
9
10
  "exports": {
10
11
  ".": {
11
12
  "types": "./dist/types/src/index.d.ts",
@@ -25,49 +26,50 @@
25
26
  "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
26
27
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
27
28
  "@effect/schema": "^0.75.5",
28
- "@radix-ui/react-context": "^1.0.0",
29
+ "@radix-ui/react-context": "1.1.1",
29
30
  "date-fns": "^3.3.1",
30
- "effect": "^3.12.1",
31
31
  "jsonpath": "^1.1.1",
32
- "@dxos/async": "0.7.5-main.9d2a38b",
33
- "@dxos/debug": "0.7.5-main.9d2a38b",
34
- "@dxos/echo-db": "0.7.5-main.9d2a38b",
35
- "@dxos/echo-schema": "0.7.5-main.9d2a38b",
36
- "@dxos/effect": "0.7.5-main.9d2a38b",
37
- "@dxos/keys": "0.7.5-main.9d2a38b",
38
- "@dxos/invariant": "0.7.5-main.9d2a38b",
39
- "@dxos/live-object": "0.7.5-main.9d2a38b",
40
- "@dxos/log": "0.7.5-main.9d2a38b",
41
- "@dxos/react-client": "0.7.5-main.9d2a38b",
42
- "@dxos/react-ui-list": "0.7.5-main.9d2a38b",
43
- "@dxos/schema": "0.7.5-main.9d2a38b",
44
- "@dxos/react-ui-types": "0.7.5-main.9d2a38b",
45
- "@dxos/util": "0.7.5-main.9d2a38b"
32
+ "@dxos/async": "0.7.5-main.b19bfc8",
33
+ "@dxos/echo-schema": "0.7.5-main.b19bfc8",
34
+ "@dxos/effect": "0.7.5-main.b19bfc8",
35
+ "@dxos/echo-db": "0.7.5-main.b19bfc8",
36
+ "@dxos/invariant": "0.7.5-main.b19bfc8",
37
+ "@dxos/log": "0.7.5-main.b19bfc8",
38
+ "@dxos/keys": "0.7.5-main.b19bfc8",
39
+ "@dxos/live-object": "0.7.5-main.b19bfc8",
40
+ "@dxos/debug": "0.7.5-main.b19bfc8",
41
+ "@dxos/react-client": "0.7.5-main.b19bfc8",
42
+ "@dxos/react-ui-list": "0.7.5-main.b19bfc8",
43
+ "@dxos/react-ui-pickers": "0.7.5-main.b19bfc8",
44
+ "@dxos/react-ui-types": "0.7.5-main.b19bfc8",
45
+ "@dxos/schema": "0.7.5-main.b19bfc8",
46
+ "@dxos/util": "0.7.5-main.b19bfc8"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@phosphor-icons/react": "^2.1.5",
49
- "@types/jsonpath": "~0.2.4",
50
+ "@types/jsonpath": "^0.2.4",
50
51
  "@types/react": "~18.2.0",
51
52
  "@types/react-dom": "~18.2.0",
53
+ "effect": "^3.12.3",
52
54
  "fast-check": "^3.19.0",
53
55
  "react": "~18.2.0",
54
56
  "react-dom": "~18.2.0",
55
57
  "vite": "5.4.7",
56
- "@dxos/echo-signals": "0.7.5-main.9d2a38b",
57
- "@dxos/react-ui": "0.7.5-main.9d2a38b",
58
- "@dxos/random": "0.7.5-main.9d2a38b",
59
- "@dxos/react-ui-syntax-highlighter": "0.7.5-main.9d2a38b",
60
- "@dxos/react-ui-theme": "0.7.5-main.9d2a38b",
61
- "@dxos/storybook-utils": "0.7.5-main.9d2a38b"
58
+ "@dxos/echo-signals": "0.7.5-main.b19bfc8",
59
+ "@dxos/random": "0.7.5-main.b19bfc8",
60
+ "@dxos/react-ui-syntax-highlighter": "0.7.5-main.b19bfc8",
61
+ "@dxos/react-ui-theme": "0.7.5-main.b19bfc8",
62
+ "@dxos/react-ui": "0.7.5-main.b19bfc8",
63
+ "@dxos/storybook-utils": "0.7.5-main.b19bfc8"
62
64
  },
63
65
  "peerDependencies": {
64
66
  "@effect/schema": "^0.75.5",
65
67
  "@phosphor-icons/react": "^2.1.5",
66
- "effect": "^3.9.2",
68
+ "effect": "^3.12.3",
67
69
  "react": "~18.2.0",
68
70
  "react-dom": "~18.2.0",
69
- "@dxos/react-ui": "0.7.5-main.9d2a38b",
70
- "@dxos/react-ui-theme": "0.7.5-main.9d2a38b"
71
+ "@dxos/react-ui": "0.7.5-main.b19bfc8",
72
+ "@dxos/react-ui-theme": "0.7.5-main.b19bfc8"
71
73
  },
72
74
  "publishConfig": {
73
75
  "access": "public"
@@ -37,7 +37,7 @@ const meta: Meta<StoryProps> = {
37
37
  title: 'ui/react-ui-form/FieldEditor',
38
38
  component: FieldEditor,
39
39
  render: DefaultStory,
40
- decorators: [withLayout({ fullscreen: true }), withTheme],
40
+ decorators: [withLayout({ fullscreen: true, tooltips: true }), withTheme],
41
41
  parameters: {
42
42
  translations,
43
43
  },
@@ -20,7 +20,7 @@ import {
20
20
  } from '@dxos/schema';
21
21
 
22
22
  import { translationKey } from '../../translations';
23
- import { Form, type FormProps, type InputComponent, SelectInput } from '../Form';
23
+ import { Form, type FormProps, type InputComponent, SelectInput, SelectOptionInput } from '../Form';
24
24
 
25
25
  export type FieldEditorProps = {
26
26
  view: ViewType;
@@ -95,7 +95,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
95
95
  return { ...props, ..._props, type };
96
96
  }
97
97
 
98
- return props;
98
+ return _props as PropertyType;
99
99
  });
100
100
  },
101
101
  [schemas, props.format, props.referenceSchema],
@@ -129,10 +129,10 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
129
129
  onSave();
130
130
  }, [onSave]);
131
131
 
132
- const Custom: Partial<Record<string, InputComponent<PropertyType>>> = useMemo(
132
+ const Custom: Partial<Record<string, InputComponent>> = useMemo(
133
133
  () => ({
134
134
  ['format' satisfies keyof PropertyType]: (props) => (
135
- <SelectInput<PropertyType>
135
+ <SelectInput
136
136
  {...props}
137
137
  options={FormatEnums.filter((value) => value !== FormatEnum.None).map((value) => ({
138
138
  value,
@@ -141,7 +141,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
141
141
  />
142
142
  ),
143
143
  ['referenceSchema' satisfies keyof PropertyType]: (props) => (
144
- <SelectInput<PropertyType>
144
+ <SelectInput
145
145
  {...props}
146
146
  options={schemas.map((schema) => ({
147
147
  value: schema.typename,
@@ -149,7 +149,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
149
149
  />
150
150
  ),
151
151
  ['referencePath' satisfies keyof PropertyType]: (props) => (
152
- <SelectInput<PropertyType>
152
+ <SelectInput
153
153
  {...props}
154
154
  options={
155
155
  referenceSchema
@@ -160,6 +160,7 @@ export const FieldEditor = ({ view, projection, field, registry, onSave, onCance
160
160
  }
161
161
  />
162
162
  ),
163
+ ['options' satisfies keyof PropertyType]: (props) => <SelectOptionInput {...props} />,
163
164
  }),
164
165
  [t, schemas, referenceSchema],
165
166
  );
@@ -0,0 +1,111 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { pipe } from 'effect';
6
+ import { capitalize } from 'effect/String';
7
+ import React, { useCallback, useMemo } from 'react';
8
+
9
+ import { AST } from '@dxos/echo-schema';
10
+ import { findNode, getDiscriminatedType, isDiscriminatedUnion, SimpleType } from '@dxos/effect';
11
+ import { invariant } from '@dxos/invariant';
12
+ import { IconButton, useTranslation } from '@dxos/react-ui';
13
+ import { mx } from '@dxos/react-ui-theme';
14
+ import { getSchemaProperties, type SchemaProperty } from '@dxos/schema';
15
+
16
+ import { type ComponentLookup } from './Form';
17
+ import { FormField } from './FormContent';
18
+ import { useFormValues, type FormInputStateProps } from './FormContext';
19
+ import { InputHeader, type InputComponent } from './Input';
20
+ import { translationKey } from '../../translations';
21
+
22
+ const padding = 'px-2';
23
+
24
+ type ArrayFieldProps = {
25
+ property: SchemaProperty<any>;
26
+ readonly?: boolean;
27
+ inputProps: FormInputStateProps;
28
+ path?: (string | number)[];
29
+ Custom?: Partial<Record<string, InputComponent>>;
30
+ lookupComponent?: ComponentLookup;
31
+ };
32
+
33
+ export const ArrayField = ({ property, readonly, path, inputProps, Custom, lookupComponent }: ArrayFieldProps) => {
34
+ const { t } = useTranslation(translationKey);
35
+ const { ast, name, type, title } = property;
36
+ const values = useFormValues(path ?? []) as any[];
37
+ invariant(Array.isArray(values), `Values at path ${path?.join('.')} must be an array.`);
38
+ const label = title ?? pipe(name, capitalize);
39
+
40
+ const tupleType = findNode(ast, AST.isTupleType);
41
+ const elementType = (tupleType as AST.TupleType | undefined)?.rest[0]?.type;
42
+
43
+ const getDefaultObjectValue = (typeNode: AST.AST): any => {
44
+ const baseNode = findNode(typeNode, isDiscriminatedUnion);
45
+ const typeLiteral = baseNode ? getDiscriminatedType(baseNode, {}) : findNode(typeNode, AST.isTypeLiteral);
46
+ if (!typeLiteral) {
47
+ return {};
48
+ }
49
+
50
+ return Object.fromEntries(getSchemaProperties(typeLiteral, {}).map((prop) => [prop.name, prop.defaultValue]));
51
+ };
52
+
53
+ const newValue = useMemo(() => {
54
+ if (type === 'object' && elementType) {
55
+ return getDefaultObjectValue(elementType);
56
+ } else {
57
+ return SimpleType.getDefaultValue(type);
58
+ }
59
+ }, [type, elementType]);
60
+
61
+ const handleAdd = useCallback(() => {
62
+ inputProps.onValueChange(type, [...values, newValue]);
63
+ }, [type, elementType, inputProps, newValue, values]);
64
+
65
+ const handleRemove = useCallback(
66
+ (index: number) => {
67
+ const newValues = values.filter((_, i) => i !== index);
68
+ inputProps.onValueChange(type, newValues);
69
+ },
70
+ [type, inputProps, values],
71
+ );
72
+
73
+ if (!elementType) {
74
+ return null;
75
+ }
76
+
77
+ return (
78
+ <div role='none' className={mx(padding)}>
79
+ <InputHeader>{label}</InputHeader>
80
+ <div role='none' className='flex flex-col gap-1'>
81
+ {values.map((_value, index) => (
82
+ <div key={index} role='none' className='flex items-center gap-1'>
83
+ <div role='none' className='flex-1'>
84
+ <FormField
85
+ property={{
86
+ ...property,
87
+ array: false, // NOTE(ZaymonFC): This breaks arrays of arrays but ¯\_(ツ)_/¯. Ping me if you need that.
88
+ ast: elementType,
89
+ }}
90
+ path={[...(path ?? []), index]}
91
+ readonly={readonly}
92
+ inline
93
+ Custom={Custom}
94
+ lookupComponent={lookupComponent}
95
+ />
96
+ </div>
97
+ <IconButton
98
+ icon='ph--trash--regular'
99
+ iconOnly
100
+ label={t('button remove')}
101
+ onClick={() => handleRemove(index)}
102
+ />
103
+ </div>
104
+ ))}
105
+ </div>
106
+ <div role='none' className='flex justify-between items-center plb-1'>
107
+ <IconButton icon='ph--plus--regular' iconOnly label={t('button add')} onClick={handleAdd} />
108
+ </div>
109
+ </div>
110
+ );
111
+ };
@@ -2,15 +2,13 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import React, { useCallback, useEffect, useRef } from 'react';
6
6
 
7
- import { type BaseObject } from '@dxos/echo-schema';
8
7
  import { Input, Select } from '@dxos/react-ui';
9
8
 
10
9
  import { type InputProps, InputHeader } from './Input';
11
10
 
12
- export const TextInput = <T extends BaseObject>({
13
- property,
11
+ export const TextInput = ({
14
12
  type,
15
13
  label,
16
14
  inputOnly,
@@ -20,8 +18,8 @@ export const TextInput = <T extends BaseObject>({
20
18
  getValue,
21
19
  onValueChange,
22
20
  onBlur,
23
- }: InputProps<T>) => {
24
- const { status, error } = getStatus?.(property);
21
+ }: InputProps) => {
22
+ const { status, error } = getStatus();
25
23
 
26
24
  return (
27
25
  <Input.Root validationValence={status}>
@@ -33,8 +31,8 @@ export const TextInput = <T extends BaseObject>({
33
31
  <Input.TextInput
34
32
  disabled={disabled}
35
33
  placeholder={placeholder}
36
- value={getValue(property) ?? ''}
37
- onChange={(event) => onValueChange(property, type, event.target.value)}
34
+ value={getValue() ?? ''}
35
+ onChange={(event) => onValueChange(type, event.target.value)}
38
36
  onBlur={onBlur}
39
37
  />
40
38
  {inputOnly && <Input.Validation>{error}</Input.Validation>}
@@ -42,8 +40,7 @@ export const TextInput = <T extends BaseObject>({
42
40
  );
43
41
  };
44
42
 
45
- export const NumberInput = <T extends BaseObject>({
46
- property,
43
+ export const NumberInput = ({
47
44
  type,
48
45
  label,
49
46
  inputOnly,
@@ -53,8 +50,8 @@ export const NumberInput = <T extends BaseObject>({
53
50
  getValue,
54
51
  onValueChange,
55
52
  onBlur,
56
- }: InputProps<T>) => {
57
- const { status, error } = getStatus?.(property);
53
+ }: InputProps) => {
54
+ const { status, error } = getStatus();
58
55
 
59
56
  return (
60
57
  <Input.Root validationValence={status}>
@@ -67,8 +64,8 @@ export const NumberInput = <T extends BaseObject>({
67
64
  type='number'
68
65
  disabled={disabled}
69
66
  placeholder={placeholder}
70
- value={getValue(property) ?? 0}
71
- onChange={(event) => onValueChange(property, type, event.target.value)}
67
+ value={getValue() ?? 0}
68
+ onChange={(event) => onValueChange(type, event.target.value)}
72
69
  onBlur={onBlur}
73
70
  />
74
71
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
@@ -76,16 +73,9 @@ export const NumberInput = <T extends BaseObject>({
76
73
  );
77
74
  };
78
75
 
79
- export const BooleanInput = <T extends BaseObject>({
80
- property,
81
- type,
82
- label,
83
- inputOnly,
84
- getStatus,
85
- getValue,
86
- onValueChange,
87
- }: InputProps<T>) => {
88
- const { status, error } = getStatus?.(property);
76
+ export const BooleanInput = ({ type, label, inputOnly, getStatus, getValue, onValueChange }: InputProps) => {
77
+ const { status, error } = getStatus();
78
+ const checked = Boolean(getValue());
89
79
 
90
80
  return (
91
81
  <Input.Root validationValence={status}>
@@ -94,21 +84,17 @@ export const BooleanInput = <T extends BaseObject>({
94
84
  <Input.Label>{label}</Input.Label>
95
85
  </InputHeader>
96
86
  )}
97
- <Input.Switch
98
- checked={getValue<boolean>(property)}
99
- onCheckedChange={(value) => onValueChange(property, type, value)}
100
- />
87
+ <Input.Switch checked={checked} onCheckedChange={(value) => onValueChange(type, value)} />
101
88
  {inputOnly && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
102
89
  </Input.Root>
103
90
  );
104
91
  };
105
92
 
106
- export type SelectInputOptions<T extends BaseObject> = InputProps<T> & {
93
+ export type SelectInputOptions = InputProps & {
107
94
  options?: Array<{ value: string | number; label?: string }>;
108
95
  };
109
96
 
110
- export const SelectInput = <T extends BaseObject>({
111
- property,
97
+ export const SelectInput = ({
112
98
  type,
113
99
  label,
114
100
  inputOnly,
@@ -118,8 +104,8 @@ export const SelectInput = <T extends BaseObject>({
118
104
  getStatus,
119
105
  getValue,
120
106
  onValueChange,
121
- }: SelectInputOptions<T>) => {
122
- const { status, error } = getStatus?.(property);
107
+ }: SelectInputOptions) => {
108
+ const { status, error } = getStatus();
123
109
 
124
110
  return (
125
111
  <Input.Root validationValence={status}>
@@ -128,7 +114,7 @@ export const SelectInput = <T extends BaseObject>({
128
114
  <Input.Label>{label}</Input.Label>
129
115
  </InputHeader>
130
116
  )}
131
- <Select.Root value={getValue(property)} onValueChange={(value) => onValueChange(property, type, value)}>
117
+ <Select.Root value={getValue()} onValueChange={(value) => onValueChange(type, value)}>
132
118
  {/* TODO(burdon): Placeholder not working? */}
133
119
  <Select.TriggerButton classNames='is-full' disabled={disabled} placeholder={placeholder} />
134
120
  <Select.Portal>
@@ -148,3 +134,61 @@ export const SelectInput = <T extends BaseObject>({
148
134
  </Input.Root>
149
135
  );
150
136
  };
137
+
138
+ export const MarkdownInput = ({
139
+ type,
140
+ label,
141
+ inputOnly,
142
+ disabled,
143
+ placeholder,
144
+ getStatus,
145
+ getValue,
146
+ onValueChange,
147
+ onBlur,
148
+ }: InputProps) => {
149
+ const { status, error } = getStatus();
150
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
151
+
152
+ // TODO(ZaymonFC): If we start using `Enter` for form submission, we should prevent default behavior here
153
+ // since we're using a textarea element and the user needs to be able to enter new lines.
154
+
155
+ const adjustHeight = useCallback(() => {
156
+ const textarea = textareaRef.current;
157
+ if (textarea) {
158
+ textarea.style.blockSize = 'auto'; // For measurement.
159
+ textarea.style.blockSize = `${textarea.scrollHeight + 2}px`;
160
+ }
161
+ }, []);
162
+
163
+ // Adjust height on initial render.
164
+ useEffect(() => {
165
+ adjustHeight();
166
+ }, [adjustHeight]);
167
+
168
+ // Adjust height when the content changes.
169
+ useEffect(() => {
170
+ adjustHeight();
171
+ }, [getValue(), adjustHeight]);
172
+
173
+ return (
174
+ <Input.Root validationValence={status}>
175
+ {!inputOnly && (
176
+ <InputHeader error={error}>
177
+ <Input.Label>{label}</Input.Label>
178
+ </InputHeader>
179
+ )}
180
+ <Input.TextArea
181
+ ref={textareaRef}
182
+ disabled={disabled}
183
+ placeholder={placeholder}
184
+ value={getValue() ?? ''}
185
+ classNames={'min-bs-auto max-h-40 overflow-auto'}
186
+ onChange={(event) => onValueChange(type, event.target.value)}
187
+ onBlur={onBlur}
188
+ style={{ resize: 'none' }}
189
+ spellCheck={false}
190
+ />
191
+ {inputOnly && <Input.Validation>{error}</Input.Validation>}
192
+ </Input.Root>
193
+ );
194
+ };