@dxos/react-ui-form 0.9.0 → 0.9.1-main.c7dcc2e112

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 (282) hide show
  1. package/dist/lib/browser/index.mjs +2221 -2147
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +2221 -2147
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +3 -3
  8. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  9. package/dist/types/src/components/Form/Form.d.ts +15 -110
  10. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  11. package/dist/types/src/components/Form/Form.stories.d.ts +3 -37
  12. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/FormControls.d.ts +66 -0
  14. package/dist/types/src/components/Form/FormControls.d.ts.map +1 -0
  15. package/dist/types/src/components/Form/FormField/FieldHeader.d.ts +19 -0
  16. package/dist/types/src/components/Form/FormField/FieldHeader.d.ts.map +1 -0
  17. package/dist/types/src/components/Form/FormField/FormField.d.ts +30 -0
  18. package/dist/types/src/components/Form/FormField/FormField.d.ts.map +1 -0
  19. package/dist/types/src/components/Form/FormField/FormFieldWrapper.d.ts +47 -0
  20. package/dist/types/src/components/Form/FormField/FormFieldWrapper.d.ts.map +1 -0
  21. package/dist/types/src/components/Form/{FormFieldComponent.stories.d.ts → FormField/FormFieldWrapper.stories.d.ts} +3 -3
  22. package/dist/types/src/components/Form/FormField/FormFieldWrapper.stories.d.ts.map +1 -0
  23. package/dist/types/src/components/Form/{fields → FormField/fields/ArrayField}/ArrayField.d.ts +2 -2
  24. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.d.ts.map +1 -0
  25. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts +87 -0
  26. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts.map +1 -0
  27. package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts +2 -0
  28. package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts.map +1 -0
  29. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts +4 -0
  30. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts.map +1 -0
  31. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.d.ts +88 -0
  32. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts +2 -0
  34. package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts.map +1 -0
  35. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts +4 -0
  36. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts.map +1 -0
  37. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts +88 -0
  38. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts +2 -0
  40. package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts.map +1 -0
  41. package/dist/types/src/components/Form/{fields → FormField/fields/GeoPointField}/GeoPointField.d.ts +2 -2
  42. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts.map +1 -0
  43. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts +88 -0
  44. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts.map +1 -0
  45. package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts +2 -0
  46. package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts.map +1 -0
  47. package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.d.ts +2 -2
  48. package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.d.ts.map +1 -0
  49. package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.stories.d.ts.map +1 -0
  50. package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts +2 -0
  51. package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts.map +1 -0
  52. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts +4 -0
  53. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts.map +1 -0
  54. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts +88 -0
  55. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts.map +1 -0
  56. package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts +2 -0
  57. package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts.map +1 -0
  58. package/dist/types/src/components/Form/FormField/fields/RefField/InlineRefField.d.ts.map +1 -0
  59. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts +16 -0
  60. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts.map +1 -0
  61. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts +92 -0
  62. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts.map +1 -0
  63. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.test.d.ts.map +1 -0
  64. package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts +3 -0
  65. package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts.map +1 -0
  66. package/dist/types/src/components/Form/{fields → FormField/fields/SelectField}/SelectField.d.ts +2 -2
  67. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts.map +1 -0
  68. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts +88 -0
  69. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts.map +1 -0
  70. package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts +2 -0
  71. package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts.map +1 -0
  72. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts +5 -0
  73. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts.map +1 -0
  74. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.stories.d.ts.map +1 -0
  75. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts +2 -0
  76. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts.map +1 -0
  77. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts +4 -0
  78. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts.map +1 -0
  79. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts +88 -0
  80. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts.map +1 -0
  81. package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts +2 -0
  82. package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts.map +1 -0
  83. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts +4 -0
  84. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts.map +1 -0
  85. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts +88 -0
  86. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts.map +1 -0
  87. package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts +2 -0
  88. package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts.map +1 -0
  89. package/dist/types/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.d.ts +2 -2
  90. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.d.ts.map +1 -0
  91. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts +88 -0
  92. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts.map +1 -0
  93. package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts +2 -0
  94. package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts.map +1 -0
  95. package/dist/types/src/components/Form/{fields → FormField/fields}/index.d.ts +0 -1
  96. package/dist/types/src/components/Form/FormField/fields/index.d.ts.map +1 -0
  97. package/dist/types/src/components/Form/FormField/index.d.ts +5 -0
  98. package/dist/types/src/components/Form/FormField/index.d.ts.map +1 -0
  99. package/dist/types/src/components/Form/{FormFieldSet.d.ts → FormFieldSet/FormFieldSet.d.ts} +4 -3
  100. package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts.map +1 -0
  101. package/dist/types/src/components/Form/FormFieldSet/index.d.ts +2 -0
  102. package/dist/types/src/components/Form/FormFieldSet/index.d.ts.map +1 -0
  103. package/dist/types/src/components/Form/FormLayout/FormLayout.d.ts.map +1 -0
  104. package/dist/types/src/components/Form/FormLayout/FormLayout.stories.d.ts.map +1 -0
  105. package/dist/types/src/components/Form/FormLayout/FormLayout.stories.test.d.ts.map +1 -0
  106. package/dist/types/src/components/Form/FormLayout/FormLayout.test.d.ts.map +1 -0
  107. package/dist/types/src/components/Form/FormLayout/index.d.ts +3 -0
  108. package/dist/types/src/components/Form/FormLayout/index.d.ts.map +1 -0
  109. package/dist/types/src/components/Form/FormLayout/parser.d.ts.map +1 -0
  110. package/dist/types/src/components/Form/FormLayout/parser.test.d.ts.map +1 -0
  111. package/dist/types/src/components/Form/index.d.ts +3 -5
  112. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  113. package/dist/types/src/components/Form/meta-tags.d.ts +2 -2
  114. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -1
  115. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +6 -23
  116. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -1
  117. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -1
  118. package/dist/types/src/components/RefEditor/RefEditor.stories.d.ts.map +1 -1
  119. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -1
  120. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  121. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  122. package/dist/types/src/hooks/index.d.ts +1 -0
  123. package/dist/types/src/hooks/index.d.ts.map +1 -1
  124. package/dist/types/src/hooks/useFormContext.d.ts +37 -0
  125. package/dist/types/src/hooks/useFormContext.d.ts.map +1 -0
  126. package/dist/types/src/hooks/useFormHandler.d.ts +1 -4
  127. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
  128. package/dist/types/src/index.d.ts +1 -0
  129. package/dist/types/src/index.d.ts.map +1 -1
  130. package/dist/types/src/{components/testing.d.ts → testing/TestLayout.d.ts} +1 -1
  131. package/dist/types/src/testing/TestLayout.d.ts.map +1 -0
  132. package/dist/types/src/testing/index.d.ts +3 -0
  133. package/dist/types/src/testing/index.d.ts.map +1 -0
  134. package/dist/types/src/testing/schema.d.ts +43 -0
  135. package/dist/types/src/testing/schema.d.ts.map +1 -0
  136. package/dist/types/src/types.d.ts +112 -0
  137. package/dist/types/src/types.d.ts.map +1 -0
  138. package/dist/types/src/util/index.d.ts +1 -0
  139. package/dist/types/src/util/index.d.ts.map +1 -1
  140. package/dist/types/src/util/omit.d.ts +12 -0
  141. package/dist/types/src/util/omit.d.ts.map +1 -0
  142. package/dist/types/tsconfig.tsbuildinfo +1 -1
  143. package/package.json +35 -34
  144. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  145. package/src/components/FieldEditor/FieldEditor.test.tsx +1 -1
  146. package/src/components/FieldEditor/FieldEditor.tsx +5 -4
  147. package/src/components/Form/Form.stories.tsx +4 -49
  148. package/src/components/Form/Form.tsx +18 -447
  149. package/src/components/Form/FormControls.tsx +320 -0
  150. package/src/components/Form/FormField/FieldHeader.tsx +36 -0
  151. package/src/components/Form/{FormField.tsx → FormField/FormField.tsx} +35 -59
  152. package/src/components/Form/{FormFieldComponent.stories.tsx → FormField/FormFieldWrapper.stories.tsx} +24 -17
  153. package/src/components/Form/{FormFieldComponent.tsx → FormField/FormFieldWrapper.tsx} +21 -95
  154. package/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.tsx +103 -0
  155. package/src/components/Form/FormField/fields/ArrayField/ArrayField.tsx +269 -0
  156. package/src/components/Form/FormField/fields/ArrayField/index.ts +5 -0
  157. package/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.tsx +52 -0
  158. package/src/components/Form/{fields → FormField/fields/BooleanField}/BooleanField.tsx +10 -3
  159. package/src/components/Form/FormField/fields/BooleanField/index.ts +5 -0
  160. package/src/components/Form/FormField/fields/DateField/DateField.stories.tsx +60 -0
  161. package/src/components/Form/{fields → FormField/fields/DateField}/DateField.tsx +4 -2
  162. package/src/components/Form/FormField/fields/DateField/index.ts +5 -0
  163. package/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.tsx +53 -0
  164. package/src/components/Form/{fields → FormField/fields/GeoPointField}/GeoPointField.tsx +4 -3
  165. package/src/components/Form/FormField/fields/GeoPointField/index.ts +5 -0
  166. package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.tsx +6 -6
  167. package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.tsx +3 -2
  168. package/src/components/Form/FormField/fields/MarkdownField/index.ts +5 -0
  169. package/src/components/Form/FormField/fields/NumberField/NumberField.stories.tsx +52 -0
  170. package/src/components/Form/{fields → FormField/fields/NumberField}/NumberField.tsx +27 -2
  171. package/src/components/Form/FormField/fields/NumberField/index.ts +5 -0
  172. package/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.tsx +8 -7
  173. package/src/components/Form/FormField/fields/RefField/RefField.stories.tsx +97 -0
  174. package/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.ts +2 -1
  175. package/src/components/Form/{fields → FormField/fields/RefField}/RefField.tsx +6 -25
  176. package/src/components/Form/FormField/fields/RefField/index.ts +6 -0
  177. package/src/components/Form/FormField/fields/SelectField/SelectField.stories.tsx +53 -0
  178. package/src/components/Form/{fields → FormField/fields/SelectField}/SelectField.tsx +4 -2
  179. package/src/components/Form/FormField/fields/SelectField/index.ts +5 -0
  180. package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.tsx +5 -5
  181. package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.tsx +55 -53
  182. package/src/components/Form/FormField/fields/SelectOptionField/index.ts +5 -0
  183. package/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.tsx +53 -0
  184. package/src/components/Form/{fields → FormField/fields/TextAreaField}/TextAreaField.tsx +4 -2
  185. package/src/components/Form/FormField/fields/TextAreaField/index.ts +5 -0
  186. package/src/components/Form/FormField/fields/TextField/TextField.stories.tsx +52 -0
  187. package/src/components/Form/{fields → FormField/fields/TextField}/TextField.tsx +4 -2
  188. package/src/components/Form/FormField/fields/TextField/index.ts +5 -0
  189. package/src/components/Form/FormField/fields/TupleField/TupleField.stories.tsx +55 -0
  190. package/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.tsx +4 -2
  191. package/src/components/Form/FormField/fields/TupleField/index.ts +5 -0
  192. package/src/components/Form/{fields → FormField/fields}/index.ts +0 -1
  193. package/src/components/Form/FormField/index.ts +8 -0
  194. package/src/components/Form/{FormFieldSet.tsx → FormFieldSet/FormFieldSet.tsx} +16 -32
  195. package/src/components/Form/FormFieldSet/index.ts +5 -0
  196. package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.tsx +4 -4
  197. package/src/components/Form/{Layout → FormLayout}/FormLayout.tsx +7 -6
  198. package/src/components/Form/{Layout → FormLayout}/index.ts +1 -2
  199. package/src/components/Form/index.ts +3 -5
  200. package/src/components/Form/meta-tags.ts +1 -1
  201. package/src/components/ObjectForm/ObjectForm.tsx +15 -14
  202. package/src/components/ObjectPicker/ObjectPicker.tsx +19 -27
  203. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +1 -1
  204. package/src/components/ObjectProperties/ObjectProperties.test.tsx +1 -1
  205. package/src/components/ObjectProperties/ObjectProperties.tsx +2 -1
  206. package/src/components/RefEditor/RefEditor.stories.tsx +0 -1
  207. package/src/components/ViewEditor/ViewEditor.stories.tsx +4 -5
  208. package/src/components/ViewEditor/ViewEditor.test.tsx +1 -1
  209. package/src/components/ViewEditor/ViewEditor.tsx +98 -128
  210. package/src/hooks/index.ts +1 -0
  211. package/src/hooks/useFormContext.ts +86 -0
  212. package/src/hooks/useFormHandler.ts +1 -4
  213. package/src/index.ts +1 -0
  214. package/src/{components/testing.tsx → testing/TestLayout.tsx} +1 -1
  215. package/src/testing/index.ts +7 -0
  216. package/src/testing/schema.ts +59 -0
  217. package/src/types.ts +134 -0
  218. package/src/util/index.ts +1 -0
  219. package/src/util/omit.ts +47 -0
  220. package/src/vitest-setup.ts +40 -0
  221. package/dist/types/src/components/Form/FormField.d.ts +0 -52
  222. package/dist/types/src/components/Form/FormField.d.ts.map +0 -1
  223. package/dist/types/src/components/Form/FormFieldComponent.d.ts +0 -98
  224. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +0 -1
  225. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +0 -1
  226. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +0 -1
  227. package/dist/types/src/components/Form/FormTooltipsContext.d.ts +0 -19
  228. package/dist/types/src/components/Form/FormTooltipsContext.d.ts.map +0 -1
  229. package/dist/types/src/components/Form/Layout/FormLayout.d.ts.map +0 -1
  230. package/dist/types/src/components/Form/Layout/FormLayout.stories.d.ts.map +0 -1
  231. package/dist/types/src/components/Form/Layout/FormLayout.stories.test.d.ts.map +0 -1
  232. package/dist/types/src/components/Form/Layout/FormLayout.test.d.ts.map +0 -1
  233. package/dist/types/src/components/Form/Layout/annotation.d.ts +0 -30
  234. package/dist/types/src/components/Form/Layout/annotation.d.ts.map +0 -1
  235. package/dist/types/src/components/Form/Layout/index.d.ts +0 -4
  236. package/dist/types/src/components/Form/Layout/index.d.ts.map +0 -1
  237. package/dist/types/src/components/Form/Layout/parser.d.ts.map +0 -1
  238. package/dist/types/src/components/Form/Layout/parser.test.d.ts.map +0 -1
  239. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +0 -1
  240. package/dist/types/src/components/Form/fields/BooleanField.d.ts +0 -4
  241. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +0 -1
  242. package/dist/types/src/components/Form/fields/DateField.d.ts +0 -4
  243. package/dist/types/src/components/Form/fields/DateField.d.ts.map +0 -1
  244. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +0 -1
  245. package/dist/types/src/components/Form/fields/InlineRefField.d.ts.map +0 -1
  246. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +0 -1
  247. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +0 -1
  248. package/dist/types/src/components/Form/fields/NumberField.d.ts +0 -4
  249. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +0 -1
  250. package/dist/types/src/components/Form/fields/RefField.d.ts +0 -34
  251. package/dist/types/src/components/Form/fields/RefField.d.ts.map +0 -1
  252. package/dist/types/src/components/Form/fields/RefField.test.d.ts.map +0 -1
  253. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +0 -1
  254. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +0 -5
  255. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +0 -1
  256. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +0 -1
  257. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +0 -4
  258. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +0 -1
  259. package/dist/types/src/components/Form/fields/TextField.d.ts +0 -4
  260. package/dist/types/src/components/Form/fields/TextField.d.ts.map +0 -1
  261. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +0 -1
  262. package/dist/types/src/components/Form/fields/index.d.ts.map +0 -1
  263. package/dist/types/src/components/testing.d.ts.map +0 -1
  264. package/src/components/Form/AUDIT.md +0 -17
  265. package/src/components/Form/FormTooltipsContext.ts +0 -25
  266. package/src/components/Form/Layout/annotation.ts +0 -38
  267. package/src/components/Form/README.md +0 -3
  268. package/src/components/Form/fields/ArrayField.tsx +0 -173
  269. /package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.d.ts +0 -0
  270. /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.d.ts +0 -0
  271. /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.d.ts +0 -0
  272. /package/dist/types/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.d.ts +0 -0
  273. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.d.ts +0 -0
  274. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.d.ts +0 -0
  275. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.d.ts +0 -0
  276. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.test.d.ts +0 -0
  277. /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.d.ts +0 -0
  278. /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.test.d.ts +0 -0
  279. /package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.tsx +0 -0
  280. /package/src/components/Form/{Layout → FormLayout}/FormLayout.test.ts +0 -0
  281. /package/src/components/Form/{Layout → FormLayout}/parser.test.ts +0 -0
  282. /package/src/components/Form/{Layout → FormLayout}/parser.ts +0 -0
