@dxos/react-ui-form 0.9.0 → 0.9.1-staging.ee54ba693a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/dist/lib/browser/index.mjs +2337 -1919
  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 +2337 -1919
  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/annotations.d.ts +47 -0
  8. package/dist/types/src/annotations.d.ts.map +1 -0
  9. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts +3 -3
  10. package/dist/types/src/components/FieldEditor/FieldEditor.d.ts.map +1 -1
  11. package/dist/types/src/components/Form/Form.d.ts +23 -110
  12. package/dist/types/src/components/Form/Form.d.ts.map +1 -1
  13. package/dist/types/src/components/Form/Form.stories.d.ts +48 -101
  14. package/dist/types/src/components/Form/Form.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/Form/Form.theme.d.ts +252 -0
  16. package/dist/types/src/components/Form/Form.theme.d.ts.map +1 -0
  17. package/dist/types/src/components/Form/Form.theme.test.d.ts +2 -0
  18. package/dist/types/src/components/Form/Form.theme.test.d.ts.map +1 -0
  19. package/dist/types/src/components/Form/FormControls.d.ts +75 -0
  20. package/dist/types/src/components/Form/FormControls.d.ts.map +1 -0
  21. package/dist/types/src/components/Form/FormField/FormField.d.ts +44 -0
  22. package/dist/types/src/components/Form/FormField/FormField.d.ts.map +1 -0
  23. package/dist/types/src/components/Form/FormField/FormFieldHeader.d.ts +27 -0
  24. package/dist/types/src/components/Form/FormField/FormFieldHeader.d.ts.map +1 -0
  25. package/dist/types/src/components/Form/FormField/FormRow.d.ts +85 -0
  26. package/dist/types/src/components/Form/FormField/FormRow.d.ts.map +1 -0
  27. package/dist/types/src/components/Form/{FormFieldComponent.stories.d.ts → FormField/FormRow.stories.d.ts} +6 -3
  28. package/dist/types/src/components/Form/FormField/FormRow.stories.d.ts.map +1 -0
  29. package/dist/types/src/components/Form/{fields → FormField/fields/ArrayField}/ArrayField.d.ts +2 -2
  30. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.d.ts.map +1 -0
  31. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts +88 -0
  32. package/dist/types/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts +2 -0
  34. package/dist/types/src/components/Form/FormField/fields/ArrayField/index.d.ts.map +1 -0
  35. package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.d.ts +12 -0
  36. package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.d.ts.map +1 -0
  37. package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/index.d.ts +2 -0
  38. package/dist/types/src/components/Form/FormField/fields/AsyncSelectField/index.d.ts.map +1 -0
  39. package/dist/types/src/components/Form/FormField/fields/AutofillField/AutofillField.d.ts +12 -0
  40. package/dist/types/src/components/Form/FormField/fields/AutofillField/AutofillField.d.ts.map +1 -0
  41. package/dist/types/src/components/Form/FormField/fields/AutofillField/index.d.ts +2 -0
  42. package/dist/types/src/components/Form/FormField/fields/AutofillField/index.d.ts.map +1 -0
  43. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts +4 -0
  44. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.d.ts.map +1 -0
  45. package/dist/types/src/components/{Settings/Settings.stories.d.ts → Form/FormField/fields/BooleanField/BooleanField.stories.d.ts} +1 -2
  46. package/dist/types/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.d.ts.map +1 -0
  47. package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts +2 -0
  48. package/dist/types/src/components/Form/FormField/fields/BooleanField/index.d.ts.map +1 -0
  49. package/dist/types/src/components/Form/FormField/fields/ComboboxField/ComboboxField.d.ts +12 -0
  50. package/dist/types/src/components/Form/FormField/fields/ComboboxField/ComboboxField.d.ts.map +1 -0
  51. package/dist/types/src/components/Form/FormField/fields/ComboboxField/index.d.ts +2 -0
  52. package/dist/types/src/components/Form/FormField/fields/ComboboxField/index.d.ts.map +1 -0
  53. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts +4 -0
  54. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.d.ts.map +1 -0
  55. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts +88 -0
  56. package/dist/types/src/components/Form/FormField/fields/DateField/DateField.stories.d.ts.map +1 -0
  57. package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts +2 -0
  58. package/dist/types/src/components/Form/FormField/fields/DateField/index.d.ts.map +1 -0
  59. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts +5 -0
  60. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.d.ts.map +1 -0
  61. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts +88 -0
  62. package/dist/types/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.d.ts.map +1 -0
  63. package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts +2 -0
  64. package/dist/types/src/components/Form/FormField/fields/GeoPointField/index.d.ts.map +1 -0
  65. package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.d.ts +2 -2
  66. package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.d.ts.map +1 -0
  67. package/dist/types/src/components/Form/FormField/fields/MarkdownField/MarkdownField.stories.d.ts.map +1 -0
  68. package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts +2 -0
  69. package/dist/types/src/components/Form/FormField/fields/MarkdownField/index.d.ts.map +1 -0
  70. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts +15 -0
  71. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.d.ts.map +1 -0
  72. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts +88 -0
  73. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.stories.d.ts.map +1 -0
  74. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.test.d.ts +2 -0
  75. package/dist/types/src/components/Form/FormField/fields/NumberField/NumberField.test.d.ts.map +1 -0
  76. package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts +2 -0
  77. package/dist/types/src/components/Form/FormField/fields/NumberField/index.d.ts.map +1 -0
  78. package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.d.ts +4 -0
  79. package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.d.ts.map +1 -0
  80. package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.d.ts +88 -0
  81. package/dist/types/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.d.ts.map +1 -0
  82. package/dist/types/src/components/Form/FormField/fields/PasswordField/index.d.ts +2 -0
  83. package/dist/types/src/components/Form/FormField/fields/PasswordField/index.d.ts.map +1 -0
  84. package/dist/types/src/components/Form/FormField/fields/RefField/InlineRefField.d.ts.map +1 -0
  85. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts +16 -0
  86. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.d.ts.map +1 -0
  87. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts +92 -0
  88. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.stories.d.ts.map +1 -0
  89. package/dist/types/src/components/Form/FormField/fields/RefField/RefField.test.d.ts.map +1 -0
  90. package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts +3 -0
  91. package/dist/types/src/components/Form/FormField/fields/RefField/index.d.ts.map +1 -0
  92. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts +29 -0
  93. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.d.ts.map +1 -0
  94. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts +88 -0
  95. package/dist/types/src/components/Form/FormField/fields/SelectField/SelectField.stories.d.ts.map +1 -0
  96. package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts +2 -0
  97. package/dist/types/src/components/Form/FormField/fields/SelectField/index.d.ts.map +1 -0
  98. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts +5 -0
  99. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.d.ts.map +1 -0
  100. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/SelectOptionField.stories.d.ts.map +1 -0
  101. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts +2 -0
  102. package/dist/types/src/components/Form/FormField/fields/SelectOptionField/index.d.ts.map +1 -0
  103. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts +4 -0
  104. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.d.ts.map +1 -0
  105. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts +88 -0
  106. package/dist/types/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.d.ts.map +1 -0
  107. package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts +2 -0
  108. package/dist/types/src/components/Form/FormField/fields/TextAreaField/index.d.ts.map +1 -0
  109. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts +4 -0
  110. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.d.ts.map +1 -0
  111. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts +88 -0
  112. package/dist/types/src/components/Form/FormField/fields/TextField/TextField.stories.d.ts.map +1 -0
  113. package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts +2 -0
  114. package/dist/types/src/components/Form/FormField/fields/TextField/index.d.ts.map +1 -0
  115. package/dist/types/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.d.ts +2 -2
  116. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.d.ts.map +1 -0
  117. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts +88 -0
  118. package/dist/types/src/components/Form/FormField/fields/TupleField/TupleField.stories.d.ts.map +1 -0
  119. package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts +2 -0
  120. package/dist/types/src/components/Form/FormField/fields/TupleField/index.d.ts.map +1 -0
  121. package/dist/types/src/components/Form/{fields → FormField/fields}/index.d.ts +4 -1
  122. package/dist/types/src/components/Form/FormField/fields/index.d.ts.map +1 -0
  123. package/dist/types/src/components/Form/FormField/index.d.ts +6 -0
  124. package/dist/types/src/components/Form/FormField/index.d.ts.map +1 -0
  125. package/dist/types/src/components/Form/FormField/presentation.d.ts +22 -0
  126. package/dist/types/src/components/Form/FormField/presentation.d.ts.map +1 -0
  127. package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts +30 -0
  128. package/dist/types/src/components/Form/FormFieldSet/FormFieldSet.d.ts.map +1 -0
  129. package/dist/types/src/components/Form/FormFieldSet/FormFieldSetContainer.d.ts +22 -0
  130. package/dist/types/src/components/Form/FormFieldSet/FormFieldSetContainer.d.ts.map +1 -0
  131. package/dist/types/src/components/Form/FormFieldSet/index.d.ts +3 -0
  132. package/dist/types/src/components/Form/FormFieldSet/index.d.ts.map +1 -0
  133. package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.d.ts +2 -0
  134. package/dist/types/src/components/Form/FormLayout/FormLayout.d.ts.map +1 -0
  135. package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.d.ts +5 -5
  136. package/dist/types/src/components/Form/FormLayout/FormLayout.stories.d.ts.map +1 -0
  137. package/dist/types/src/components/Form/FormLayout/FormLayout.stories.test.d.ts.map +1 -0
  138. package/dist/types/src/components/Form/FormLayout/FormLayout.test.d.ts.map +1 -0
  139. package/dist/types/src/components/Form/FormLayout/index.d.ts +3 -0
  140. package/dist/types/src/components/Form/FormLayout/index.d.ts.map +1 -0
  141. package/dist/types/src/components/Form/FormLayout/parser.d.ts.map +1 -0
  142. package/dist/types/src/components/Form/FormLayout/parser.test.d.ts.map +1 -0
  143. package/dist/types/src/components/Form/index.d.ts +3 -5
  144. package/dist/types/src/components/Form/index.d.ts.map +1 -1
  145. package/dist/types/src/components/Form/meta-tags.d.ts +1 -12
  146. package/dist/types/src/components/Form/meta-tags.d.ts.map +1 -1
  147. package/dist/types/src/components/ObjectForm/ObjectForm.d.ts.map +1 -1
  148. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts +6 -23
  149. package/dist/types/src/components/ObjectPicker/ObjectPicker.d.ts.map +1 -1
  150. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts +2 -1
  151. package/dist/types/src/components/ObjectProperties/ObjectProperties.d.ts.map +1 -1
  152. package/dist/types/src/components/RefEditor/RefEditor.stories.d.ts +2 -2
  153. package/dist/types/src/components/RefEditor/RefEditor.stories.d.ts.map +1 -1
  154. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts +1 -1
  155. package/dist/types/src/components/ViewEditor/ViewEditor.d.ts.map +1 -1
  156. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts +2 -2
  157. package/dist/types/src/components/ViewEditor/ViewEditor.stories.d.ts.map +1 -1
  158. package/dist/types/src/components/index.d.ts +0 -1
  159. package/dist/types/src/components/index.d.ts.map +1 -1
  160. package/dist/types/src/hooks/index.d.ts +2 -0
  161. package/dist/types/src/hooks/index.d.ts.map +1 -1
  162. package/dist/types/src/hooks/useAsyncFieldEffect.d.ts +24 -0
  163. package/dist/types/src/hooks/useAsyncFieldEffect.d.ts.map +1 -0
  164. package/dist/types/src/hooks/useFormContext.d.ts +42 -0
  165. package/dist/types/src/hooks/useFormContext.d.ts.map +1 -0
  166. package/dist/types/src/hooks/useFormHandler.d.ts +9 -6
  167. package/dist/types/src/hooks/useFormHandler.d.ts.map +1 -1
  168. package/dist/types/src/index.d.ts +2 -0
  169. package/dist/types/src/index.d.ts.map +1 -1
  170. package/dist/types/src/{components/testing.d.ts → testing/TestLayout.d.ts} +2 -2
  171. package/dist/types/src/testing/TestLayout.d.ts.map +1 -0
  172. package/dist/types/src/testing/index.d.ts +3 -0
  173. package/dist/types/src/testing/index.d.ts.map +1 -0
  174. package/dist/types/src/testing/schema.d.ts +40 -0
  175. package/dist/types/src/testing/schema.d.ts.map +1 -0
  176. package/dist/types/src/types.d.ts +161 -0
  177. package/dist/types/src/types.d.ts.map +1 -0
  178. package/dist/types/src/util/index.d.ts +1 -1
  179. package/dist/types/src/util/index.d.ts.map +1 -1
  180. package/dist/types/src/util/omit.d.ts +12 -0
  181. package/dist/types/src/util/omit.d.ts.map +1 -0
  182. package/dist/types/tsconfig.tsbuildinfo +1 -1
  183. package/package.json +43 -41
  184. package/src/annotations.ts +63 -0
  185. package/src/components/FieldEditor/FieldEditor.stories.tsx +1 -1
  186. package/src/components/FieldEditor/FieldEditor.test.tsx +1 -1
  187. package/src/components/FieldEditor/FieldEditor.tsx +10 -6
  188. package/src/components/Form/DESIGN.md +24 -0
  189. package/src/components/Form/Form.stories.tsx +260 -61
  190. package/src/components/Form/Form.theme.test.ts +33 -0
  191. package/src/components/Form/Form.theme.ts +86 -0
  192. package/src/components/Form/Form.tsx +30 -453
  193. package/src/components/Form/FormControls.tsx +377 -0
  194. package/src/components/Form/{FormField.tsx → FormField/FormField.tsx} +98 -71
  195. package/src/components/Form/FormField/FormFieldHeader.tsx +68 -0
  196. package/src/components/Form/FormField/FormRow.stories.tsx +97 -0
  197. package/src/components/Form/FormField/FormRow.tsx +298 -0
  198. package/src/components/Form/FormField/fields/ArrayField/ArrayField.stories.tsx +119 -0
  199. package/src/components/Form/FormField/fields/ArrayField/ArrayField.tsx +328 -0
  200. package/src/components/Form/FormField/fields/ArrayField/index.ts +5 -0
  201. package/src/components/Form/FormField/fields/AsyncSelectField/AsyncSelectField.tsx +59 -0
  202. package/src/components/Form/FormField/fields/AsyncSelectField/index.ts +5 -0
  203. package/src/components/Form/FormField/fields/AutofillField/AutofillField.tsx +67 -0
  204. package/src/components/Form/FormField/fields/AutofillField/index.ts +5 -0
  205. package/src/components/Form/FormField/fields/BooleanField/BooleanField.stories.tsx +52 -0
  206. package/src/components/Form/FormField/fields/BooleanField/BooleanField.tsx +28 -0
  207. package/src/components/Form/FormField/fields/BooleanField/index.ts +5 -0
  208. package/src/components/Form/FormField/fields/ComboboxField/ComboboxField.tsx +104 -0
  209. package/src/components/Form/FormField/fields/ComboboxField/index.ts +5 -0
  210. package/src/components/Form/FormField/fields/DateField/DateField.stories.tsx +60 -0
  211. package/src/components/Form/{fields → FormField/fields/DateField}/DateField.tsx +12 -10
  212. package/src/components/Form/FormField/fields/DateField/index.ts +5 -0
  213. package/src/components/Form/FormField/fields/GeoPointField/GeoPointField.stories.tsx +53 -0
  214. package/src/components/Form/{fields → FormField/fields/GeoPointField}/GeoPointField.tsx +19 -21
  215. package/src/components/Form/FormField/fields/GeoPointField/index.ts +5 -0
  216. package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.tsx +8 -8
  217. package/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.tsx +41 -41
  218. package/src/components/Form/FormField/fields/MarkdownField/index.ts +5 -0
  219. package/src/components/Form/FormField/fields/NumberField/NumberField.stories.tsx +52 -0
  220. package/src/components/Form/FormField/fields/NumberField/NumberField.test.ts +29 -0
  221. package/src/components/Form/FormField/fields/NumberField/NumberField.tsx +140 -0
  222. package/src/components/Form/FormField/fields/NumberField/index.ts +5 -0
  223. package/src/components/Form/FormField/fields/PasswordField/PasswordField.stories.tsx +53 -0
  224. package/src/components/Form/FormField/fields/PasswordField/PasswordField.tsx +41 -0
  225. package/src/components/Form/FormField/fields/PasswordField/index.ts +5 -0
  226. package/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.tsx +21 -14
  227. package/src/components/Form/FormField/fields/RefField/RefField.stories.tsx +97 -0
  228. package/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.ts +10 -1
  229. package/src/components/Form/{fields → FormField/fields/RefField}/RefField.tsx +55 -47
  230. package/src/components/Form/FormField/fields/RefField/index.ts +6 -0
  231. package/src/components/Form/FormField/fields/SelectField/SelectField.stories.tsx +53 -0
  232. package/src/components/Form/FormField/fields/SelectField/SelectField.tsx +136 -0
  233. package/src/components/Form/FormField/fields/SelectField/index.ts +5 -0
  234. package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.tsx +5 -5
  235. package/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.tsx +56 -54
  236. package/src/components/Form/FormField/fields/SelectOptionField/index.ts +5 -0
  237. package/src/components/Form/FormField/fields/TextAreaField/TextAreaField.stories.tsx +53 -0
  238. package/src/components/Form/{fields → FormField/fields/TextAreaField}/TextAreaField.tsx +6 -4
  239. package/src/components/Form/FormField/fields/TextAreaField/index.ts +5 -0
  240. package/src/components/Form/FormField/fields/TextField/TextField.stories.tsx +52 -0
  241. package/src/components/Form/{fields → FormField/fields/TextField}/TextField.tsx +6 -4
  242. package/src/components/Form/FormField/fields/TextField/index.ts +5 -0
  243. package/src/components/Form/FormField/fields/TupleField/TupleField.stories.tsx +55 -0
  244. package/src/components/Form/{fields → FormField/fields/TupleField}/TupleField.tsx +4 -2
  245. package/src/components/Form/FormField/fields/TupleField/index.ts +5 -0
  246. package/src/components/Form/{fields → FormField/fields}/index.ts +4 -1
  247. package/src/components/Form/FormField/index.ts +10 -0
  248. package/src/components/Form/FormField/presentation.tsx +32 -0
  249. package/src/components/Form/{FormFieldSet.tsx → FormFieldSet/FormFieldSet.tsx} +53 -90
  250. package/src/components/Form/FormFieldSet/FormFieldSetContainer.tsx +93 -0
  251. package/src/components/Form/FormFieldSet/index.ts +6 -0
  252. package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.tsx +11 -9
  253. package/src/components/Form/{Layout → FormLayout}/FormLayout.tsx +29 -18
  254. package/src/components/Form/FormLayout/index.ts +6 -0
  255. package/src/components/Form/index.ts +3 -5
  256. package/src/components/Form/meta-tags.test.ts +1 -1
  257. package/src/components/Form/meta-tags.ts +1 -1
  258. package/src/components/ObjectForm/ObjectForm.tsx +15 -14
  259. package/src/components/ObjectPicker/ObjectPicker.tsx +20 -27
  260. package/src/components/ObjectProperties/ObjectProperties.stories.tsx +2 -2
  261. package/src/components/ObjectProperties/ObjectProperties.test.tsx +1 -1
  262. package/src/components/ObjectProperties/ObjectProperties.tsx +13 -8
  263. package/src/components/RefEditor/RefEditor.stories.tsx +2 -3
  264. package/src/components/RefEditor/RefEditor.tsx +1 -1
  265. package/src/components/ViewEditor/ViewEditor.stories.tsx +6 -7
  266. package/src/components/ViewEditor/ViewEditor.test.tsx +9 -3
  267. package/src/components/ViewEditor/ViewEditor.tsx +98 -128
  268. package/src/components/index.ts +0 -1
  269. package/src/hooks/index.ts +2 -0
  270. package/src/hooks/useAsyncFieldEffect.ts +81 -0
  271. package/src/hooks/useFormContext.ts +89 -0
  272. package/src/hooks/useFormHandler.ts +12 -10
  273. package/src/index.ts +2 -0
  274. package/src/{components/testing.tsx → testing/TestLayout.tsx} +16 -13
  275. package/src/testing/index.ts +7 -0
  276. package/src/testing/schema.ts +59 -0
  277. package/src/types.ts +186 -0
  278. package/src/util/index.ts +1 -1
  279. package/src/util/omit.ts +61 -0
  280. package/src/util/properties.test.ts +110 -28
  281. package/src/util/refs.ts +1 -1
  282. package/src/vitest-setup.ts +40 -0
  283. package/dist/types/src/components/Form/FormField.d.ts +0 -52
  284. package/dist/types/src/components/Form/FormField.d.ts.map +0 -1
  285. package/dist/types/src/components/Form/FormFieldComponent.d.ts +0 -98
  286. package/dist/types/src/components/Form/FormFieldComponent.d.ts.map +0 -1
  287. package/dist/types/src/components/Form/FormFieldComponent.stories.d.ts.map +0 -1
  288. package/dist/types/src/components/Form/FormFieldSet.d.ts +0 -26
  289. package/dist/types/src/components/Form/FormFieldSet.d.ts.map +0 -1
  290. package/dist/types/src/components/Form/FormTooltipsContext.d.ts +0 -19
  291. package/dist/types/src/components/Form/FormTooltipsContext.d.ts.map +0 -1
  292. package/dist/types/src/components/Form/Layout/FormLayout.d.ts.map +0 -1
  293. package/dist/types/src/components/Form/Layout/FormLayout.stories.d.ts.map +0 -1
  294. package/dist/types/src/components/Form/Layout/FormLayout.stories.test.d.ts.map +0 -1
  295. package/dist/types/src/components/Form/Layout/FormLayout.test.d.ts.map +0 -1
  296. package/dist/types/src/components/Form/Layout/annotation.d.ts +0 -30
  297. package/dist/types/src/components/Form/Layout/annotation.d.ts.map +0 -1
  298. package/dist/types/src/components/Form/Layout/index.d.ts +0 -4
  299. package/dist/types/src/components/Form/Layout/index.d.ts.map +0 -1
  300. package/dist/types/src/components/Form/Layout/parser.d.ts.map +0 -1
  301. package/dist/types/src/components/Form/Layout/parser.test.d.ts.map +0 -1
  302. package/dist/types/src/components/Form/fields/ArrayField.d.ts.map +0 -1
  303. package/dist/types/src/components/Form/fields/BooleanField.d.ts +0 -4
  304. package/dist/types/src/components/Form/fields/BooleanField.d.ts.map +0 -1
  305. package/dist/types/src/components/Form/fields/DateField.d.ts +0 -4
  306. package/dist/types/src/components/Form/fields/DateField.d.ts.map +0 -1
  307. package/dist/types/src/components/Form/fields/GeoPointField.d.ts +0 -5
  308. package/dist/types/src/components/Form/fields/GeoPointField.d.ts.map +0 -1
  309. package/dist/types/src/components/Form/fields/InlineRefField.d.ts.map +0 -1
  310. package/dist/types/src/components/Form/fields/MarkdownField.d.ts.map +0 -1
  311. package/dist/types/src/components/Form/fields/MarkdownField.stories.d.ts.map +0 -1
  312. package/dist/types/src/components/Form/fields/NumberField.d.ts +0 -4
  313. package/dist/types/src/components/Form/fields/NumberField.d.ts.map +0 -1
  314. package/dist/types/src/components/Form/fields/RefField.d.ts +0 -34
  315. package/dist/types/src/components/Form/fields/RefField.d.ts.map +0 -1
  316. package/dist/types/src/components/Form/fields/RefField.test.d.ts.map +0 -1
  317. package/dist/types/src/components/Form/fields/SelectField.d.ts +0 -13
  318. package/dist/types/src/components/Form/fields/SelectField.d.ts.map +0 -1
  319. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts +0 -5
  320. package/dist/types/src/components/Form/fields/SelectOptionField.d.ts.map +0 -1
  321. package/dist/types/src/components/Form/fields/SelectOptionField.stories.d.ts.map +0 -1
  322. package/dist/types/src/components/Form/fields/TextAreaField.d.ts +0 -4
  323. package/dist/types/src/components/Form/fields/TextAreaField.d.ts.map +0 -1
  324. package/dist/types/src/components/Form/fields/TextField.d.ts +0 -4
  325. package/dist/types/src/components/Form/fields/TextField.d.ts.map +0 -1
  326. package/dist/types/src/components/Form/fields/TupleField.d.ts.map +0 -1
  327. package/dist/types/src/components/Form/fields/index.d.ts.map +0 -1
  328. package/dist/types/src/components/Settings/Settings.d.ts +0 -51
  329. package/dist/types/src/components/Settings/Settings.d.ts.map +0 -1
  330. package/dist/types/src/components/Settings/Settings.stories.d.ts.map +0 -1
  331. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts +0 -43
  332. package/dist/types/src/components/Settings/SettingsFieldSet.d.ts.map +0 -1
  333. package/dist/types/src/components/Settings/SettingsItem.d.ts +0 -16
  334. package/dist/types/src/components/Settings/SettingsItem.d.ts.map +0 -1
  335. package/dist/types/src/components/Settings/SettingsSelectField.d.ts +0 -18
  336. package/dist/types/src/components/Settings/SettingsSelectField.d.ts.map +0 -1
  337. package/dist/types/src/components/Settings/index.d.ts +0 -4
  338. package/dist/types/src/components/Settings/index.d.ts.map +0 -1
  339. package/dist/types/src/components/testing.d.ts.map +0 -1
  340. package/dist/types/src/util/field-type.d.ts +0 -19
  341. package/dist/types/src/util/field-type.d.ts.map +0 -1
  342. package/src/components/Form/AUDIT.md +0 -17
  343. package/src/components/Form/FormFieldComponent.stories.tsx +0 -65
  344. package/src/components/Form/FormFieldComponent.tsx +0 -253
  345. package/src/components/Form/FormTooltipsContext.ts +0 -25
  346. package/src/components/Form/Layout/annotation.ts +0 -38
  347. package/src/components/Form/Layout/index.ts +0 -7
  348. package/src/components/Form/README.md +0 -3
  349. package/src/components/Form/fields/ArrayField.tsx +0 -173
  350. package/src/components/Form/fields/BooleanField.tsx +0 -22
  351. package/src/components/Form/fields/NumberField.tsx +0 -76
  352. package/src/components/Form/fields/SelectField.tsx +0 -77
  353. package/src/components/Settings/AUDIT.md +0 -51
  354. package/src/components/Settings/Settings.stories.tsx +0 -104
  355. package/src/components/Settings/Settings.tsx +0 -81
  356. package/src/components/Settings/SettingsFieldSet.tsx +0 -257
  357. package/src/components/Settings/SettingsItem.tsx +0 -58
  358. package/src/components/Settings/SettingsSelectField.tsx +0 -59
  359. package/src/components/Settings/index.ts +0 -7
  360. package/src/util/field-type.ts +0 -60
  361. /package/dist/types/src/components/Form/{fields → FormField/fields/MarkdownField}/MarkdownField.stories.d.ts +0 -0
  362. /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/InlineRefField.d.ts +0 -0
  363. /package/dist/types/src/components/Form/{fields → FormField/fields/RefField}/RefField.test.d.ts +0 -0
  364. /package/dist/types/src/components/Form/{fields → FormField/fields/SelectOptionField}/SelectOptionField.stories.d.ts +0 -0
  365. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.d.ts +0 -0
  366. /package/dist/types/src/components/Form/{Layout → FormLayout}/FormLayout.test.d.ts +0 -0
  367. /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.d.ts +0 -0
  368. /package/dist/types/src/components/Form/{Layout → FormLayout}/parser.test.d.ts +0 -0
  369. /package/src/components/Form/{Layout → FormLayout}/FormLayout.stories.test.tsx +0 -0
  370. /package/src/components/Form/{Layout → FormLayout}/FormLayout.test.ts +0 -0
  371. /package/src/components/Form/{Layout → FormLayout}/parser.test.ts +0 -0
  372. /package/src/components/Form/{Layout → FormLayout}/parser.ts +0 -0
