@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
@@ -0,0 +1,33 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { formTheme } from './Form.theme';
8
+
9
+ describe('formTheme', () => {
10
+ test('default variant adds no chrome to the field', ({ expect }) => {
11
+ const styles = formTheme.styles({ variant: 'default' });
12
+ expect(styles.field()).toBeFalsy();
13
+ expect(formTheme.behavior.default.showDescription).toBe(false);
14
+ });
15
+
16
+ test('settings variant frames the field and shows the description', ({ expect }) => {
17
+ const styles = formTheme.styles({ variant: 'settings' });
18
+ // Assert stable invariants (bordered, grid-framed, prominent label, right-aligned control),
19
+ // not the specific grid mechanism, so the test survives layout tweaks.
20
+ expect(styles.field()).toContain('border');
21
+ expect(styles.field()).toContain('grid');
22
+ expect(styles.fieldLabel()).toContain('[grid-area:header]');
23
+ expect(styles.fieldLabelText()).toContain('text-lg');
24
+ expect(styles.fieldControl()).toContain('justify-end');
25
+ expect(formTheme.behavior.settings.showDescription).toBe(true);
26
+ });
27
+
28
+ test('per-slot override wins', ({ expect }) => {
29
+ const styles = formTheme.styles({ variant: 'settings' });
30
+ expect(styles.fieldLabelText({ class: 'text-2xl' })).toContain('text-2xl');
31
+ expect(styles.fieldLabelText({ class: 'text-2xl' })).not.toContain('text-lg');
32
+ });
33
+ });
@@ -0,0 +1,86 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type VariantProps, mx, tv } from '@dxos/ui-theme';
6
+
7
+ /** Visual variants for {@link Form}. `settings` is the bordered two-column settings-panel look. */
8
+ export type FormVariant = NonNullable<VariantProps<typeof formStyles>['variant']>;
9
+
10
+ /** Non-className behavior flags, keyed by {@link FormVariant}. */
11
+ export type FormBehavior = { showDescription: boolean };
12
+
13
+ const formStyles = tv({
14
+ slots: {
15
+ viewport: '',
16
+ content: '',
17
+ section: 'flex flex-col py-form-section-gap first:pt-0',
18
+ group: 'flex flex-col gap-3 p-trim-md border border-separator rounded-sm',
19
+ sectionHeader: '',
20
+ sectionTitle: 'text-lg',
21
+ sectionDescription: 'text-description',
22
+ fieldSet: '',
23
+ field: '',
24
+ fieldLabel: 'h-8 grid grid-cols-[1fr_auto_auto] items-center select-none',
25
+ fieldLabelText: '',
26
+ fieldDescription: 'text-description',
27
+ fieldControl: '',
28
+ fieldValidation: '',
29
+ // Action bar (cancel/save), equal-width columns flowing horizontally.
30
+ actions: 'grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding',
31
+ // Standalone submit row (full-width primary button).
32
+ submit: 'flex w-full pt-form-padding',
33
+ // Collapsible field-set body: indented column of sub-fields.
34
+ fieldSetBody: 'flex flex-col gap-2 px-2 pb-2',
35
+ // Bordered container wrapping a collapsible nested group, plus its top spacing.
36
+ fieldSetBox: 'border border-subdued-separator rounded-sm',
37
+ fieldSetBoxOuter: 'pt-trim-md',
38
+ },
39
+ variants: {
40
+ variant: {
41
+ default: {},
42
+ settings: {
43
+ content: 'dx-document',
44
+ // Gap on the section spaces its direct children — section title/description and, for action
45
+ // panels, the `Form.Row`s placed directly in the section (which have no `fieldSet` wrapper).
46
+ section: 'py-form-section-gap! gap-trim-md',
47
+ sectionHeader: 'pb-form-section-gap',
48
+ sectionTitle: 'px-trim-md text-xl',
49
+ sectionDescription: 'px-trim-md',
50
+ // No top padding: the section gap already separates the field set from the title above it.
51
+ fieldSet: 'flex flex-col gap-trim-md',
52
+ field: mx(
53
+ 'grid',
54
+ 'grid-cols-1 [grid-template-areas:"header""description""control""validation"]',
55
+ 'md:grid-cols-2 md:[grid-template-areas:"header_header""description_control""validation_validation"]',
56
+ 'gap-x-trim-lg gap-y-0 p-trim-md border border-input-separator rounded-md',
57
+ ),
58
+ fieldLabel: '[grid-area:header]',
59
+ fieldLabelText: 'text-base-fg text-lg',
60
+ fieldDescription: '[grid-area:description] pt-1 text-description',
61
+ fieldControl: '[grid-area:control] flex justify-end items-start md:text-right pt-3 md:pt-0',
62
+ fieldValidation: '[grid-area:validation]',
63
+ },
64
+ },
65
+ },
66
+ defaultVariants: {
67
+ variant: 'default',
68
+ },
69
+ });
70
+
71
+ /** {@link Form} theme template: a tailwind-variants recipe (`styles`) plus non-class `behavior`. */
72
+ export const formTheme = {
73
+ styles: formStyles,
74
+ behavior: {
75
+ default: {
76
+ showDescription: false,
77
+ },
78
+ settings: {
79
+ showDescription: true,
80
+ },
81
+ } satisfies Record<FormVariant, FormBehavior>,
82
+ };
83
+
84
+ /** Slot names of {@link formTheme.styles}, for `bridgeTv` registration. */
85
+ // Object.keys widens to string[]; the slot names are statically known.
86
+ export const formSlots = Object.keys(formTheme.styles()) as Array<keyof ReturnType<typeof formTheme.styles>>;
@@ -2,474 +2,51 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { createContext } from '@radix-ui/react-context';
6
- import * as Option from 'effect/Option';
7
- import * as Schema from 'effect/Schema';
8
- import * as SchemaAST from 'effect/SchemaAST';
9
- import React, { type PropsWithChildren, useEffect, useMemo, useRef } from 'react';
10
-
11
- import { Annotation as EchoAnnotation, Type } from '@dxos/echo';
12
- import { type AnyProperties } from '@dxos/echo/internal';
13
- import { SchemaEx } from '@dxos/effect';
14
- import {
15
- Column,
16
- type ColumnRootProps,
17
- IconButton,
18
- type IconButtonProps,
19
- Input,
20
- ScrollArea,
21
- type ThemedClassName,
22
- useMergeRefs,
23
- useTranslation,
24
- } from '@dxos/react-ui';
25
- import { composable, composableProps, withColumn } from '@dxos/react-ui';
26
- import { mx } from '@dxos/ui-theme';
27
-
28
- import { translationKey } from '#translations';
29
-
30
5
  import {
31
- type FormHandler,
32
- type FormHandlerProps,
33
- type FormUpdateMeta,
34
- useFormHandler,
35
- useKeyHandler,
36
- } from '../../hooks';
37
- import { FormFieldLabel, type FormFieldLabelProps, type FormFieldStateProps } from './FormFieldComponent';
38
- import {
39
- FormFieldSet as NaturalFormFieldSet,
40
- type FormFieldSetProps as NaturalFormFieldSetProps,
41
- } from './FormFieldSet';
42
- import { FormTooltipsContext } from './FormTooltipsContext';
43
- import { FormLayout as NaturalFormLayout } from './Layout';
44
- import { type FormLayoutProps as NaturalFormLayoutProps } from './Layout/FormLayout';
45
-
46
- // TODO(burdon): Move styles to form.ts (as with ui-theme).
47
-
48
- // TODO(burdon): Reconcile with @dxos/echo.
49
- export type ExcludeId<S extends Schema.Schema.AnyNoContext | Type.AnyEntity> = Omit<
50
- S extends Type.AnyEntity
51
- ? Type.InstanceType<S>
52
- : S extends Schema.Schema.AnyNoContext
53
- ? Schema.Schema.Type<S>
54
- : never,
55
- 'id'
56
- >;
57
-
58
- // TODO(burdon): Move to @dxos/schema (re-export here).
59
- export const omitId = <S extends Schema.Schema.AnyNoContext | Type.AnyEntity>(
60
- schemaOrType: S,
61
- ): Schema.Schema<ExcludeId<S>, ExcludeId<S>> => {
62
- const schema = Type.isType(schemaOrType)
63
- ? Type.getSchema(schemaOrType)
64
- : (schemaOrType as Schema.Schema.AnyNoContext);
65
- return schema.pipe(Schema.omit('id')) as any;
66
- };
67
-
68
- /**
69
- * Drop fields annotated with `FormInputAnnotation.set(false)` from a schema so
70
- * the form's validator doesn't trip on required-but-hidden fields. Used by
71
- * the picker's inline create form, where a `FactoryAnnotation` typically
72
- * supplies the hidden values (e.g. a backing-object Ref) outside the form.
73
- */
74
- export const omitHiddenFormFields = <S extends Schema.Schema.AnyNoContext>(schema: S): S => {
75
- const properties = SchemaAST.getPropertySignatures(schema.ast);
76
- const hidden = properties
77
- .filter((prop) => Option.getOrElse(EchoAnnotation.FormInputAnnotation.getFromAst(prop.type), () => true) === false)
78
- .map((prop) => prop.name as string);
79
- return hidden.length === 0 ? schema : (schema.pipe(Schema.omit(...(hidden as [string, ...string[]]))) as any);
80
- };
81
-
82
- //
83
- // Context
84
- //
85
-
86
- type FormContextValue<T extends AnyProperties = any> = {
87
- /**
88
- * Form handler.
89
- */
90
- form: FormHandler<T>;
91
-
92
- /**
93
- * Show field tooltips (currently: JSON path on each label). Defaults to
94
- * `true`; pass `false` to suppress.
95
- */
96
- tooltips?: boolean;
97
-
98
- /**
99
- * Testing.
100
- */
101
- testId?: string;
102
- } & Pick<
103
- NaturalFormFieldSetProps<T>,
104
- 'readonly' | 'layout' | 'fieldMap' | 'fieldProvider' | 'projection' | 'createTypename' | 'createFieldMap' | 'db'
105
- >;
106
-
107
- const [FormContextProvider, useFormContext] = createContext<FormContextValue>('Form');
108
-
109
- /**
110
- * Get the current form values.
111
- */
112
- const useFormValues: {
113
- <T extends AnyProperties>(componentName: string, path?: (string | number)[]): T;
114
- <T extends AnyProperties>(
115
- componentName: string,
116
- path: (string | number)[] | undefined,
117
- defaultValue: () => T,
118
- ): T | undefined;
119
- } = (componentName: string, path?: (string | number)[], defaultValue?: () => any) => {
120
- const stablePath = useMemo(() => path ?? [], [path ? path.join('.') : undefined]);
121
- const jsonPath = SchemaEx.createJsonPath(stablePath);
122
- const {
123
- form: { values, onValueChange },
124
- } = useFormContext(componentName);
125
-
126
- const value = SchemaEx.getValue(values, jsonPath);
127
-
128
- // Apply default value once when the field has no value. lastAppliedPathRef prevents
129
- // re-applying on every render (e.g. when defaultValue() returns null) and ensures
130
- // we apply per path when the hook is used for different fields.
131
- const lastAppliedPathRef = useRef<string | null>(null);
132
- useEffect(() => {
133
- if (value == null && defaultValue && lastAppliedPathRef.current !== jsonPath) {
134
- lastAppliedPathRef.current = jsonPath;
135
- onValueChange(stablePath, SchemaAST.stringKeyword, defaultValue());
136
- }
137
- }, [value, defaultValue, onValueChange, stablePath, jsonPath]);
138
-
139
- return value;
140
- };
141
-
142
- /**
143
- * Get the state props for the given field.
144
- */
145
- const useFormFieldState = (componentName: string, path: (string | number)[] = []): FormFieldStateProps => {
146
- const stablePath = useMemo(() => path, [Array.isArray(path) ? path.join('.') : path]);
147
- const {
148
- form: { getStatus, getValue, onBlur, onValueChange },
149
- } = useFormContext(componentName);
150
-
151
- return useMemo(
152
- () => ({
153
- getStatus: () => getStatus(stablePath),
154
- getValue: () => getValue(stablePath),
155
- onBlur: () => onBlur(stablePath),
156
- onValueChange: (ast: SchemaAST.AST, value: any) => onValueChange(stablePath, ast, value),
157
- }),
158
- [getStatus, getValue, onBlur, onValueChange, stablePath],
159
- );
160
- };
161
-
162
- //
163
- // Root
164
- //
165
-
166
- type FormRootProps<T extends AnyProperties = AnyProperties> = PropsWithChildren<
167
- {
168
- /**
169
- * Called when the form is submitted and passes validation.
170
- */
171
- onSave?: (values: T, meta: FormUpdateMeta<T>) => void;
172
-
173
- /**
174
- * Called when the form is canceled to abandon/undo any pending changes.
175
- */
176
- onCancel?: () => void;
177
- } & Omit<FormContextValue<T>, 'form'> &
178
- Pick<FormHandlerProps<T>, 'schema' | 'autoSave' | 'values' | 'defaultValues' | 'onValidate' | 'onValuesChanged'> &
179
- Omit<NaturalFormFieldSetProps<T>, 'schema' | 'path'>
180
- >;
181
-
182
- const FormRoot = <T extends AnyProperties = AnyProperties>({
183
- children,
184
- schema,
185
- values,
186
- onSave,
187
- onCancel,
188
- ...props
189
- }: FormRootProps<T>) => {
190
- const form = useFormHandler({ schema, values, onSave, onCancel, ...props });
191
-
192
- return (
193
- <FormTooltipsContext.Provider value={props.tooltips ?? true}>
194
- <FormContextProvider form={form} {...props}>
195
- {children}
196
- </FormContextProvider>
197
- </FormTooltipsContext.Provider>
198
- );
199
- };
200
-
201
- FormRoot.displayName = 'Form.Root';
202
-
203
- //
204
- // Viewport
205
- //
206
-
207
- const FORM_VIEWPORT_NAME = 'Form.Viewport';
208
-
209
- type FormViewportProps = { scroll?: boolean; gutter?: ColumnRootProps['gutter'] };
210
-
211
- // The viewing window: owns the gutter Column (chrome/side-padding).
212
- // Content-height by default; `scroll` makes it fill its parent and scroll (the gutter then hosts the scrollbar).
213
- const FormViewport = composable<HTMLDivElement, FormViewportProps>(
214
- ({ children, scroll, gutter = 'xs', ...props }, forwardedRef) => {
215
- // Span the full width when nested inside another Column grid (e.g. Card.Root)
216
- // instead of landing in a single narrow track.
217
- const span = '[.dx-column-root_&]:col-span-full';
218
- if (scroll) {
219
- return (
220
- <Column.Root gutter={gutter} classNames={['dx-expander', span]}>
221
- <ScrollArea.Root {...composableProps(props)} orientation='vertical' centered padding thin ref={forwardedRef}>
222
- <ScrollArea.Viewport>{children}</ScrollArea.Viewport>
223
- </ScrollArea.Root>
224
- </Column.Root>
225
- );
226
- }
227
-
228
- return (
229
- <Column.Root {...composableProps(props)} gutter={gutter} classNames={['w-full min-w-0', span]} ref={forwardedRef}>
230
- {children}
231
- </Column.Root>
232
- );
233
- },
234
- );
235
-
236
- FormViewport.displayName = FORM_VIEWPORT_NAME;
237
-
238
- //
239
- // Content
240
- //
241
-
242
- const FORM_CONTENT_NAME = 'Form.Content';
243
-
244
- type FormContentProps = ThemedClassName<PropsWithChildren<{}>>;
245
-
246
- // The viewed body: centered in the viewport's gutter. Pure body — the gutter Column is owned by `Form.Viewport`.
247
- const FormContent = composable<HTMLDivElement, FormContentProps>(({ children, ...props }, forwardedRef) => {
248
- const { form, testId } = useFormContext(FORM_CONTENT_NAME);
249
- const localRef = useRef<HTMLDivElement>(null);
250
- const mergedRef = useMergeRefs([forwardedRef, localRef]);
251
- useKeyHandler(localRef, form);
252
-
253
- return (
254
- <div
255
- {...composableProps(props, {
256
- role: 'form',
257
- classNames: mx(withColumn.center(), 'flex flex-col w-full'),
258
- })}
259
- data-testid={testId}
260
- ref={mergedRef}
261
- >
262
- {children}
263
- </div>
264
- );
265
- });
266
-
267
- FormContent.displayName = FORM_CONTENT_NAME;
268
-
269
- //
270
- // FieldSet
271
- //
272
-
273
- const FORM_FIELDSET_NAME = 'Form.FieldSet';
274
-
275
- type FormFieldSetProps = ThemedClassName<NaturalFormFieldSetProps<any>>;
276
-
277
- const FormFieldSet = (props: FormFieldSetProps) => {
278
- const { form, ...contextProps } = useFormContext(FORM_FIELDSET_NAME);
279
-
280
- return <NaturalFormFieldSet schema={form.schema} {...contextProps} {...props} />;
281
- };
282
-
283
- FormFieldSet.displayName = FORM_FIELDSET_NAME;
284
-
285
- //
286
- // Layout
287
- //
288
-
289
- const FORM_LAYOUT_NAME = 'Form.Layout';
290
-
291
- type FormLayoutProps = Omit<NaturalFormLayoutProps, 'schema'> & { schema?: NaturalFormLayoutProps['schema'] };
292
-
293
- const FormLayout = ({ schema, ...props }: FormLayoutProps) => {
294
- const { form, ...contextProps } = useFormContext(FORM_LAYOUT_NAME);
295
- const resolvedSchema = schema ?? form.schema;
296
- if (!resolvedSchema) {
297
- return null;
298
- }
299
-
300
- return <NaturalFormLayout schema={resolvedSchema} {...contextProps} {...props} />;
301
- };
302
-
303
- FormLayout.displayName = FORM_LAYOUT_NAME;
304
-
305
- //
306
- // Actions
307
- //
308
-
309
- const FORM_ACTIONS_NAME = 'Form.Actions';
310
-
311
- type FormActionsProps = ThemedClassName<{}>;
312
-
313
- const FormActions = ({ classNames }: FormActionsProps) => {
314
- const { t } = useTranslation(translationKey);
315
- const {
316
- form: { canSave, onSave, onCancel },
317
- readonly,
318
- layout,
319
- } = useFormContext(FORM_ACTIONS_NAME);
320
-
321
- if (readonly || layout === 'static') {
322
- return null;
323
- }
324
-
325
- // TODO(burdon): Currently onCancel is a no-op; implement "revert values".
326
- // Deprecate FormSubmit ans use FormActions without Cancel button if no callback is supplied.
327
-
328
- return (
329
- <div
330
- className={mx(withColumn.center(), 'grid grid-flow-col gap-form-gap auto-cols-fr py-form-padding', classNames)}
331
- >
332
- {onCancel && (
333
- <IconButton
334
- icon='ph--x--regular'
335
- iconEnd
336
- label={t('cancel-button.label')}
337
- onClick={onCancel}
338
- data-testid='cancel-button'
339
- />
340
- )}
341
- {onSave && (
342
- <IconButton
343
- type='submit'
344
- variant='primary'
345
- disabled={!canSave}
346
- icon='ph--check--regular'
347
- iconEnd
348
- label={t('save-button.label')}
349
- onClick={onSave}
350
- data-testid='save-button'
351
- />
352
- )}
353
- </div>
354
- );
355
- };
356
-
357
- FormActions.displayName = FORM_ACTIONS_NAME;
358
-
359
- //
360
- // Section
361
- //
362
-
363
- const FORM_SECTION_NAME = 'Form.Section';
364
-
365
- type FormSectionProps = ThemedClassName<{ label?: string; description?: string }>;
366
-
367
- const FormSection = composable<HTMLDivElement, FormSectionProps>(
368
- ({ children, label, description, ...props }, forwardedRef) => {
369
- return (
370
- <div
371
- {...composableProps(props, { classNames: 'flex flex-col pt-form-section-gap first:pt-0' })}
372
- ref={forwardedRef}
373
- >
374
- {label && <h2 className='text-lg'>{label}</h2>}
375
- {description && <p className='text-description'>{description}</p>}
376
- {children}
377
- </div>
378
- );
379
- },
380
- );
381
-
382
- FormSection.displayName = FORM_SECTION_NAME;
383
-
384
- //
385
- // Submit
386
- //
387
-
388
- const FORM_SUBMIT_NAME = 'Form.Submit';
389
-
390
- type FormSubmitProps = ThemedClassName<Partial<Pick<IconButtonProps, 'icon' | 'label' | 'disabled'>>>;
391
-
392
- const FormSubmit = ({ classNames, label, icon, disabled }: FormSubmitProps) => {
393
- const { t } = useTranslation(translationKey);
394
- const {
395
- form: { canSave, onSave },
396
- readonly,
397
- layout,
398
- } = useFormContext(FORM_SUBMIT_NAME);
399
-
400
- if (readonly || layout === 'static') {
401
- return null;
402
- }
403
-
404
- return (
405
- <div className={mx('flex w-full pt-form-padding', classNames)}>
406
- <IconButton
407
- classNames='w-full'
408
- type='submit'
409
- variant='primary'
410
- disabled={disabled ?? !canSave}
411
- icon={icon ?? 'ph--check--regular'}
412
- label={label ?? t('save-button.label')}
413
- onClick={onSave}
414
- data-testid='save-button'
415
- />
416
- </div>
417
- );
418
- };
419
-
420
- FormSubmit.displayName = FORM_SUBMIT_NAME;
421
-
422
- //
423
- // Error
424
- //
425
-
426
- const FORM_ERROR_NAME = 'Form.Error';
427
-
428
- type FormErrorProps = ThemedClassName<PropsWithChildren>;
429
-
430
- /** Form-level error/validation message (e.g. a failed submit), styled via the error valence. */
431
- const FormError = ({ children, classNames }: FormErrorProps) => {
432
- if (!children) {
433
- return null;
434
- }
435
-
436
- return (
437
- <Input.Root validationValence='error'>
438
- <Input.Validation classNames={classNames}>{children}</Input.Validation>
439
- </Input.Root>
440
- );
441
- };
442
-
443
- FormError.displayName = FORM_ERROR_NAME;
444
-
445
- //
446
- // Form
447
- // https://www.radix-ui.com/primitives/docs/guides/composition
448
- //
6
+ FormActions,
7
+ type FormActionsProps,
8
+ FormContent,
9
+ type FormContentProps,
10
+ FormError,
11
+ FormFieldSetController,
12
+ FormGroup,
13
+ type FormGroupProps,
14
+ FormLayoutController,
15
+ type FormLayoutProps,
16
+ FormRoot,
17
+ type FormRootProps,
18
+ FormSection,
19
+ type FormSectionProps,
20
+ FormSubmit,
21
+ type FormSubmitProps,
22
+ FormViewport,
23
+ type FormViewportProps,
24
+ } from './FormControls';
25
+ import { FormFieldLabel, FormRow, type FormRowProps } from './FormField';
449
26
 
450
27
  export const Form = {
451
28
  Root: FormRoot,
452
29
  Viewport: FormViewport,
453
30
  Content: FormContent,
454
31
  Section: FormSection,
455
- FieldSet: FormFieldSet,
456
- Layout: FormLayout,
32
+ Group: FormGroup,
33
+ FieldSet: FormFieldSetController,
34
+ Layout: FormLayoutController,
457
35
  Label: FormFieldLabel,
36
+ Row: FormRow,
458
37
  Actions: FormActions,
459
38
  Submit: FormSubmit,
460
39
  Error: FormError,
461
40
  };
462
41
 
463
- export { useFormContext, useFormValues, useFormFieldState };
464
-
465
42
  export type {
466
- FormRootProps,
467
- FormViewportProps,
43
+ FormActionsProps,
468
44
  FormContentProps,
469
- FormSectionProps,
470
- FormFieldSetProps,
45
+ FormGroupProps,
471
46
  FormLayoutProps,
472
- FormFieldLabelProps,
473
- FormActionsProps,
47
+ FormRootProps,
48
+ FormRowProps,
49
+ FormSectionProps,
474
50
  FormSubmitProps,
51
+ FormViewportProps,
475
52
  };