@@ -10,27 +10,15 @@ import { invariant } from '@dxos/invariant';
10
10
  import { HuePicker } from '@dxos/react-ui-pickers';
11
11
 
12
12
  import { translationKey } from '#translations';
13
+ import { type FormFieldMap } from '#types';
13
14
 
14
- import { Form, type FormFieldMap, META_TAGS_KEY, withMetaTags } from '../Form';
15
+ import { Form, META_TAGS_KEY, withMetaTags } from '../Form';
15
16
 
16
17
  export type ObjectFormProps = {
17
18
  type: Type.AnyEntity;
18
19
  object: Obj.Unknown;
19
20
  };
20
21
 
21
- const createFieldMap: FormFieldMap = {
22
- hue: ({ type, label, layout, getValue, onValueChange }) => {
23
- const handleChange = useCallback((nextHue: string) => onValueChange(type, nextHue), [onValueChange, type]);
24
- const handleReset = useCallback(() => onValueChange(type, undefined), [onValueChange, type]);
25
- return (
26
- <>
27
- {layout !== 'inline' && <Form.Label label={label} />}
28
- <HuePicker value={getValue()} onChange={handleChange} onReset={handleReset} />
29
- </>
30
- );
31
- },
32
- };
33
-
34
22
  export const ObjectForm = ({ object, type }: ObjectFormProps) => {
35
23
  const db = Obj.getDatabase(object);
36
24
  const meta = Obj.getMeta(object);
@@ -109,3 +97,16 @@ export const ObjectForm = ({ object, type }: ObjectFormProps) => {
109
97
  </Form.Root>
110
98
  );
111
99
  };
