@dxos/react-ui-form 0.8.4-main.b97322e → 0.8.4-main.bcb3aa67d6

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 (205) hide show
  1. package/README.md +0 -1
  2. package/dist/lib/browser/index.mjs +2315 -2116
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +2315 -2116
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +8 -7
  9. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  10. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts +82 -5
  11. package/dist/types/src/components/FieldEditor/FieldEditor.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Form/Form.d.ts +84 -25
  13. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  14. package/dist/types/src/components/Form/Form.stories.d.ts +127 -55
  15. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Form/FormField.d.ts +43 -0
  17. package/dist/types/src/components/Form/FormField.d.ts.map +1 -0
  18. package/dist/types/src/components/Form/FormFieldComponent.d.ts +77 -0
  19. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +1 -0
  20. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts +9 -0
  21. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +1 -0
  22. package/dist/types/src/components/Form/FormFieldSet.d.ts +18 -0
  23. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +1 -0
  24. package/dist/types/src/components/Form/fields/ArrayField.d.ts +18 -0
  25. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +1 -0
  26. package/dist/types/src/components/Form/fields/BooleanField.d.ts +4 -0
  27. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +1 -0
  28. package/dist/types/src/components/Form/fields/GeoPointField.d.ts +5 -0
  29. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +1 -0
  30. package/dist/types/src/components/Form/fields/MarkdownField.d.ts +4 -0
  31. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +1 -0
  32. package/dist/types/src/components/Form/fields/NumberField.d.ts +4 -0
  33. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +1 -0
  34. package/dist/types/src/components/Form/fields/RefField.d.ts +16 -0
  35. package/dist/types/src/components/Form/fields/RefField.d.ts.map +1 -0
  36. package/dist/types/src/components/Form/fields/SelectField.d.ts +10 -0
  37. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +1 -0
  38. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +5 -0
  39. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +1 -0
  40. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts +82 -0
  41. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +4 -0
  43. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +1 -0
  44. package/dist/types/src/components/Form/fields/TextField.d.ts +4 -0
  45. package/dist/types/src/components/Form/fields/TextField.d.ts.map +1 -0
  46. package/dist/types/src/components/Form/fields/TupleField.d.ts +6 -0
  47. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +1 -0
  48. package/dist/types/src/components/Form/fields/index.d.ts +12 -0
  49. package/dist/types/src/components/Form/fields/index.d.ts.map +1 -0
  50. package/dist/types/src/components/Form/index.d.ts +2 -4
  51. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  52. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +54 -0
  53. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -0
  54. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts +85 -0
  55. package/dist/types/src/components/ObjectPicker/ObjectPicker.stories.d.ts.map +1 -0
  56. package/dist/types/src/components/ObjectPicker/index.d.ts +2 -0
  57. package/dist/types/src/components/ObjectPicker/index.d.ts.map +1 -0
  58. package/dist/types/src/components/Settings/Settings.d.ts +39 -0
  59. package/dist/types/src/components/Settings/Settings.d.ts.map +1 -0
  60. package/dist/types/src/components/Settings/Settings.stories.d.ts +81 -0
  61. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +1 -0
  62. package/dist/types/src/components/Settings/index.d.ts +2 -0
  63. package/dist/types/src/components/Settings/index.d.ts.map +1 -0
  64. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +22 -10
  65. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  66. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +84 -8
  67. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  68. package/dist/types/src/components/index.d.ts +2 -2
  69. package/dist/types/src/components/index.d.ts.map +1 -1
  70. package/dist/types/src/components/testing.d.ts +4 -3
  71. package/dist/types/src/components/testing.d.ts.map +1 -1
  72. package/dist/types/src/hooks/index.d.ts +2 -3
  73. package/dist/types/src/hooks/index.d.ts.map +1 -1
  74. package/dist/types/src/hooks/useFormHandler.d.ts +82 -0
  75. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -0
  76. package/dist/types/src/hooks/useKeyHandler.d.ts +6 -0
  77. package/dist/types/src/hooks/useKeyHandler.d.ts.map +1 -0
  78. package/dist/types/src/translations.d.ts +63 -54
  79. package/dist/types/src/translations.d.ts.map +1 -1
  80. package/dist/types/src/util/field.d.ts +3 -3
  81. package/dist/types/src/util/field.d.ts.map +1 -1
  82. package/dist/types/src/util/formatting.d.ts +2 -2
  83. package/dist/types/src/util/formatting.d.ts.map +1 -1
  84. package/dist/types/src/util/index.d.ts +1 -1
  85. package/dist/types/src/util/index.d.ts.map +1 -1
  86. package/dist/types/src/util/properties.d.ts +7 -0
  87. package/dist/types/src/util/properties.d.ts.map +1 -0
  88. package/dist/types/src/util/refs.d.ts +3 -3
  89. package/dist/types/src/util/refs.d.ts.map +1 -1
  90. package/dist/types/tsconfig.tsbuildinfo +1 -1
  91. package/package.json +52 -43
  92. package/src/components/FieldEditor/FieldEditor.stories.tsx +51 -32
  93. package/src/components/FieldEditor/FieldEditor.test.tsx +3 -2
  94. package/src/components/FieldEditor/FieldEditor.tsx +87 -83
  95. package/src/components/Form/AUDIT.md +17 -0
  96. package/src/components/Form/Form.stories.tsx +154 -219
  97. package/src/components/Form/Form.tsx +314 -97
  98. package/src/components/Form/FormField.tsx +305 -0
  99. package/src/components/Form/FormFieldComponent.stories.tsx +65 -0
  100. package/src/components/Form/FormFieldComponent.tsx +171 -0
  101. package/src/components/Form/FormFieldSet.tsx +129 -0
  102. package/src/components/Form/README.md +3 -0
  103. package/src/components/Form/fields/ArrayField.tsx +154 -0
  104. package/src/components/Form/fields/BooleanField.tsx +22 -0
  105. package/src/components/Form/fields/GeoPointField.tsx +120 -0
  106. package/src/components/Form/fields/MarkdownField.tsx +78 -0
  107. package/src/components/Form/fields/NumberField.tsx +39 -0
  108. package/src/components/Form/fields/RefField.tsx +199 -0
  109. package/src/components/Form/fields/SelectField.tsx +65 -0
  110. package/src/components/Form/fields/SelectOptionField.stories.tsx +64 -0
  111. package/src/components/Form/{custom/SelectOptionsInput.tsx → fields/SelectOptionField.tsx} +49 -45
  112. package/src/components/Form/fields/TextAreaField.tsx +38 -0
  113. package/src/components/Form/fields/TextField.tsx +38 -0
  114. package/src/components/Form/{custom/TupleInput.tsx → fields/TupleField.tsx} +17 -10
  115. package/src/components/Form/fields/index.ts +15 -0
  116. package/src/components/Form/index.ts +3 -4
  117. package/src/components/ObjectPicker/ObjectPicker.stories.tsx +210 -0
  118. package/src/components/ObjectPicker/ObjectPicker.tsx +186 -0
  119. package/src/components/{ControlSection → ObjectPicker}/index.ts +1 -1
  120. package/src/components/Settings/Settings.stories.tsx +56 -0
  121. package/src/components/Settings/Settings.tsx +129 -0
  122. package/src/components/Settings/index.ts +5 -0
  123. package/src/components/ViewEditor/ViewEditor.stories.tsx +141 -63
  124. package/src/components/ViewEditor/ViewEditor.test.tsx +17 -18
  125. package/src/components/ViewEditor/ViewEditor.tsx +353 -203
  126. package/src/components/index.ts +2 -3
  127. package/src/components/testing.tsx +33 -13
  128. package/src/hooks/index.ts +2 -3
  129. package/src/hooks/useFormHandler.ts +380 -0
  130. package/src/hooks/useKeyHandler.tsx +37 -0
  131. package/src/translations.ts +66 -58
  132. package/src/util/field.ts +33 -43
  133. package/src/util/formatting.ts +22 -22
  134. package/src/util/index.ts +1 -1
  135. package/src/util/properties.ts +18 -0
  136. package/src/util/refs.ts +17 -19
  137. package/dist/types/src/components/ControlSection/ControlSection.d.ts +0 -23
  138. package/dist/types/src/components/ControlSection/ControlSection.d.ts.map +0 -1
  139. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts +0 -8
  140. package/dist/types/src/components/ControlSection/ControlSection.stories.d.ts.map +0 -1
  141. package/dist/types/src/components/ControlSection/index.d.ts +0 -2
  142. package/dist/types/src/components/ControlSection/index.d.ts.map +0 -1
  143. package/dist/types/src/components/Form/ArrayField.d.ts +0 -16
  144. package/dist/types/src/components/Form/ArrayField.d.ts.map +0 -1
  145. package/dist/types/src/components/Form/Defaults.d.ts +0 -14
  146. package/dist/types/src/components/Form/Defaults.d.ts.map +0 -1
  147. package/dist/types/src/components/Form/FormActions.d.ts +0 -9
  148. package/dist/types/src/components/Form/FormActions.d.ts.map +0 -1
  149. package/dist/types/src/components/Form/FormContent.d.ts +0 -57
  150. package/dist/types/src/components/Form/FormContent.d.ts.map +0 -1
  151. package/dist/types/src/components/Form/FormContext.d.ts +0 -23
  152. package/dist/types/src/components/Form/FormContext.d.ts.map +0 -1
  153. package/dist/types/src/components/Form/Input.d.ts +0 -26
  154. package/dist/types/src/components/Form/Input.d.ts.map +0 -1
  155. package/dist/types/src/components/Form/RefField.d.ts +0 -12
  156. package/dist/types/src/components/Form/RefField.d.ts.map +0 -1
  157. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts +0 -4
  158. package/dist/types/src/components/Form/custom/GeoPointInput.d.ts.map +0 -1
  159. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts +0 -4
  160. package/dist/types/src/components/Form/custom/SelectOptionsInput.d.ts.map +0 -1
  161. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts +0 -7
  162. package/dist/types/src/components/Form/custom/SelectOptionsInput.stories.d.ts.map +0 -1
  163. package/dist/types/src/components/Form/custom/TupleInput.d.ts +0 -6
  164. package/dist/types/src/components/Form/custom/TupleInput.d.ts.map +0 -1
  165. package/dist/types/src/components/Form/custom/index.d.ts +0 -4
  166. package/dist/types/src/components/Form/custom/index.d.ts.map +0 -1
  167. package/dist/types/src/components/Form/factory.d.ts +0 -8
  168. package/dist/types/src/components/Form/factory.d.ts.map +0 -1
  169. package/dist/types/src/components/deprecated/Form.d.ts +0 -15
  170. package/dist/types/src/components/deprecated/Form.d.ts.map +0 -1
  171. package/dist/types/src/components/deprecated/Form.stories.d.ts +0 -13
  172. package/dist/types/src/components/deprecated/Form.stories.d.ts.map +0 -1
  173. package/dist/types/src/components/deprecated/FormInput.d.ts +0 -16
  174. package/dist/types/src/components/deprecated/FormInput.d.ts.map +0 -1
  175. package/dist/types/src/components/deprecated/index.d.ts +0 -2
  176. package/dist/types/src/components/deprecated/index.d.ts.map +0 -1
  177. package/dist/types/src/hooks/useForm.d.ts +0 -67
  178. package/dist/types/src/hooks/useForm.d.ts.map +0 -1
  179. package/dist/types/src/hooks/useQueryRefOptions.d.ts +0 -23
  180. package/dist/types/src/hooks/useQueryRefOptions.d.ts.map +0 -1
  181. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts +0 -8
  182. package/dist/types/src/hooks/useRefQueryLookupHandler.d.ts.map +0 -1
  183. package/dist/types/src/util/schema.d.ts +0 -3
  184. package/dist/types/src/util/schema.d.ts.map +0 -1
  185. package/src/components/ControlSection/ControlSection.stories.tsx +0 -41
  186. package/src/components/ControlSection/ControlSection.tsx +0 -139
  187. package/src/components/Form/ArrayField.tsx +0 -124
  188. package/src/components/Form/Defaults.tsx +0 -203
  189. package/src/components/Form/FormActions.tsx +0 -53
  190. package/src/components/Form/FormContent.tsx +0 -240
  191. package/src/components/Form/FormContext.tsx +0 -110
  192. package/src/components/Form/Input.tsx +0 -51
  193. package/src/components/Form/RefField.tsx +0 -213
  194. package/src/components/Form/custom/GeoPointInput.tsx +0 -72
  195. package/src/components/Form/custom/SelectOptionsInput.stories.tsx +0 -61
  196. package/src/components/Form/custom/index.ts +0 -7
  197. package/src/components/Form/factory.tsx +0 -31
  198. package/src/components/deprecated/Form.stories.tsx +0 -62
  199. package/src/components/deprecated/Form.tsx +0 -119
  200. package/src/components/deprecated/FormInput.tsx +0 -71
  201. package/src/components/deprecated/index.ts +0 -5
  202. package/src/hooks/useForm.ts +0 -291
  203. package/src/hooks/useQueryRefOptions.ts +0 -53
  204. package/src/hooks/useRefQueryLookupHandler.ts +0 -39
  205. package/src/util/schema.ts +0 -14