@@ -3,12 +3,15 @@
3
3
  //
4
4
 
5
5
  export * from './ArrayField';
6
+ export * from './AsyncSelectField';
7
+ export * from './AutofillField';
6
8
  export * from './BooleanField';
9
+ export * from './ComboboxField';
7
10
  export * from './DateField';
8
11
  export * from './GeoPointField';
9
- export * from './InlineRefField';
10
12
  export * from './MarkdownField';
11
13
  export * from './NumberField';
14
+ export * from './PasswordField';
12
15
  export * from './RefField';
13
16
  export * from './SelectField';
14
17
  export * from './SelectOptionField';
@@ -0,0 +1,10 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './fields';
6
+ export * from './presentation';
7
+
8
+ export * from './FormFieldHeader';
9
+ export * from './FormField';
10
+ export * from './FormRow';
@@ -0,0 +1,32 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type FormPresentation } from '#types';
6
+
7
+ /**
8
+ * Resolved presentation strategy for a field — which parts render, derived from {@link FormPresentation}.
9
+ * Visual chrome (borders, grid, spacing) is owned by the Form theme recipe, not here.
10
+ */
11
+ export type FormFieldPresentation = {
12
+ layout?: FormPresentation;
13
+ /** Render the value as read-only plain DOM rather than an editable control. */
14
+ isStatic: boolean;
15
+ /** Render the field's label row. */
16
+ showLabel: boolean;
17
+ /** Render the inline validation/error block beneath the control. */
18
+ showError: boolean;
19
+ };
20
+
21
+ /**
22
+ * Derive the {@link FormFieldPresentation} for a layout.
23
+ * - `static` renders read-only plain DOM.
24
+ * - `inline` drops the label (the control stands alone, e.g. an array row).
25
+ * - `full` adds the inline error block.
26
+ */
27
+ export const presentationFor = (layout?: FormPresentation): FormFieldPresentation => ({
28
+ layout,
29
+ isStatic: layout === 'static',
30
+ showLabel: layout !== 'inline',
31
+ showError: layout === 'full',
32
+ });
@@ -3,81 +3,66 @@
3
3
  //