100
+
101
+ const createFieldMap: FormFieldMap = {
102
+ hue: ({ type, label, layout, getValue, onValueChange }) => {
103
+ const handleChange = useCallback((nextHue: string) => onValueChange(type, nextHue), [onValueChange, type]);
104
+ const handleReset = useCallback(() => onValueChange(type, undefined), [onValueChange, type]);
105
+ return (
106
+ <>
107
+ {layout !== 'inline' && <Form.Label label={label} />}
108
+ <HuePicker value={getValue()} onChange={handleChange} onReset={handleReset} />
109
+ </>
110
+ );
111
+ },
112
+ };
@@ -5,39 +5,31 @@
5
5
  import type * as Schema from 'effect/Schema';
6
6
  import React, { type KeyboardEvent, forwardRef, useCallback, useState } from 'react';
7
7
 
8
- import { type Palette, Popover, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
+ import { Popover, type ThemedClassName, useTranslation } from '@dxos/react-ui';
9
9
  import { Combobox } from '@dxos/react-ui-list';
10
10
  import { useSearchListResults } from '@dxos/react-ui-search';
11
11
 
12
12
  import { translationKey } from '#translations';
13
+ import { type CreateOptions, type RefOption } from '#types';
13
14
 
14
15
  import { Form } from '../Form';
15
- import { type FormFieldMap } from '../Form/FormFieldComponent';
16
16
 
17
- export type RefOption = {
18
- id: string;
19
- label: string;
20
- hue?: Palette;
21
- };
22
-
23
- export type ObjectPickerContentProps = ThemedClassName<{
24
- options: RefOption[];
25
- selectedIds?: string[];
26
- createOptionLabel?: [string, { ns: string | readonly string[] }];
27
- createOptionIcon?: string;
28
- createSchema?: Schema.Schema.AnyNoContext;
29
- createInitialValuePath?: string;
30
- createFieldMap?: FormFieldMap;
31
- /**
32
- * Persist a newly-created object given the form values. May be async (e.g.
33
- * to write to a database). The Promise is awaited before the inline create
34
- * form is collapsed back to the picker list, so consumers can complete
35
- * follow-up work (assign the new ref to a parent slot, close the popover)
36
- * before the picker UI re-renders.
37
- */
38
- onCreate?: (values: any) => unknown | Promise<unknown>;
39
- onSelect: (id: string) => void;
40
- }>;
17
+ export type ObjectPickerContentProps = ThemedClassName<
18
+ CreateOptions & {
19
+ options: RefOption[];
20
+ selectedIds?: string[];
21
+ createSchema?: Schema.Schema.AnyNoContext;
22
+ /**
23
+ * Persist a newly-created object given the form values. May be async (e.g.
24
+ * to write to a database). The Promise is awaited before the inline create
25
+ * form is collapsed back to the picker list, so consumers can complete
26
+ * follow-up work (assign the new ref to a parent slot, close the popover)
27
+ * before the picker UI re-renders.
28
+ */
29
+ onCreate?: (values: any) => unknown | Promise<unknown>;
30
+ onSelect?: (id: string) => void;
31
+ }
32
+ >;
41
33
 
42
34
  const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>(
43
35
  (
@@ -138,7 +130,7 @@ const ObjectPickerContent = forwardRef<HTMLDivElement, ObjectPickerContentProps>
138
130
  value={option.id}
139
131
  label={option.label}
140
132
  checked={selectedIds?.includes(option.id)}
141
- onSelect={() => onSelect(option.id)}
133
+ onSelect={() => onSelect?.(option.id)}
142
134
  classNames='flex items-center gap-2'
143
135
  />
144
136
  ))}