package/package.json CHANGED
@@ -1,14 +1,19 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-form",
3
- "version": "0.8.4-main.b97322e",
3
+ "version": "0.8.4-main.bcb3aa67d6",
4
4
  "description": "Data components.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
13
  "type": "module",
10
14
  "exports": {
11
15
  ".": {
16
+ "source": "./src/index.ts",
12
17
  "types": "./dist/types/src/index.d.ts",
13
18
  "browser": "./dist/lib/browser/index.mjs",
14
19
  "node": "./dist/lib/node-esm/index.mjs"
@@ -23,54 +28,58 @@
23
28
  "src"
24
29
  ],
25
30
  "dependencies": {
26
- "@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
27
- "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
28
- "@preact-signals/safe-react": "^0.9.0",
31
+ "@atlaskit/pragmatic-drag-and-drop": "1.7.7",
32
+ "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
33
+ "@effect-atom/atom-react": "^0.5.0",
34
+ "@fluentui/react-tabster": "9.26.11",
29
35
  "@radix-ui/react-context": "1.1.1",
30
- "date-fns": "^3.3.1",
31
- "jsonpath": "^1.1.1",
32
- "@dxos/async": "0.8.4-main.b97322e",
33
- "@dxos/debug": "0.8.4-main.b97322e",
34
- "@dxos/echo-schema": "0.8.4-main.b97322e",
35
- "@dxos/echo": "0.8.4-main.b97322e",
36
- "@dxos/echo-db": "0.8.4-main.b97322e",
37
- "@dxos/effect": "0.8.4-main.b97322e",
38
- "@dxos/invariant": "0.8.4-main.b97322e",
39
- "@dxos/keys": "0.8.4-main.b97322e",
40
- "@dxos/lit-ui": "0.8.4-main.b97322e",
41
- "@dxos/log": "0.8.4-main.b97322e",
42
- "@dxos/react-client": "0.8.4-main.b97322e",
43
- "@dxos/live-object": "0.8.4-main.b97322e",
44
- "@dxos/react-ui-list": "0.8.4-main.b97322e",
45
- "@dxos/react-ui-stack": "0.8.4-main.b97322e",
46
- "@dxos/react-ui-pickers": "0.8.4-main.b97322e",
47
- "@dxos/react-ui-types": "0.8.4-main.b97322e",
48
- "@dxos/react-ui-tag-picker": "0.8.4-main.b97322e",
49
- "@dxos/schema": "0.8.4-main.b97322e",
50
- "@dxos/util": "0.8.4-main.b97322e"
36
+ "@radix-ui/react-use-controllable-state": "1.1.0",
37
+ "date-fns": "^3.6.0",
38
+ "tabster": "^8.5.5",
39
+ "@dxos/async": "0.8.4-main.bcb3aa67d6",
40
+ "@dxos/debug": "0.8.4-main.bcb3aa67d6",
41
+ "@dxos/echo": "0.8.4-main.bcb3aa67d6",
42
+ "@dxos/effect": "0.8.4-main.bcb3aa67d6",
43
+ "@dxos/echo-query": "0.8.4-main.bcb3aa67d6",
44
+ "@dxos/invariant": "0.8.4-main.bcb3aa67d6",
45
+ "@dxos/lit-ui": "0.8.4-main.bcb3aa67d6",
46
+ "@dxos/keys": "0.8.4-main.bcb3aa67d6",
47
+ "@dxos/echo-react": "0.8.4-main.bcb3aa67d6",
48
+ "@dxos/log": "0.8.4-main.bcb3aa67d6",
49
+ "@dxos/react-client": "0.8.4-main.bcb3aa67d6",
50
+ "@dxos/react-ui-components": "0.8.4-main.bcb3aa67d6",
51
+ "@dxos/react-ui-editor": "0.8.4-main.bcb3aa67d6",
52
+ "@dxos/react-ui-list": "0.8.4-main.bcb3aa67d6",
53
+ "@dxos/react-ui-pickers": "0.8.4-main.bcb3aa67d6",
54
+ "@dxos/react-ui-mosaic": "0.8.4-main.bcb3aa67d6",
55
+ "@dxos/react-ui-search": "0.8.4-main.bcb3aa67d6",
56
+ "@dxos/react-ui-stack": "0.8.4-main.bcb3aa67d6",
57
+ "@dxos/schema": "0.8.4-main.bcb3aa67d6",
58
+ "@dxos/ui-types": "0.8.4-main.bcb3aa67d6",
59
+ "@dxos/types": "0.8.4-main.bcb3aa67d6",
60
+ "@dxos/util": "0.8.4-main.bcb3aa67d6"
51
61
  },
52
62
  "devDependencies": {
53
- "@types/jsonpath": "^0.2.4",
54
- "@types/react": "~18.2.0",
55
- "@types/react-dom": "~18.2.0",
56
- "effect": "3.17.0",
63
+ "@types/react": "~19.2.7",
64
+ "@types/react-dom": "~19.2.3",
65
+ "effect": "3.20.0",
57
66
  "fast-check": "^3.19.0",
58
- "react": "~18.2.0",
59
- "react-dom": "~18.2.0",
60
- "vite": "5.4.7",
61
- "@dxos/echo-signals": "0.8.4-main.b97322e",
62
- "@dxos/random": "0.8.4-main.b97322e",
63
- "@dxos/react-ui": "0.8.4-main.b97322e",
64
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.b97322e",
65
- "@dxos/storybook-utils": "0.8.4-main.b97322e",
66
- "@dxos/react-ui-theme": "0.8.4-main.b97322e"
67
+ "react": "~19.2.3",
68
+ "react-dom": "~19.2.3",
69
+ "vite": "^7.1.11",
70
+ "@dxos/react-client": "0.8.4-main.bcb3aa67d6",
71
+ "@dxos/random": "0.8.4-main.bcb3aa67d6",
72
+ "@dxos/react-ui": "0.8.4-main.bcb3aa67d6",
73
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.bcb3aa67d6",
74
+ "@dxos/ui-theme": "0.8.4-main.bcb3aa67d6",
75
+ "@dxos/storybook-utils": "0.8.4-main.bcb3aa67d6"
67
76
  },
68
77
  "peerDependencies": {
69
- "effect": "^3.13.3",
70
- "react": "~18.2.0",
71
- "react-dom": "~18.2.0",
72
- "@dxos/react-ui": "0.8.4-main.b97322e",
73
- "@dxos/react-ui-theme": "0.8.4-main.b97322e"
78
+ "effect": "3.20.0",
79
+ "react": "~19.2.3",
80
+ "react-dom": "~19.2.3",
81
+ "@dxos/react-ui": "0.8.4-main.bcb3aa67d6",
82
+ "@dxos/ui-theme": "0.8.4-main.bcb3aa67d6"
74
83
  },
75
84
  "publishConfig": {
76
85
  "access": "public"
@@ -2,32 +2,55 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
- import React, { useMemo, useEffect } from 'react';
6
+ import React, { useEffect, useMemo } from 'react';
9
7
 
10
- import { createEchoSchema } from '@dxos/live-object/testing';
8
+ import { Filter, Query } from '@dxos/echo';
9
+ import { createEchoSchema } from '@dxos/echo/testing';
11
10
  import { log } from '@dxos/log';
12
- import { ProjectionModel } from '@dxos/schema';
13
- import { TestSchema, testView } from '@dxos/schema/testing';
14
- import { withLayout, withTheme } from '@dxos/storybook-utils';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+ import { ProjectionModel, ViewModel, createEchoChangeCallback } from '@dxos/schema';
13
+ import { Example } from '@dxos/schema/testing';
15
14
 
16
- import { FieldEditor, type FieldEditorProps } from './FieldEditor';
17
15
  import { translations } from '../../translations';
18
- import { TestLayout, TestPanel, FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
16
+ import { FIELD_EDITOR_DEBUG_SYMBOL, TestLayout } from '../testing';
17
+
18
+ import { FieldEditor, type FieldEditorProps } from './FieldEditor';
19
19
 
20
- // Type definition for debug objects exposed to tests.
21
20
  export type FieldEditorDebugObjects = {
22
21
  props: FieldEditorProps;
23
22
  projection: ProjectionModel;
24
23
  };
25
24
 
26
- type StoryProps = FieldEditorProps;
25
+ const useTestProjection = () => {
26
+ return useMemo(() => {
27
+ const schema = createEchoSchema(Example);
28
+ const view = ViewModel.make({
29
+ name: 'Test',
30
+ query: Query.select(Filter.type(Example)),
31
+ jsonSchema: schema.jsonSchema,
32
+ });
33
+ const projection = new ProjectionModel({
34
+ view,
35
+ baseSchema: schema.jsonSchema,
36
+ change: createEchoChangeCallback(view, schema),
37
+ });
38
+ projection.normalizeView();
39
+ return { view, projection };
40
+ }, []);
41
+ };
42
+
43
+ const DefaultStory = () => {
44
+ const { view, projection } = useTestProjection();
27
45
 
28
- const DefaultStory = (props: FieldEditorProps) => {
29
46
  const handleComplete: FieldEditorProps['onSave'] = () => {
30
- log.info('onClose', { props });
47
+ log.info('onClose');
48
+ };
49
+
50
+ const props: FieldEditorProps = {
51
+ projection,
52
+ field: view.projection.fields[0],
53
+ onSave: handleComplete,
31
54
  };
32
55
 
33
56
  // Expose objects on window for test access.
@@ -35,44 +58,40 @@ const DefaultStory = (props: FieldEditorProps) => {
35
58
  if (typeof window !== 'undefined') {
36
59
  (window as any)[FIELD_EDITOR_DEBUG_SYMBOL] = {
37
60
  props,
38
- projection: props.projection,
61
+ projection,
39
62
  } satisfies FieldEditorDebugObjects;
40
63
  }
41
- }, [props, props.projection]);
64
+ }, [props, projection]);
42
65
 
43
66
  // NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
44
67
  const json = useMemo(
45
- () => JSON.parse(JSON.stringify({ props, projection: props.projection })),
46
- [JSON.stringify(props), JSON.stringify(props.projection)],
68
+ () => JSON.parse(JSON.stringify({ props, projection })),
69
+ [JSON.stringify(props), JSON.stringify(projection)],
47
70
  );
48
71
 
49
72
  return (
50
73
  <TestLayout json={json}>
51
- <TestPanel>
52
- <FieldEditor {...props} onSave={handleComplete} />
53
- </TestPanel>
74
+ <FieldEditor {...props} />
54
75
  </TestLayout>
55
76
  );
56
77
  };
57
78
 
58
- const meta: Meta<StoryProps> = {
79
+ const meta = {
59
80
  title: 'ui/react-ui-form/FieldEditor',
60
- component: FieldEditor,
81
+ component: FieldEditor as any,
61
82
  render: DefaultStory,
62
- decorators: [withLayout({ fullscreen: true }), withTheme],
83
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
63
84
  parameters: {
85
+ layout: 'fullscreen',
64
86
  translations,
87
+ controls: {
88
+ disabled: true,
89
+ },
65
90
  },
66
- };
91
+ } satisfies Meta<typeof DefaultStory>;
67
92
 
68
93
  export default meta;
69
94
 
70
- type Story = StoryObj<StoryProps>;
95
+ type Story = StoryObj<typeof meta>;
71
96
 
72
- export const Default: Story = {
73
- args: {
74
- projection: new ProjectionModel(createEchoSchema(TestSchema).jsonSchema, testView.projection),
75
- field: testView.projection.fields[0],
76
- },
77
- parameters: { controls: { disabled: true } },
78
- };
97
+ export const Default: Story = {};
@@ -3,14 +3,15 @@
3
3
  //
4
4
 
5
5
  import { composeStories } from '@storybook/react';
6
- import { screen, cleanup, fireEvent, act } from '@testing-library/react';
6
+ import { act, cleanup, fireEvent, screen } from '@testing-library/react';
7
7
  import { afterEach, describe, expect, test } from 'vitest';
8
8
 
9
9
  import { ProjectionModel } from '@dxos/schema';
10
10
 
11
+ import { FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
12
+
11
13
  import * as stories from './FieldEditor.stories';
12
14
  import { type FieldEditorDebugObjects } from './FieldEditor.stories';
13
- import { FIELD_EDITOR_DEBUG_SYMBOL } from '../testing';
14
15
 
15
16
  const { Default } = composeStories(stories);
16
17
 
@@ -4,41 +4,41 @@
4
4
 
5
5
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
6
 
7
- import { type SchemaRegistry } from '@dxos/echo-db';
8
- import { FormatEnum, FormatEnums, formatToType, type EchoSchema } from '@dxos/echo-schema';
7
+ import { Obj, type SchemaRegistry, type View } from '@dxos/echo';
8
+ import { type EchoSchema, Format, FormatEnums, formatToType } from '@dxos/echo/internal';
9
+ import { type SchemaProperty } from '@dxos/effect';
9
10
  import { log } from '@dxos/log';
10
- import { useTranslation } from '@dxos/react-ui';
11
+ import { useAsyncEffect, useTranslation } from '@dxos/react-ui';
11
12
  import {
12
- getFormatSchema,
13
- getSchemaProperties,
14
- sortProperties,
15
- type FieldType,
16
- type PropertyType,
17
13
  type ProjectionModel,
18
- type SchemaProperty,
14
+ type PropertyType,
15
+ formatToAdditionalPropertyAttributes,
16
+ getFormatSchema,
19
17
  } from '@dxos/schema';
20
18
 
21
19
  import { translationKey } from '../../translations';
22
- import { Form, type FormProps, type InputComponent, SelectInput, SelectOptionInput } from '../Form';
20
+ import { getFormProperties } from '../../util';
21
+ import { Form, type FormFieldMap, type FormRootProps, SelectField, SelectOptionField } from '../Form';
23
22
 
24
23
  export type FieldEditorProps = {
25
24
  projection: ProjectionModel;
26
- field: FieldType;
27
- registry?: SchemaRegistry;
25
+ field: View.FieldType;
26
+ registry?: SchemaRegistry.SchemaRegistry;
27
+ view?: Obj.Unknown;
28
28
  onSave: () => void;
29
29
  onCancel?: () => void;
30
- } & Pick<FormProps<any>, 'outerSpacing'>;
30
+ } & Pick<FormRootProps<any>, 'readonly'>;
31
31
 
32
32
  /**
33
33
  * Displays a Form representing the metadata for a given `Field` and `View`.
34
34
  */
35
- export const FieldEditor = ({ projection, field, registry, onSave, onCancel, outerSpacing }: FieldEditorProps) => {
35
+ export const FieldEditor = ({ readonly, projection, field, registry, view, onSave, onCancel }: FieldEditorProps) => {
36
36
  const { t } = useTranslation(translationKey);
37
37
  const [props, setProps] = useState<PropertyType>(projection.getFieldProjection(field.id).props);
38
38
  useEffect(() => setProps(projection.getFieldProjection(field.id).props), [field, projection]);
39
39
 
40
40
  const [schemas, setSchemas] = useState<EchoSchema[]>([]);
41
- useEffect(() => {
41
+ useAsyncEffect(async () => {
42
42
  if (!registry) {
43
43
  return;
44
44
  }
@@ -46,14 +46,10 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
46
46
  const subscription = registry.query().subscribe((query) => setSchemas(query.results), { fire: true });
47
47
 
48
48
  // TODO(dmaretskyi): This shouldn't be needed.
49
- const t = setTimeout(async () => {
50
- const schemas = await registry.query().run();
51
- setSchemas(schemas);
52
- });
53
- return () => {
54
- clearTimeout(t);
55
- subscription?.();
56
- };
49
+ const schemas = await registry.query().run();
50
+ setSchemas(schemas);
51
+
52
+ return () => subscription?.();
57
53
  }, [registry]);
58
54
 
59
55
  const [referenceSchema, setReferenceSchema] = useState<EchoSchema>();
@@ -65,11 +61,47 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
65
61
  // Class constructor SchemaClass cannot be invoked without 'new'.
66
62
  const [{ fieldSchema }, setFieldSchema] = useState({ fieldSchema: getFormatSchema(props?.format) });
67
63
 
68
- const handleValuesChanged = useCallback<NonNullable<FormProps<PropertyType>['onValuesChanged']>>(
64
+ const fieldMap = useMemo<FormFieldMap>(
65
+ () => ({
66
+ ['format' satisfies keyof PropertyType]: (props) => (
67
+ <SelectField
68
+ {...props}
69
+ options={FormatEnums.filter((value) => value !== Format.TypeFormat.None).map((value) => ({
70
+ value,
71
+ label: t(`format.${value}.label`),
72
+ }))}
73
+ />
74
+ ),
75
+ ['referenceSchema' satisfies keyof PropertyType]: (props) => (
76
+ <SelectField
77
+ {...props}
78
+ options={schemas.map((schema) => ({
79
+ value: schema.typename,
80
+ }))}
81
+ />
82
+ ),
83
+ ['referencePath' satisfies keyof PropertyType]: (props) => (
84
+ <SelectField
85
+ {...props}
86
+ options={
87
+ referenceSchema
88
+ ? getFormProperties(referenceSchema.ast)
89
+ .sort((a, b) => a.name.toString().localeCompare(b.name.toString()))
90
+ .map((p) => ({ value: p.name.toString() }))
91
+ : []
92
+ }
93
+ />
94
+ ),
95
+ ['options' satisfies keyof PropertyType]: (props) => <SelectOptionField {...props} />,
96
+ }),
97
+ [t, schemas, referenceSchema],
98
+ );
99
+
100
+ const propIsNotType = useCallback((props: SchemaProperty[]) => props.filter((prop) => prop.name !== 'type'), []);
101
+
102
+ const handleValuesChanged = useCallback<NonNullable<FormRootProps<PropertyType>['onValuesChanged']>>(
69
103
  (_props) => {
70
- // TODO(burdon): Callback should pass `changed` to indicate which fields have changed.
71
- // TODO(Zaymon): Workout why old and new format values are the same sometimes even when
72
- // selecting novel format values.
104
+ // TODO(Zaymon): Workout why old and new format values are the same sometimes even when selecting novel format values.
73
105
  setFieldSchema((prev) => {
74
106
  const fieldSchema = getFormatSchema(_props.format);
75
107
  if (prev.fieldSchema === fieldSchema) {
@@ -90,8 +122,10 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
90
122
 
91
123
  setProps((props) => {
92
124
  const type = formatToType[_props.format as keyof typeof formatToType];
125
+ const additionalProps =
126
+ formatToAdditionalPropertyAttributes[_props.format as keyof typeof formatToAdditionalPropertyAttributes];
93
127
  if (props.type !== type) {
94
- return { ...props, ..._props, type };
128
+ return { ...props, ..._props, ...additionalProps, type } as PropertyType;
95
129
  }
96
130
 
97
131
  return _props as PropertyType;
@@ -100,9 +134,9 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
100
134
  [schemas, props.format, props.referenceSchema],
101
135
  );
102
136
 
103
- const handleValidate = useCallback<NonNullable<FormProps<PropertyType>['onValidate']>>(
137
+ const handleValidate = useCallback<NonNullable<FormRootProps<PropertyType>['onValidate']>>(
104
138
  ({ property }) => {
105
- if (property && projection.fields.find((f) => f.path === property && f.path !== field.path)) {
139
+ if (property && projection.getFields().find((f) => f.path === property && f.path !== field.path)) {
106
140
  return [
107
141
  {
108
142
  path: 'property',
@@ -111,83 +145,53 @@ export const FieldEditor = ({ projection, field, registry, onSave, onCancel, out
111
145
  ];
112
146
  }
113
147
  },
114
- [projection.fields, field],
148
+ [projection.getFields(), field],
115
149
  );
116
150
 
117
- const handleSave = useCallback<NonNullable<FormProps<PropertyType>['onSave']>>(
151
+ const handleSave = useCallback<NonNullable<FormRootProps<PropertyType>['onSave']>>(
118
152
  (props) => {
119
- projection.setFieldProjection({ field, props });
153
+ if (view) {
154
+ Obj.change(view, () => {
155
+ projection.setFieldProjection({ field, props });
156
+ });
157
+ } else {
158
+ projection.setFieldProjection({ field, props });
159
+ }
120
160
  onSave();
121
161
  },
122
- [projection, field, onSave],
162
+ [projection, field, view, onSave],
123
163
  );
124
164
 
125
- const handleCancel = useCallback<NonNullable<FormProps<PropertyType>['onCancel']>>(() => {
165
+ const handleCancel = useCallback<NonNullable<FormRootProps<PropertyType>['onCancel']>>(() => {
166
+ onSave();
126
167
  // Need to defer to allow form to close.
127
168
  requestAnimationFrame(() => onCancel?.());
128
- onSave();
129
169
  }, [onSave]);
130
170
 
131
- const custom: Partial<Record<string, InputComponent>> = useMemo(
132
- () => ({
133
- ['format' satisfies keyof PropertyType]: (props) => (
134
- <SelectInput
135
- {...props}
136
- options={FormatEnums.filter((value) => value !== FormatEnum.None).map((value) => ({
137
- value,
138
- label: t(`format ${value}`),
139
- }))}
140
- />
141
- ),
142
- ['referenceSchema' satisfies keyof PropertyType]: (props) => (
143
- <SelectInput
144
- {...props}
145
- options={schemas.map((schema) => ({
146
- value: schema.typename,
147
- }))}
148
- />
149
- ),
150
- ['referencePath' satisfies keyof PropertyType]: (props) => (
151
- <SelectInput
152
- {...props}
153
- options={
154
- referenceSchema
155
- ? getSchemaProperties(referenceSchema.ast)
156
- .sort(sortProperties)
157
- .map((p) => ({ value: p.name }))
158
- : []
159
- }
160
- />
161
- ),
162
- ['options' satisfies keyof PropertyType]: (props) => <SelectOptionInput {...props} />,
163
- }),
164
- [t, schemas, referenceSchema],
165
- );
166
-
167
- const propIsNotType = useCallback(
168
- (props: SchemaProperty<PropertyType>[]) => props.filter((p) => p.name !== 'type'),
169
- [],
170
- );
171
-
172
171
  if (!fieldSchema) {
173
172
  log.warn('invalid format', { props });
174
173
  return null;
175
174
  }
176
175
 
177
176
  return (
178
- <Form<PropertyType>
177
+ <Form.Root<PropertyType>
179
178
  key={field.id}
179
+ fieldMap={fieldMap}
180
180
  autoFocus
181
- values={props}
181
+ readonly={readonly}
182
182
  schema={fieldSchema}
183
- filter={propIsNotType}
183
+ values={props}
184
+ exclude={propIsNotType}
184
185
  sort={['property', 'format']}
185
186
  onValuesChanged={handleValuesChanged}
186
187
  onValidate={handleValidate}
187
188
  onSave={handleSave}
188
189
  onCancel={handleCancel}
189
- Custom={custom}
190
- outerSpacing={outerSpacing}
191
- />
190
+ >
191
+ <Form.Content>
192
+ <Form.FieldSet />
193
+ <Form.Actions />
194
+ </Form.Content>
195
+ </Form.Root>
192
196
  );
193
197
  };
@@ -0,0 +1,17 @@
1
+ # Form
2
+
3
+ ## New features/polish
4
+
5
+ - [x] Unify readonly/inline modes.
6
+ - [x] Refs
7
+ - [x] Single-select (fix popover)
8
+ - [x] Multi-select (array)
9
+ - [ ] auto save doesn't work for combobox + select due to only firing on blur (workaround is to use onValuesChanged).
10
+ - [ ] Don't call save/autoSave if value hasn't changed.
11
+ - [ ] Fix onCancel (restore values).
12
+ - [ ] Fix useSchema Type.AnyObj cast.
13
+ - [ ] TableCellEditor (handleEnter/ModalController).
14
+ - [ ] Use FormFieldWrapper uniformly
15
+ - [ ] Inline tables.
16
+ - [ ] Defer query until popover.
17
+ - [ ] Omit id from sub properties (tune Omit)