4
4
 
5
5
  import * as Option from 'effect/Option';
6
- import React, { useMemo, useState } from 'react';
6
+ import React, { useMemo } from 'react';
7
7
 
8
+ import { DEFAULT_LAYOUT_NAME, FormLayoutAnnotation } from '@dxos/echo/Annotation';
8
9
  import { type AnyProperties } from '@dxos/echo/internal';
9
10
  import { SchemaEx } from '@dxos/effect';
10
- import { IconButton, useTranslation } from '@dxos/react-ui';
11
- import { mx } from '@dxos/ui-theme';
11
+ import { type Merge } from '@dxos/util';
12
12
 
13
- import { translationKey } from '#translations';
13
+ import { type FieldContext } from '#types';
14
14
 
15
- import { type FormHandlerProps } from '../../hooks';
16
- import { getRootFormProperties } from '../../util';
17
- import { useFormValues } from './Form';
18
- import { FormField, type FormFieldProps } from './FormField';
19
- import { FormFieldErrorBoundary, FormFieldLabel } from './FormFieldComponent';
20
- import { DEFAULT_LAYOUT_NAME, FormLayout, FormLayoutAnnotation } from './Layout';
15
+ import { type FormHandlerProps, useFormValues } from '../../../hooks';
16
+ import { getRootFormProperties } from '../../../util';
17
+ import { FormField, FormFieldErrorBoundary, type FormFieldProps, presentationFor } from '../FormField';
18
+ import { FormLayout } from '../FormLayout';
19
+ import { FormFieldSetContainer } from './FormFieldSetContainer';
21
20
 