@@ -18,7 +18,7 @@ import { Pipeline } from '@dxos/types';
18
18
 
19
19
  import { translations } from '#translations';
20
20
 
21
- import { OBJECT_PROPERTIES_DEBUG_SYMBOL } from '../testing';
21
+ import { OBJECT_PROPERTIES_DEBUG_SYMBOL } from '../../testing';
22
22
  import { ObjectProperties } from './ObjectProperties';
23
23
 
24
24
  //
@@ -9,7 +9,7 @@ import { afterEach, describe, expect, test } from 'vitest';
9
9
  import { Filter, Obj, Tag } from '@dxos/echo';
10
10
  import { DXN, EID } from '@dxos/keys';
11
11
 
12
- import { OBJECT_PROPERTIES_DEBUG_SYMBOL } from '../testing';
12
+ import { OBJECT_PROPERTIES_DEBUG_SYMBOL } from '../../testing';
13
13
  import * as stories from './ObjectProperties.stories';
14
14
  import { type ObjectPropertiesDebug } from './ObjectProperties.stories';
15
15
 
@@ -15,8 +15,9 @@ import { HuePicker } from '@dxos/react-ui-pickers';
15
15
  import { FactoryAnnotation } from '@dxos/schema';
16
16
 
17
17
  import { translationKey } from '#translations';
18
+ import { type FormFieldMap } from '#types';
18
19
 
19
- import { Form, type FormFieldMap, META_TAGS_KEY, withMetaTags } from '../Form';
20
+ import { Form, META_TAGS_KEY, withMetaTags } from '../Form';
20
21
 
21
22
  export type ObjectPropertiesProps = PropsWithChildren<{ object: Obj.Unknown }>;
22
23
 
@@ -88,7 +88,6 @@ const DefaultStory = ({ value: initialValue, ...args }: StoryProps) => {
88
88
  icon='ph--user--regular'
89
89
  db={space?.db}
90
90
  onChange={setValue}
91
- classNames='border'
92
91
  />
93
92
  <JsonHighlighter data={{ value }} classNames='text-xs' />
94
93
  <PeopleGrid db={space?.db} />
@@ -12,17 +12,16 @@ import { type Mutable } from '@dxos/echo/Obj';
12
12
  import { useQuery } from '@dxos/react-client/echo';
13
13
  import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
14
14
  import { useAsyncEffect } from '@dxos/react-ui';
15
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
16
16
  import { type ProjectionModel, ViewModel, getTypeURIFromQuery } from '@dxos/schema';
17
17
  import { Employer, Organization, Person, Pipeline } from '@dxos/types';
18
18
 
19
19
  import { translations } from '#translations';
20
20
 
21
- import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
21
+ import { TestLayout, VIEW_EDITOR_DEBUG_SYMBOL } from '../../testing';
22
22
  import { ViewEditor, type ViewEditorProps } from './ViewEditor';
23
23
 
24
24
  const types = [
25
- // TODO(burdon): Get label from annotation.
26
25
  { value: Type.getURI(Organization.Organization), label: 'Organization' },
27
26
  { value: Type.getURI(Person.Person), label: 'Person' },
28
27
  { value: Type.getURI(Pipeline.Pipeline), label: 'Project' },
@@ -126,14 +125,14 @@ const DefaultStory = (props: DefaultStoryProps) => {
126
125
  }
127
126
  }, [type, view]);
128
127
 
129
- // NOTE(ZaymonFC): This looks awkward but it resolves an infinite parsing issue with sb.
128
+ // NOTE(ZaymonFC): Avoids infinite parsing issue with storybook args.
130
129
  const json = useMemo(
131
130
  () => JSON.parse(JSON.stringify({ schema: type, view, projection: projectionRef.current })),
132
131
  [JSON.stringify(type), JSON.stringify(view)],
133
132
  );
134
133
 
135
134
  if (!type || !view) {
136
- return <div />;
135
+ return <Loading />;
137
136
  }
138
137
 