22
21
  const FORM_FIELDSET_NAME = 'Form.FieldSet';
23
22
 
24
- export type FormFieldSetProps<T extends AnyProperties> = {
25
- label?: string;
26
- sort?: string[];
27
- /**
28
- * When set, renders a toggle button at the end of the label row that
29
- * shows/hides the field set body. Used for nested objects.
30
- */
31
- collapsible?: boolean;
32
- exclude?: (props: SchemaEx.SchemaProperty[]) => SchemaEx.SchemaProperty[];
33
- /**
34
- * Picks a named layout out of `FormLayoutAnnotation` when present.
35
- * Falls back to `'default'`. Ignored when the schema has no annotation
36
- * (linear rendering then takes over).
37
- */
38
- layoutName?: string;
39
- } & Pick<FormHandlerProps<T>, 'schema'> &
40
- Pick<
41
- FormFieldProps,
42
- | 'path'
43
- | 'autoFocus'
44
- | 'readonly'
45
- | 'layout'
46
- | 'projection'
47
- | 'fieldMap'
48
- | 'fieldProvider'
49
- | 'createTypename'
50
- | 'createOptionLabel'
51
- | 'createOptionIcon'
52
- | 'createInitialValuePath'
53
- | 'createFieldMap'
54
- | 'db'
55
- | 'useType'
56
- | 'getOptions'
57
- | 'onCreate'
58
- >;
23
+ export type FormFieldSetProps<T extends AnyProperties> = Merge<
24
+ {
25
+ /** Applied to the field set's container (the bordered box when collapsible). */
26
+ classNames?: string;
27
+ label?: string;
28
+ sort?: string[];
29
+ /**
30
+ * When set, renders a toggle button at the end of the label row that
31
+ * shows/hides the field set body. Used for nested objects.
32
+ */
33
+ collapsible?: boolean;
34
+ filter?: (props: SchemaEx.SchemaProperty[]) => SchemaEx.SchemaProperty[];
35
+ /**
36
+ * Picks a named layout out of `FormLayoutAnnotation` when present.
37
+ * Falls back to `'default'`. Ignored when the schema has no annotation
38
+ * (linear rendering then takes over).
39
+ */
40
+ layoutName?: string;
41
+ },
42
+ Pick<FormHandlerProps<T>, 'schema'>,
43
+ Pick<FormFieldProps, 'path' | 'autoFocus'>,
44
+ FieldContext
45
+ >;
59
46
 