139
138
  return (
@@ -10,7 +10,7 @@ import { Type, View } from '@dxos/echo';
10
10
  import { instanceOf as isInstanceOf } from '@dxos/echo/Obj';
11
11
  import { ProjectionModel } from '@dxos/schema';
12
12
 
13
- import { VIEW_EDITOR_DEBUG_SYMBOL } from '../testing';
13
+ import { VIEW_EDITOR_DEBUG_SYMBOL } from '../../testing';
14
14
  import * as stories from './ViewEditor.stories';
15
15
  import { type ViewEditorDebugObjects } from './ViewEditor.stories';
16
16
 
@@ -26,9 +26,9 @@ import {
26
26
  import { SchemaEx } from '@dxos/effect';
27
27
  import { invariant } from '@dxos/invariant';
28
28
  import { useObject, useQuery } from '@dxos/react-client/echo';
29
- import { IconButton, Input, Message, type ThemedClassName, useTranslation } from '@dxos/react-ui';
29
+ import { Input, Message, type ThemedClassName, ToggleIconButton, useTranslation } from '@dxos/react-ui';
30
30
  import { QueryForm, type QueryFormProps } from '@dxos/react-ui-components';
31
- import { List } from '@dxos/react-ui-list';
31
+ import { OrderedList } from '@dxos/react-ui-list';
32
32
  import {
33
33
  ParentLabelAnnotation,
34
34
  ProjectionModel,
@@ -36,19 +36,13 @@ import {
36
36
  createEchoChangeCallback,
37
37
  getTypeURIFromQuery,
38
38
  } from '@dxos/schema';
39
- import { mx, osTranslations } from '@dxos/ui-theme';
39
+ import { mx } from '@dxos/ui-theme';
40
40
 
41
41
  import { translationKey } from '#translations';
42
+ import { type FormFieldRenderer, type FormFieldRendererProps, type FormFieldMap } from '#types';
42
43
 
43
44
  import { FieldEditor } from '../FieldEditor';
44
- import {
45
- Form,
46
- type FormFieldComponent,
47
- type FormFieldComponentProps,
48
- FormFieldLabel,
49
- type FormFieldMap,
50
- type FormRootProps,
51
- } from '../Form';
45
+ import { CompactIconButton, FieldHeader, Form, FormFieldLabel, type FormRootProps } from '../Form';
52
46
 
53
47
  export type ViewEditorProps = ThemedClassName<
54
48
  {
@@ -64,7 +58,7 @@ export type ViewEditorProps = ThemedClassName<
64
58
  >;
65
59
 
66
60
  /**
67
- * Schema-based object form.
61
+ * View editor form.
68
62
  */
69
63
  export const ViewEditor = forwardRef<ProjectionModel | null, ViewEditorProps>(
70
64
  (
@@ -92,6 +86,7 @@ export const ViewEditor = forwardRef<ProjectionModel | null, ViewEditorProps>(
92
86
  if (!type) {
93
87
  return null;
94
88
  }
89
+
95
90
  const jsonSchema = type.jsonSchema;
96
91
 
97
92
  // Always use createEchoChangeCallback since the view is ECHO-backed.
@@ -117,6 +112,7 @@ export const ViewEditor = forwardRef<ProjectionModel | null, ViewEditorProps>(
117
112
  if (from._tag !== 'scope') {
118
113
  return undefined;
119
114
  }
115
+
120
116
  const feedScope = from.scopes.find((s) => s._tag === 'feed');
121
117
  return Option.fromNullable(feedScope).pipe(
122
118
  Option.map((s) => s.feedUri),
@@ -216,42 +212,54 @@ export const ViewEditor = forwardRef<ProjectionModel | null, ViewEditorProps>(
216
212
 
217
213
  return (
218
214
  <div className={mx(classNames)}>
219
- {/* If readonly is set, then the callout is not needed. */}
220
- {schemaReadonly && !readonly && (
221
- <Message.Root valence='info' classNames='my-form-padding'>
222
- <Message.Title>{t('system-schema.description')}</Message.Title>
223
- </Message.Root>
224
- )}
225
-
226
215
  {/* TODO(burdon): Is the form read-only or just the schema? */}
227
216
  <Form.Root schema={viewSchema} values={viewValues} fieldMap={fieldMap} db={db} onValuesChanged={handleUpdate}>
228
- <Form.FieldSet />
229
-
230
- {type && (
231
- <>
232
- <FormFieldLabel label={t('fields.label')} asChild />
233
- <FieldList
234
- type={type}
235
- view={view}
236
- registry={registry}
237
- readonly={readonly}
238
- showHeading={showHeading}
239
- onDelete={handleDelete}
240
- />
241
- </>
242
- )}
217
+ <Form.Viewport>
218
+ <Form.Content>
219
+ {/* If readonly is set, then the callout is not needed. */}
220
+ {schemaReadonly && !readonly && (
221
+ <Message.Root valence='info' classNames='my-form-padding'>
222
+ <Message.Title>{t('system-schema.description')}</Message.Title>
223
+ </Message.Root>
224
+ )}
225
+ <Form.FieldSet />
226
+ {type && (
227
+ <FieldList
228
+ type={type}
229
+ view={view}
230
+ registry={registry}
231
+ readonly={readonly}
232
+ showHeading={showHeading}
233
+ onDelete={handleDelete}
234
+ />
235
+ )}
236
+ </Form.Content>
237
+ </Form.Viewport>
243
238
  </Form.Root>
244
239
  </div>
245
240
  );
246
241
  },
247
242
  );
248
243
 
249
- type FieldListProps = Omit<
250
- Pick<ViewEditorProps, 'type' | 'view' | 'registry' | 'readonly' | 'showHeading' | 'onDelete'>,
251
- 'type'
252
- > & {
244
+ const customFields = ({ types, tags }: Pick<ViewEditorProps, 'types' | 'tags'>): Record<string, FormFieldRenderer> => ({
245
+ query: ({ type, readonly, label, getValue, onValueChange }: FormFieldRendererProps) => {
246
+ const handleChange = useCallback<NonNullable<QueryFormProps['onChange']>>(
247
+ (query) => onValueChange(type, query.ast),
248
+ [onValueChange],
249
+ );
250
+
251
+ return (
252
+ <Input.Root>
253
+ <FormFieldLabel readonly={readonly} label={label} />
254
+ <QueryForm initialQuery={getValue()} types={types} tags={tags} onChange={handleChange} />
255
+ </Input.Root>
256
+ );
257
+ },
258
+ });
259
+
260
+ type FieldListProps = {
253
261
  type: Type.AnyEntity;
254
- };
262
+ } & Pick<ViewEditorProps, 'view' | 'registry' | 'readonly' | 'showHeading' | 'onDelete'>;
255
263
 
256
264
  const FieldList = ({ type, view, registry, readonly, showHeading = false, onDelete }: FieldListProps) => {
257
265
  const atomRegistry = useContext(RegistryContext);
@@ -268,14 +276,12 @@ const FieldList = ({ type, view, registry, readonly, showHeading = false, onDele
268
276
  // Pass type only when mutable to allow schema mutations.
269
277
  const change = createEchoChangeCallback(view, Type.getDatabase(type) != null ? type : undefined);
270
278
 
271
- const model = new ProjectionModel({
279
+ return new ProjectionModel({
272
280
  registry: atomRegistry,
273
281
  view,
274
282
  baseSchema: jsonSchema,
275
283
  change,
276
284
  });
277
-
278
- return model;
279
285
  }, [atomRegistry, type, view]);
280
286
 
281
287
  const [expandedField, setExpandedField] = useState<View.FieldType['id']>();
@@ -286,13 +292,6 @@ const FieldList = ({ type, view, registry, readonly, showHeading = false, onDele
286
292
  setExpandedField(field.id);
287
293
  }, [projectionModel, readonly]);
288
294
 
289
- const handleToggleField = useCallback(
290
- (field: View.FieldType) => {
291
- setExpandedField((prevExpandedFieldId) => (prevExpandedFieldId === field.id ? undefined : field.id));
292
- },
293
- [readonly],
294
- );
295
-
296
295
  const handleDelete = useCallback(
297
296
  (fieldId: string) => {
298
297
  invariant(!readonly);
@@ -342,106 +341,77 @@ const FieldList = ({ type, view, registry, readonly, showHeading = false, onDele
342
341
  }
343
342
 
344
343
  return (
345
- <List.Root<View.FieldType>
344
+ <OrderedList.Root<View.FieldType>
346
345
  items={viewSnapshot.projection.fields as View.FieldType[]}
347
346
  isItem={Schema.is(View.FieldSchema)}
348
347
  getId={(field) => field.id}
349
348
  onMove={readonly ? undefined : handleMove}
350
349
  readonly={readonly}
350
+ expandedId={expandedField}
351
+ onExpandedChange={setExpandedField}
351
352
  >
352
353
  {({ items: fields }) => (
353
354
  <>
354
- {showHeading && <h3 className='text-sm'>{t('field-path.label')}</h3>}
355
- <div role='list' className='grid grid-cols-[min-content_1fr_min-content_min-content_min-content]'>
356
- {fields?.map((field) => {
355
+ <FieldHeader
356
+ label={t('fields.label')}
357
+ readonly={readonly}
358
+ add={{
359
+ label: t('add-property-button.label'),
360
+ disabled: viewSnapshot.projection.fields.length >= VIEW_FIELD_LIMIT,
361
+ onClick: handleAdd,
362
+ }}
363
+ />
364
+ {showHeading && <FormFieldLabel standalone classNames='py-1' label={t('field-path.label')} />}
365
+ <OrderedList.Content>
366
+ {fields.map((field) => {
357
367
  const hidden = field.visible === false;
358
368
  return (
359
- <List.Item<View.FieldType>
369
+ <OrderedList.DetailItem<View.FieldType>
360
370
  key={field.id}
371
+ id={field.id}
361
372
  item={field}
362
- classNames={'grid grid-cols-subgrid col-span-5'}
363
- aria-expanded={expandedField === field.id}
364
- >
365
- <div className='grid grid-cols-subgrid col-span-5 rounded-xs cursor-pointer min-h-10 dx-hover'>
366
- <List.ItemDragHandle disabled={readonly || schemaReadonly} />
367
- <List.ItemTitle classNames={hidden && 'text-subdued'} onClick={() => handleToggleField(field)}>
368
- {field.path}
369
- </List.ItemTitle>
370
- <List.ItemIconButton
373
+ canDrag={!readonly && !schemaReadonly}
374
+ expandable={!readonly}
375
+ title={field.path}
376
+ titleClassNames={hidden ? 'text-subdued' : undefined}
377
+ actions={
378
+ <ToggleIconButton
379
+ iconOnly
380
+ variant='ghost'
381
+ active={hidden}
382
+ icon='ph--eye--regular'
383
+ activeIcon='ph--eye-closed--regular'
371
384
  label={t(hidden ? 'show-field.label' : 'hide-field.label')}
372
385
  data-testid={hidden ? 'show-field-button' : 'hide-field-button'}
373
- icon={hidden ? 'ph--eye-closed--regular' : 'ph--eye--regular'}
374
- autoHide={false}
375
386
  disabled={readonly || (!hidden && projectionModel.getFields().length <= 1)}
376
387
  onClick={() => (hidden ? handleShow(field.path) : handleHide(field.id))}
377
388
  />
378
- {!readonly && (
379
- <>
380
- <List.ItemDeleteButton
381
- label={t('delete-field.label')}
382
- autoHide={false}
383
- disabled={readonly || schemaReadonly || viewSnapshot.projection.fields.length <= 1}
384
- onClick={() => handleDelete(field.id)}
385
- data-testid='field.delete'
386
- />
387
- <List.ItemIconButton
388
- iconOnly
389
- variant='ghost'
390
- label={t('toggle-expand.label', { ns: osTranslations })}
391
- icon={expandedField === field.id ? 'ph--caret-down--regular' : 'ph--caret-right--regular'}
392
- onClick={() => handleToggleField(field)}
393
- data-testid='field.toggle'
394
- />
395
- </>
396
- )}
397
- </div>
398
- {expandedField === field.id && !readonly && (
399
- <div className='col-span-full mt-1 mb-1 border border-separator rounded-md'>
400
- <FieldEditor
401
- readonly={readonly || schemaReadonly}
402
- registry={registry}
403
- projection={projectionModel}
404
- field={field}
405
- onSave={handleClose}
389
+ }
390
+ trailing={
391
+ !readonly && (
392
+ <CompactIconButton
393
+ icon='ph--x--regular'
394
+ label={t('delete-field.label')}
395
+ disabled={schemaReadonly || viewSnapshot.projection.fields.length <= 1}
396
+ onClick={() => handleDelete(field.id)}
397
+ data-testid='field.delete'
406
398
  />
407
- </div>
408
- )}
409
- </List.Item>
399
+ )
400
+ }
401
+ >
402
+ <FieldEditor
403
+ readonly={readonly || schemaReadonly}
404
+ registry={registry}
405
+ projection={projectionModel}
406
+ field={field}
407
+ onSave={handleClose}
408
+ />
409
+ </OrderedList.DetailItem>
410
410
  );
411
411
  })}
412
- </div>
413
- {!readonly && !expandedField && (
414
- <div className='my-form-padding'>
415
- <IconButton
416
- icon='ph--plus--regular'
417
- label={t('add-property-button.label')}
418
- onClick={handleAdd}
419
- disabled={viewSnapshot.projection.fields.length >= VIEW_FIELD_LIMIT}
420
- classNames='w-full'
421
- />
422
- </div>
423
- )}
412
+ </OrderedList.Content>
424
413
  </>
425
414
  )}
426
- </List.Root>
415
+ </OrderedList.Root>
427
416
  );
428
417
  };
429
-
430
- const customFields = ({
431
- types,
432
- tags,
433
- }: Pick<ViewEditorProps, 'types' | 'tags'>): Record<string, FormFieldComponent> => ({
434
- query: ({ type, readonly, label, getValue, onValueChange }: FormFieldComponentProps) => {
435
- const handleChange = useCallback<NonNullable<QueryFormProps['onChange']>>(
436
- (query) => onValueChange(type, query.ast),
437
- [onValueChange],
438
- );
439
-
440
- return (
441
- <Input.Root>
442
- <FormFieldLabel readonly={readonly} label={label} />
443
- <QueryForm initialQuery={getValue()} types={types} tags={tags} onChange={handleChange} />
444
- </Input.Root>
445
- );
446
- },
447
- });
@@ -2,5 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ export * from './useFormContext';
5
6
  export * from './useFormHandler';
6
7
  export * from './useKeyHandler';
@@ -0,0 +1,86 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createContext } from '@radix-ui/react-context';
6
+ import * as SchemaAST from 'effect/SchemaAST';
7
+ import { useEffect, useMemo, useRef } from 'react';
8
+
9
+ import { type AnyProperties } from '@dxos/echo/internal';
10
+ import { SchemaEx } from '@dxos/effect';
11
+
12
+ import { type CreateOptions, type FormFieldOptions, type FormFieldStateProps } from '#types';
13
+
14
+ import { type FormHandler } from './useFormHandler';
15
+
16
+ //
17
+ // Context
18
+ //
19
+
20
+ export type FormContextValue<T extends AnyProperties = any> = {
21
+ /**
22
+ * Form handler.
23
+ */
24
+ form: FormHandler<T>;
25
+
26
+ /**
27
+ * Testing.
28
+ */
29
+ testId?: string;
30
+ } & FormFieldOptions &
31
+ Pick<CreateOptions, 'createFieldMap'>;
32
+
33
+ export const [FormContextProvider, useFormContext] = createContext<FormContextValue>('Form');
34
+
35
+ /**
36
+ * Get the current form values.
37
+ */
38
+ export const useFormValues: {
39
+ <T extends AnyProperties>(componentName: string, path?: (string | number)[]): T;
40
+ <T extends AnyProperties>(
41
+ componentName: string,
42
+ path: (string | number)[] | undefined,
43
+ defaultValue: () => T,
44
+ ): T | undefined;
45
+ } = (componentName: string, path?: (string | number)[], defaultValue?: () => any) => {
46
+ const stablePath = useMemo(() => path ?? [], [path ? path.join('.') : undefined]);
47
+ const jsonPath = SchemaEx.createJsonPath(stablePath);
48
+ const {
49
+ form: { values, onValueChange },
50
+ } = useFormContext(componentName);
51
+
52
+ const value = SchemaEx.getValue(values, jsonPath);
53
+
54
+ // Apply default value once when the field has no value. lastAppliedPathRef prevents
55
+ // re-applying on every render (e.g. when defaultValue() returns null) and ensures
56
+ // we apply per path when the hook is used for different fields.
57
+ const lastAppliedPathRef = useRef<string | null>(null);
58
+ useEffect(() => {
59
+ if (value == null && defaultValue && lastAppliedPathRef.current !== jsonPath) {
60
+ lastAppliedPathRef.current = jsonPath;
61
+ onValueChange(stablePath, SchemaAST.stringKeyword, defaultValue());
62
+ }
63
+ }, [value, defaultValue, onValueChange, stablePath, jsonPath]);
64
+
65
+ return value;
66
+ };
67
+
68
+ /**
69
+ * Get the state props for the given field.
70
+ */
71
+ export const useFormFieldState = (componentName: string, path: (string | number)[] = []): FormFieldStateProps => {
72
+ const stablePath = useMemo(() => path, [Array.isArray(path) ? path.join('.') : path]);
73
+ const {
74
+ form: { getStatus, getValue, onBlur, onValueChange },
75
+ } = useFormContext(componentName);
76
+
77
+ return useMemo(
78
+ () => ({
79
+ getStatus: () => getStatus(stablePath),
80
+ getValue: () => getValue(stablePath),
81
+ onBlur: () => onBlur(stablePath),
82
+ onValueChange: (ast: SchemaAST.AST, value: any) => onValueChange(stablePath, ast, value),
83
+ }),
84
+ [getStatus, getValue, onBlur, onValueChange, stablePath],
85
+ );
86
+ };
@@ -14,10 +14,7 @@ import { useDefaultValue } from '@dxos/react-ui';
14
14
  import { type ValidationError, validateSchema } from '@dxos/schema';
15
15
  import { type MaybePromise } from '@dxos/util';
16
16
 
17
- export type FormFieldStatus = {
18
- status?: 'error';
19
- error?: string;
20
- };
17
+ import { type FormFieldStatus } from '#types';
21
18
 
22
19
  /**
23
20
  * Form properties.
package/src/index.ts CHANGED
@@ -4,4 +4,5 @@
4
4
 
5
5
  export * from './components';
6
6
  export * from './hooks';
7
+ export * from './types';
7
8
  export * from './util';
@@ -32,7 +32,7 @@ type TestPanelProps = ThemedClassName<PropsWithChildren>;
32
32
 
33
33
  export const TestPanel = slottable<HTMLDivElement, TestPanelProps>(({ children }, forwardedRef) => {
34
34
  return (
35
- <div {...composableProps({ classNames: 'dx-container bg-card-surface rounded-md' })} ref={forwardedRef}>
35
+ <div {...composableProps({ classNames: 'dx-container dx-card-surface rounded-sm' })} ref={forwardedRef}>
36
36
  {children}
37
37
  </div>
38
38
  );
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './schema';
6
+
7
+ export * from './TestLayout';