60
47
  /**
61
48
  * Renders a set of form fields derived from a schema object.
62
49
  */
63
50
  export const FormFieldSet = ({
51
+ classNames,
64
52
  label,
65
53
  schema,
66
54
  readonly,
67
55
  path,
68
56
  sort,
69
57
  collapsible,
70
- exclude,
58
+ filter,
71
59
  projection,
72
60
  layout,
73
61
  layoutName = DEFAULT_LAYOUT_NAME,
74
62
  ...props
75
63
  }: FormFieldSetProps<any>) => {
76
- const { t } = useTranslation(translationKey);
77
64
  const values = useFormValues(FORM_FIELDSET_NAME, path);
78
- const properties = useFormFieldSetProperties({ schema, values, exclude, sort, projection });
79
- // TODO(burdon): Generalize collapse state (cf. useSelected in react-ui-attention, plugin-markdown cursor state).
80
- const [collapsed, setCollapsed] = useState(false);
65
+ const properties = useFormFieldSetProperties({ schema, values, filter, sort, projection });
81
66
  if ((readonly || layout === 'static') && values == null) {
82
67
  return null;
83
68
  }
@@ -105,6 +90,7 @@ export const FormFieldSet = ({
105
90
  type={property.type}
106
91
  name={name}
107
92
  path={[...(path ?? []), name]}
93
+ required={!property.isOptional}
108
94
  readonly={readonly}
109
95
  layout={layout}
110
96
  projection={projection}
@@ -115,56 +101,33 @@ export const FormFieldSet = ({
115
101
  })
116
102
  );
117
103
 
118
- const showBody = !(collapsible && collapsed);
119
- const content = (
120
- <>
121
- {layout !== 'inline' && label && (
122
- <FormFieldLabel
123
- asChild
124
- classNames='pl-2'
125
- label={label}
126
- path={SchemaEx.createJsonPath(path ?? [])}
127
- button={
128
- collapsible && (
129
- <IconButton
130
- classNames='px-1 mr-0.5'
131
- variant='ghost'
132
- density='xs'
133
- iconOnly
134
- icon='ph--caret-right--regular'
135
- iconClassNames={mx('transition-transform', !collapsed && 'rotate-90')}
136
- label={t(collapsed ? 'expand-fields.label' : 'collapse-fields.label')}
137
- />
138
- )
139
- }
140
- onClick={() => setCollapsed((value) => !value)}
141
- />
142
- )}
143
- {showBody && (collapsible ? <div className='px-2 pb-2'>{body}</div> : body)}
144
- </>
104
+ return (
105
+ <FormFieldSetContainer
106
+ classNames={classNames}
107
+ label={label}
108
+ path={SchemaEx.createJsonPath(path ?? [])}
109
+ readonly={readonly}
110
+ presentation={presentationFor(layout)}
111
+ collapsible={collapsible}
112
+ >
113
+ {body}
114
+ </FormFieldSetContainer>
145
115
  );
146
-
147
- // Nested field sets render inside an indented, bordered container with a collapse toggle.
148
- if (collapsible) {
149
- return <div className='border border-subdued-separator rounded-sm mt-2'>{content}</div>;
150
- }
151
-
152
- return content;
153
116
  };
154
117
 
155
118
  FormFieldSet.displayName = FORM_FIELDSET_NAME;
156
119
 
157
- type UseFormFieldSetPropertiesParams = Pick<FormFieldSetProps<any>, 'schema' | 'exclude' | 'projection' | 'sort'> & {
120
+ type UseFormFieldSetPropertiesParams = Pick<FormFieldSetProps<any>, 'schema' | 'filter' | 'projection' | 'sort'> & {
158
121
  values: AnyProperties | undefined;
159
122
  sort?: string[];
160
123
  };
161
124
 
162
125
  /**
163
- * Resolves ordered schema properties for a field set (projection order, exclude, or sort).
126
+ * Resolves ordered schema properties for a field set (projection order, filter, or sort).
164
127
  */
165
128
  const useFormFieldSetProperties = ({
166
129
  schema,
167
- exclude,
130
+ filter,
168
131
  projection,
169
132
  values,
170
133
  sort,
@@ -176,9 +139,9 @@ const useFormFieldSetProperties = ({
176
139
  return [];
177
140
  }
178
141
 
179
- // TODO(wittjosiah): Reconcile FormInputAnnotation with projection hidden properties & exclude function.
142
+ // TODO(wittjosiah): Reconcile FormInputAnnotation with projection hidden properties & filter function.
180
143
  const schemaProps = getRootFormProperties(schema.ast, values);
181
- const filteredProps = exclude ? exclude(schemaProps) : schemaProps;
144
+ const filteredProps = filter ? filter(schemaProps) : schemaProps;
182
145
 
183
146
  // Use projection-based field management when view and projection are available.
184
147
  if (projection) {
@@ -209,5 +172,5 @@ const useFormFieldSetProperties = ({
209
172
  return sort
210
173
  ? [...filteredProps].sort(({ name: a }, { name: b }) => sort.indexOf(a.toString()) - sort.indexOf(b.toString()))
211
174
  : filteredProps;
212
- }, [schema, values, exclude, sort, projection]);
175
+ }, [schema, values, filter, sort, projection]);
213
176
  };
@@ -0,0 +1,93 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren, useState } from 'react';
6
+
7
+ import { type ThemedClassName, ToggleIconButton, useTranslation } from '@dxos/react-ui';
8
+ import { mx } from '@dxos/ui-theme';
9
+
10
+ import { translationKey } from '#translations';
11
+
12
+ import { formTheme } from '../Form.theme';
13
+ import { FormFieldHeader } from '../FormField/FormFieldHeader';
14
+ import { type FormFieldPresentation } from '../FormField/presentation';
15
+
16
+ const styles = formTheme.styles();
17
+
18
+ export type FormFieldSetContainerProps = ThemedClassName<
19
+ PropsWithChildren<{
20
+ label?: string;
21
+ /** JSON path of the group, forwarded to the label as field metadata. */
22
+ path?: string;
23
+ readonly?: boolean;
24
+ presentation: FormFieldPresentation;
25
+ /**
26
+ * Render a collapse toggle in the header and wrap the body in an indented, bordered box.
27
+ * Used for nested objects (struct fields, object-array items, inline refs).
28
+ */
29
+ collapsible?: boolean;
30
+ }>
31
+ >;
32
+
33
+ /**
34
+ * Shared chrome for a labelled group of sub-fields: an optional header (label + collapse toggle) and,
35
+ * when collapsible, an indented bordered container around the body. Nested structs, object-array items,
36
+ * and inline refs all reach this via `FormFieldSet`, so their visual containment is identical.
37
+ */
38
+ export const FormFieldSetContainer = ({
39
+ classNames,
40
+ label,
41
+ path,
42
+ readonly,
43
+ presentation,
44
+ collapsible,
45
+ children,
46
+ }: FormFieldSetContainerProps) => {
47
+ const { t } = useTranslation(translationKey);
48
+ // TODO(burdon): Generalize collapse state (cf. useSelection in react-ui-attention, plugin-markdown cursor state).
49
+ const [collapsed, setCollapsed] = useState(false);
50
+ const showBody = !(collapsible && collapsed);
51
+
52
+ const content = (
53
+ <>
54
+ {presentation.showLabel && label && (
55
+ <FormFieldHeader
56
+ label={label}
57
+ path={path}
58
+ readonly={readonly}
59
+ classNames='pl-2'
60
+ actions={
61
+ collapsible ? (
62
+ <ToggleIconButton
63
+ active={!collapsed}
64
+ classNames='px-1 mr-0.5'
65
+ variant='ghost'
66
+ density='xs'
67
+ iconOnly
68
+ icon='ph--caret-right--regular'
69
+ label={t(collapsed ? 'expand-fields.label' : 'collapse-fields.label')}
70
+ />
71
+ ) : undefined
72
+ }
73
+ onClick={collapsible ? () => setCollapsed((value) => !value) : undefined}
74
+ />
75
+ )}
76
+ {showBody && (collapsible ? <div className={styles.fieldSetBody()}>{children}</div> : children)}
77
+ </>
78
+ );
79
+
80
+ // Nested groups render inside an indented, bordered container with a collapse toggle. A non-collapsible
81
+ // group only materializes a wrapper when `classNames` is supplied — otherwise the body flows straight
82
+ // into the parent grid (the default, grid-transparent behavior).
83
+ if (collapsible) {
84
+ return (
85
+ <div className={styles.fieldSetBoxOuter()}>
86
+ <div className={styles.fieldSetBox({ class: mx(classNames) })}>{content}</div>
87
+ </div>
88
+ );
89
+ }
90
+
91
+ // Only materialize a wrapper when `classNames` is supplied; otherwise stay grid-transparent.
92
+ return classNames ? <div className={mx(classNames)}>{content}</div> : <>{content}</>;
93
+ };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './FormFieldSet';
6
+ export * from './FormFieldSetContainer';
@@ -19,9 +19,9 @@ import { trim } from '@dxos/util';
19
19
 
20
20
  import { translations } from '#translations';
21
21
 
22
- import { TestLayout, TestPanel } from '../../testing';
23
- import { Form, type FormRootProps, omitId } from '../Form';
24
- import { FormLayoutAnnotation } from './annotation';
22
+ import { TestLayout, TestPanel } from '../../../testing';
23
+ import { omitId } from '../../../util';
24
+ import { Form, type FormRootProps } from '../Form';
25
25
  import { parseLayout } from './parser';
26
26
 
27
27
  /**
@@ -84,7 +84,7 @@ const FLIGHT_LAYOUT_COMPACT = trim`
84
84
  */
85
85
  const AnnotatedFlight = Type.getSchema(Flight)
86
86
  .annotations({})
87
- .pipe(FormLayoutAnnotation.set({ default: FLIGHT_LAYOUT, compact: FLIGHT_LAYOUT_COMPACT }));
87
+ .pipe(Annotation.FormLayoutAnnotation.set({ default: FLIGHT_LAYOUT, compact: FLIGHT_LAYOUT_COMPACT }));
88
88
 
89
89
  /**
90
90
  * Sample schema with nested `Place` structs carrying a `LabelAnnotation`.
@@ -125,12 +125,12 @@ const JOURNEY_LAYOUT = trim`
125
125
  </grid>
126
126
  `;
127
127
 
128
- type StoryProps = {
128
+ type StoryArgs = {
129
129
  schema: Schema.Schema<any>;
130
130
  template?: string;
131
131
  };
132
132
 
133
- const DefaultStory = ({ schema, template }: StoryProps) => {
133
+ const DefaultStory = ({ schema, template }: StoryArgs) => {
134
134
  const [values, setValues] = useState<Partial<FlightValues>>(flight);
135
135
 
136
136
  const handleSave = useCallback<NonNullable<FormRootProps<any>['onSave']>>((next) => {
@@ -164,11 +164,11 @@ const meta = {
164
164
  layout: 'fullscreen',
165
165
  translations,
166
166
  },
167
- } satisfies Meta<StoryProps>;
167
+ } satisfies Meta<StoryArgs>;
168
168
 
169
169
  export default meta;
170
170
 
171
- type Story = StoryObj<StoryProps>;
171
+ type Story = StoryObj<StoryArgs>;
172
172
 
173
173
  /** Baseline: no annotation, no override — `Form.FieldSet` renders linearly (one field per row). */
174
174
  export const Linear: Story = {
@@ -383,7 +383,9 @@ const PlaygroundStory = ({ card = false }: PlaygroundStoryProps) => {
383
383
  onChange={setTemplate}
384
384
  />
385
385
  </Editor.Root>
386
- {error && <div className='border-t border-separator p-2 text-sm text-error-text font-mono'>{error}</div>}
386
+ {error && (
387
+ <div className='border-t border-input-separator p-2 text-sm text-error-text font-mono'>{error}</div>
388
+ )}
387
389
  </div>
388
390
  </TestPanel>
389
391
  <TestPanel>
@@ -13,11 +13,12 @@ import { type AnyProperties } from '@dxos/echo/internal';
13
13
  import { SchemaEx } from '@dxos/effect';
14
14
  import { Input } from '@dxos/react-ui';
15
15
 
16
- import { useFormFieldState } from '../Form';
17
- import { FormField, type FormFieldProps } from '../FormField';
18
- import { FormFieldErrorBoundary, FormFieldLabel, type Presentation } from '../FormFieldComponent';
19
- import { DEFAULT_LAYOUT_NAME, FormLayoutAnnotation } from './annotation';
20
- import { LayoutParseError, type LayoutNode, parseLayout } from './parser';
16
+ import { type FormPresentation } from '#types';
17
+
18
+ import { useFormContext, useFormFieldState } from '../../../hooks';
19
+ import { formTheme } from '../Form.theme';
20
+ import { FormField, FormFieldErrorBoundary, FormFieldLabel, type FormFieldProps, presentationFor } from '../FormField';
21
+ import { type LayoutNode, LayoutParseError, parseLayout } from './parser';
21
22
 
22
23
  const FORM_LAYOUT_NAME = 'Form.Layout';
23
24
 
@@ -57,14 +58,14 @@ type FormFieldSetSubset = Pick<
57
58
  export const FormLayout = ({
58
59
  schema,
59
60
  template,
60
- name = DEFAULT_LAYOUT_NAME,
61
+ name = Annotation.DEFAULT_LAYOUT_NAME,
61
62
  path,
62
63
  readonly,
63
64
  layout,
64
65
  projection,
65
66
  ...props
66
67
  }: FormLayoutProps) => {
67
- const annotated = Option.getOrUndefined(FormLayoutAnnotation.get(schema));
68
+ const annotated = Option.getOrUndefined(Annotation.FormLayoutAnnotation.get(schema));
68
69
  const source = template ?? annotated?.[name];
69
70
  if (source === undefined) {
70
71
  throw new LayoutParseError(
@@ -114,7 +115,7 @@ const RenderNode = ({ node, schema, basePath, ...props }: RenderNodeProps) => {
114
115
  throw new LayoutParseError(`field "${node.name}" not found on schema`);
115
116
  }
116
117
 
117
- const { type, segments, leafName, title, labelType } = resolved;
118
+ const { type, segments, leafName, title, labelType, required } = resolved;
118
119
  const path = [...basePath, ...segments];
119
120
  const span = node.span ? { gridColumn: `span ${node.span} / span ${node.span}` } : undefined;
120
121
 
@@ -129,7 +130,7 @@ const RenderNode = ({ node, schema, basePath, ...props }: RenderNodeProps) => {
129
130
  layout={props.layout}
130
131
  />
131
132
  ) : (
132
- <FormField type={type} name={leafName} path={path} {...props} />
133
+ <FormField type={type} name={leafName} path={path} required={required} {...props} />
133
134
  )}
134
135
  </FormFieldErrorBoundary>
135
136
  </div>
@@ -151,6 +152,8 @@ export type ResolvedLayoutField = {
151
152
  * sub-fields. Undefined for ordinary (non-auto-labelled) fields.
152
153
  */
153
154
  labelType?: SchemaAST.AST;
155
+ /** Whether the resolved property is required (non-optional). */
156
+ required: boolean;
154
157
  };
155
158
 
156
159
  /**
@@ -215,6 +218,7 @@ export const resolveLayoutField = (schema: Schema.Schema<any>, name: string): Re
215
218
  leafName: segments[segments.length - 1],
216
219
  title,
217
220
  labelType: labelled ? labelType : undefined,
221
+ required: !prop.isOptional,
218
222
  };
219
223
  };
220
224
 
@@ -222,7 +226,7 @@ type LabelFieldProps = {
222
226
  schema: Schema.Schema<any>;
223
227
  label: string;
224
228
  path: (string | number)[];
225
- layout?: Presentation;
229
+ layout?: FormPresentation;
226
230
  };
227
231
 
228
232
  /**
@@ -231,6 +235,8 @@ type LabelFieldProps = {
231
235
  * presentation of regular fields.
232
236
  */
233
237
  const LabelField = ({ schema, label, path, layout }: LabelFieldProps) => {
238
+ const { variant = 'default' } = useFormContext(FORM_LAYOUT_NAME);
239
+ const styles = formTheme.styles({ variant });
234
240
  const { getValue } = useFormFieldState(FORM_LAYOUT_NAME, path);
235
241
  const value = getValue();
236
242
  const text = value == null ? undefined : Annotation.getLabelWithSchema(schema, value);
@@ -238,14 +244,19 @@ const LabelField = ({ schema, label, path, layout }: LabelFieldProps) => {
238
244
  return null;
239
245
  }
240
246
 
247
+ const presentation = presentationFor(layout);
241
248
  return (
242
- <div className='contents'>
243
- <Input.Root>
244
- {layout !== 'inline' && <FormFieldLabel readonly label={label} path={SchemaEx.createJsonPath(path)} />}
245
- <p className='truncate min-w-0' title={text}>
246
- {text}
247
- </p>
248
- </Input.Root>
249
- </div>
249
+ <Input.Root>
250
+ <div className={styles.field()}>
251
+ {presentation.showLabel && (
252
+ <FormFieldLabel variant={variant} readonly label={label} path={SchemaEx.createJsonPath(path)} />
253
+ )}
254
+ <div className={styles.fieldControl()}>
255
+ <p className='truncate min-w-0' title={text}>
256
+ {text}
257
+ </p>
258
+ </div>
259
+ </div>
260
+ </Input.Root>
250
261
  );
251
262
  };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { FormLayout, type FormLayoutProps } from './FormLayout';
6
+ export { type LayoutNode, LayoutParseError, parseLayout } from './parser';
@@ -2,10 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './fields';
5
+ export * from './meta-tags';
6
6
 
7
7
  export * from './Form';
8
- export * from './FormFieldComponent';
9
- export * from './FormTooltipsContext';
10
- export * from './meta-tags';
11
- export * from './Layout';
8
+ export * from './FormField';
9
+ export * from './FormFieldSet';
@@ -11,7 +11,7 @@ import { Obj, Ref, Tag } from '@dxos/echo';
11
11
  import { META_TAGS_KEY, withMetaTags } from './meta-tags';
12
12
 
13
13
  // A feed-host schema whose own `tags` field is a `TagIndex` record (tagId -> objectId[]), not an
14
- // array — mirrors plugin-commerce `Search`, plugin-inbox `Mailbox`, plugin-feed `Subscription`.
14
+ // array — mirrors plugin-commerce `Search`, plugin-inbox `Mailbox`, plugin-magazine `Subscription`.
15
15
  const TagIndexHost = Schema.Struct({
16
16
  name: Schema.String.pipe(Schema.optional),
17
17
  tags: Schema.Record({ key: Schema.String, value: Schema.Array(Obj.ID) }).pipe(Schema.optional),
@@ -6,7 +6,7 @@ import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { Ref, Tag } from '@dxos/echo';
8
8
 
9
- import { omitId } from './Form';
9
+ import { omitId } from '../../util';
10
10
 
11
11
  /**
12
12
  * Form-field key for the synthetic meta-tags array spliced into property/create forms.
@@ -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, presentation, 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
+ {presentation !== 'inline' && <Form.Label label={label} />}
108
+ <HuePicker value={getValue()} onChange={handleChange} onReset={handleReset} />
109
+ </>
110
+ );
111
+ },
112
+ };