@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,53 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Schema from 'effect/Schema';
7
+ import React, { useState } from 'react';
8
+
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
+
11
+ import { translations } from '#translations';
12
+
13
+ import { TestLayout } from '../../../../../testing';
14
+ import { Form } from '../../../Form';
15
+
16
+ // A literal union auto-dispatches to SelectField.
17
+ const schema = Schema.Struct({
18
+ status: Schema.Literal('active', 'inactive', 'archived').annotations({ title: 'Status' }),
19
+ }).pipe(Schema.mutable);
20
+
21
+ type Values = Schema.Schema.Type<typeof schema>;
22
+
23
+ const DefaultStory = () => {
24
+ const [values, setValues] = useState<Values>({ status: 'active' });
25
+ return (
26
+ <TestLayout json={values}>
27
+ <Form.Root
28
+ schema={schema}
29
+ values={values}
30
+ onValuesChanged={(values) => setValues((prev) => ({ ...prev, ...values }))}
31
+ >
32
+ <Form.Viewport>
33
+ <Form.Content>
34
+ <Form.FieldSet />
35
+ </Form.Content>
36
+ </Form.Viewport>
37
+ </Form.Root>
38
+ </TestLayout>
39
+ );
40
+ };
41
+
42
+ const meta = {
43
+ title: 'ui/react-ui-form/FormField/SelectField',
44
+ render: DefaultStory,
45
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
46
+ parameters: { layout: 'fullscreen', translations },
47
+ } satisfies Meta<typeof DefaultStory>;
48
+
49
+ export default meta;
50
+
51
+ type Story = StoryObj<typeof meta>;
52
+
53
+ export const Default: Story = {};
@@ -0,0 +1,136 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback } from 'react';
6
+
7
+ import { invariant } from '@dxos/invariant';
8
+ import { Icon, Select, type SelectRootProps } from '@dxos/react-ui';
9
+ import { getStyles } from '@dxos/ui-theme';
10
+
11
+ import { type FormFieldRenderer, type FormFieldRendererProps } from '#types';
12
+
13
+ import { FormRow } from '../../FormRow';
14
+
15
+ export type SelectFieldOptions = FormFieldRendererProps & {
16
+ options?: Array<{ value: string | number; label?: string; secondaryLabel?: string; icon?: string; iconHue?: string }>;
17
+ };
18
+
19
+ export const SelectField = ({ type, readonly, placeholder, options, onValueChange, ...props }: SelectFieldOptions) => {
20
+ const handleValueChange = useCallback<NonNullable<SelectRootProps['onValueChange']>>(
21
+ (value) => onValueChange(type, value),
22
+ [type, onValueChange],
23
+ );
24
+
25
+ return (
26
+ <FormRow<string>
27
+ readonly={readonly}
28
+ renderStatic={(value) => (
29
+ <p className='truncate min-w-0'>
30
+ {options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)}
31
+ </p>
32
+ )}
33
+ {...props}
34
+ >
35
+ {({ value }) => (
36
+ <Select.Root value={value} onValueChange={handleValueChange}>
37
+ <Select.TriggerButton classNames='w-full' disabled={!!readonly} placeholder={placeholder} />
38
+ {options?.length !== 0 && (
39
+ <Select.Portal>
40
+ <Select.Content>
41
+ <Select.Viewport>
42
+ {options?.map(({ value, label, secondaryLabel, icon, iconHue }) => (
43
+ // NOTE: Numeric values are converted to and from strings.
44
+ <Select.Option key={String(value)} value={String(value)}>
45
+ <span className='flex items-center flex-row gap-2'>
46
+ {icon && <Icon icon={icon} classNames={getIconHueStyles(iconHue)} />}
47
+ {label ?? String(value)}
48
+ {secondaryLabel && <span className='text-subdued text-xs'>{secondaryLabel}</span>}
49
+ </span>
50
+ </Select.Option>
51
+ ))}
52
+ </Select.Viewport>
53
+ <Select.Arrow />
54
+ </Select.Content>
55
+ </Select.Portal>
56
+ )}
57
+ </Select.Root>
58
+ )}
59
+ </FormRow>
60
+ );
61
+ };
62
+
63
+ const getIconHueStyles = (iconHue?: string): string | undefined => {
64
+ const styles = iconHue ? getStyles(iconHue) : undefined;
65
+
66
+ return styles?.fg;
67
+ };
68
+
69
+ export type SelectFieldOption = {
70
+ value: string;
71
+ label?: string;
72
+ };
73
+
74
+ export type CreateSelectFieldOptions = {
75
+ /** Options to display. Strings are used as both value and label. */
76
+ options: ReadonlyArray<string | SelectFieldOption>;
77
+ /** Label for the sentinel option that maps to `undefined`. Defaults to `'Default'`. Pass `null` to omit. */
78
+ defaultLabel?: string | null;
79
+ };
80
+
81
+ /**
82
+ * Factory for a `fieldMap` entry (keyed by JSON path) that renders a Select over a fixed list of
83
+ * options, with an optional sentinel mapping to `undefined`. Use for fields whose choices come from a
84
+ * runtime list rather than the schema (e.g. available model ids).
85
+ */
86
+ export const createSelectField = ({
87
+ options,
88
+ defaultLabel = 'Default',
89
+ }: CreateSelectFieldOptions): FormFieldRenderer => {
90
+ const normalized = options.map((option) => (typeof option === 'string' ? { value: option, label: option } : option));
91
+ const hasDefault = defaultLabel !== null;
92
+ // The sentinel maps to `undefined`. Radix forbids an empty-string `Select.Item` value, so use a
93
+ // non-empty placeholder; reserved (a real option with this value would be unrepresentable).
94
+ const sentinel = '__default__';
95
+ invariant(
96
+ !normalized.some((option) => option.value === sentinel),
97
+ `createSelectField: option value '${sentinel}' is reserved.`,
98
+ );
99
+
100
+ return ({ type, readonly, onValueChange, ...props }: FormFieldRendererProps<string | undefined>) => (
101
+ <FormRow<string>
102
+ readonly={readonly}
103
+ renderStatic={(value) => (
104
+ <p className='truncate min-w-0'>
105
+ {normalized.find((option) => option.value === value)?.label ?? String(value ?? '')}
106
+ </p>
107
+ )}
108
+ {...props}
109
+ >
110
+ {({ value }) => (
111
+ <Select.Root
112
+ disabled={!!readonly}
113
+ value={value ?? sentinel}
114
+ onValueChange={(next) => onValueChange(type, hasDefault && next === sentinel ? undefined : next)}
115
+ >
116
+ <Select.TriggerButton classNames='w-full' disabled={!!readonly} />
117
+ {normalized.length > 0 && (
118
+ <Select.Portal>
119
+ <Select.Content>
120
+ <Select.Viewport>
121
+ {hasDefault && <Select.Option value={sentinel}>{defaultLabel}</Select.Option>}
122
+ {normalized.map((option) => (
123
+ <Select.Option key={option.value} value={option.value}>
124
+ {option.label ?? option.value}
125
+ </Select.Option>
126
+ ))}
127
+ </Select.Viewport>
128
+ <Select.Arrow />
129
+ </Select.Content>
130
+ </Select.Portal>
131
+ )}
132
+ </Select.Root>
133
+ )}
134
+ </FormRow>
135
+ );
136
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './SelectField';
@@ -11,11 +11,11 @@ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
11
 
12
12
  import { translations } from '#translations';
13
13
 
14
- import { TestLayout } from '../../testing';
15
- import { Form } from '../Form';
14
+ import { TestLayout } from '../../../../../testing';
15
+ import { Form } from '../../../Form';
16
16
  import { SelectOptionField } from './SelectOptionField';
17
17
 
18
- const schema = Schema.Struct({
18
+ const TestSchema = Schema.Struct({
19
19
  options: Schema.Array(SelectOption).pipe(Schema.mutable),
20
20
  }).pipe(Schema.mutable);
21
21
 
@@ -32,7 +32,7 @@ const DefaultStory = () => {
32
32
  return (
33
33
  <TestLayout>
34
34
  <Form.Root
35
- schema={schema}
35
+ schema={TestSchema}
36
36
  values={values}
37
37
  fieldMap={{ options: SelectOptionField }}
38
38
  onSave={(values) => setValues(values)}
@@ -49,7 +49,7 @@ const DefaultStory = () => {
49
49
  };
50
50
 
51
51
  const meta = {
52
- title: 'ui/react-ui-form/SelectOptionField',
52
+ title: 'ui/react-ui-form/FormField/SelectOptionField',
53
53
  component: SelectOptionField as any,
54
54
  render: DefaultStory,
55
55
  decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
@@ -6,14 +6,15 @@ import React, { type ChangeEvent, type KeyboardEvent, useCallback, useEffect, us
6
6
 
7
7
  import { type SelectOption } from '@dxos/echo/Format';
8
8
  import { PublicKey } from '@dxos/keys';
9
- import { type ChromaticPalette, IconButton, Input, Tag, useTranslation } from '@dxos/react-ui';
10
- import { List } from '@dxos/react-ui-list';
9
+ import { type ChromaticPalette, IconButton, Input, Tag, ToggleIconButton, useTranslation } from '@dxos/react-ui';
10
+ import { OrderedList } from '@dxos/react-ui-list';
11
11
  import { HuePicker } from '@dxos/react-ui-pickers';
12
12
  import { hues, osTranslations } from '@dxos/ui-theme';
13
13
 
14
14
  import { translationKey } from '#translations';
15
+ import { type FormFieldRendererProps } from '#types';
15
16
 
16
- import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
17
+ import { FormFieldLabel } from '../../FormRow';
17
18
 
18
19
  export const SelectOptionField = ({
19
20
  type,
@@ -23,7 +24,7 @@ export const SelectOptionField = ({
23
24
  getStatus,
24
25
  getValue,
25
26
  onValueChange,
26
- }: FormFieldComponentProps<SelectOption[] | undefined>) => {
27
+ }: FormFieldRendererProps<SelectOption[] | undefined>) => {
27
28
  const { t } = useTranslation(translationKey);
28
29
  const { status, error } = getStatus();
29
30
  const [selected, setSelectedId] = useState<string | null>(null);
@@ -123,74 +124,75 @@ export const SelectOptionField = ({
123
124
  <FormFieldLabel error={error} readonly={readonly} label={label} path={jsonPath} />
124
125
  <div>
125
126
  {options && (
126
- <List.Root
127
+ <OrderedList.Root<SelectOption>
127
128
  items={options}
128
129
  isItem={(_item) => true}
130
+ getId={(option) => option.id}
129
131
  onMove={readonly ? undefined : handleMove}
130
132
  readonly={!!readonly}
131
133
  >
132
134
  {({ items }) => (
133
- <div role='list' className='w-full overflow-auto'>
135
+ <OrderedList.Content classNames='w-full overflow-auto'>
134
136
  {items?.map((item) => (
135
- <div key={item.id}>
136
- <List.Item
137
- role='button'
138
- item={item}
139
- classNames='flex flex-col cursor-pointer rounded-xs dx-hover'
140
- aria-expanded={selected === item.id}
141
- >
142
- <div className='flex items-center'>
143
- <List.ItemDragHandle disabled={!!readonly} />
144
- <List.ItemTitle onClick={() => handleClick(item.id)} classNames='flex-1'>
145
- {/* TODO(ZaymonFC): Move spacer into Tag component. */}
146
- <Tag palette={item.color as ChromaticPalette}>{item.title || '\u200b'}</Tag>
147
- </List.ItemTitle>
148
- <IconButton
149
- iconOnly
150
- variant='ghost'
151
- label={t(selected === item.id ? 'collapse.label' : 'expand.label', { ns: osTranslations })}
152
- icon={selected === item.id ? 'ph--caret-down--regular' : 'ph--caret-right--regular'}
153
- onClick={() => handleClick(item.id)}
154
- />
137
+ <OrderedList.Item
138
+ key={item.id}
139
+ id={item.id}
140
+ item={item}
141
+ canDrag={!readonly}
142
+ classNames='flex flex-col cursor-pointer rounded-xs dx-hover'
143
+ >
144
+ <div className='flex items-center'>
145
+ <OrderedList.DragHandle />
146
+ {/* TODO(ZaymonFC): Move spacer into Tag component. */}
147
+ <div className='flex grow items-center truncate px-2' onClick={() => handleClick(item.id)}>
148
+ <Tag hue={item.color as ChromaticPalette}>{item.title || '\u200b'}</Tag>
155
149
  </div>
156
- {selected === item.id && (
157
- <div className='flex flex-col p-form-padding gap-form-gap dx-density-md'>
158
- <Input.Label classNames='text-sm'>{t('select-option.label')}</Input.Label>
159
- <div className='grid grid-cols-[1fr_min-content_min-content] gap-form-gap'>
160
- <Input.TextInput
161
- disabled={!!readonly}
162
- placeholder={t('select-option-label.placeholder')}
163
- ref={selected === item.id ? inputRef : undefined}
164
- value={item.title}
165
- onChange={handleTitleChange(item.id)}
166
- onKeyDown={handleKeyDown}
167
- classNames='flex-1'
168
- />
169
- <HuePicker disabled={!!readonly} value={item.color} onChange={handleColorChange(item.id)} />
170
- <IconButton
171
- disabled={!!readonly}
172
- icon='ph--trash--fill'
173
- iconOnly
174
- label={t('select-option-delete.button')}
175
- onClick={() => handleDelete(item.id)}
176
- />
177
- </div>
150
+ <ToggleIconButton
151
+ iconOnly
152
+ variant='ghost'
153
+ active={selected === item.id}
154
+ icon='ph--caret-right--regular'
155
+ label={t(selected === item.id ? 'collapse.label' : 'expand.label', { ns: osTranslations })}
156
+ onClick={() => handleClick(item.id)}
157
+ />
158
+ </div>
159
+ {selected === item.id && (
160
+ <div className='flex flex-col p-form-padding gap-form-gap dx-density-md'>
161
+ <Input.Label classNames='text-sm'>{t('select-option.label')}</Input.Label>
162
+ <div className='grid grid-cols-[1fr_min-content_min-content] gap-form-gap'>
163
+ <Input.TextInput
164
+ disabled={!!readonly}
165
+ placeholder={t('select-option-label.placeholder')}
166
+ ref={selected === item.id ? inputRef : undefined}
167
+ value={item.title}
168
+ onChange={handleTitleChange(item.id)}
169
+ onKeyDown={handleKeyDown}
170
+ classNames='flex-1'
171
+ />
172
+ <HuePicker disabled={!!readonly} value={item.color} onChange={handleColorChange(item.id)} />
173
+ <IconButton
174
+ disabled={!!readonly}
175
+ icon='ph--trash--fill'
176
+ iconOnly
177
+ label={t('select-option-delete.button')}
178
+ onClick={() => handleDelete(item.id)}
179
+ />
178
180
  </div>
179
- )}
180
- </List.Item>
181
- </div>
181
+ </div>
182
+ )}
183
+ </OrderedList.Item>
182
184
  ))}
183
185
  <IconButton
186
+ classNames='w-full'
184
187
  variant='ghost'
185
188
  icon='ph--plus--regular'
186
189
  label={t('select-option-add.button')}
187
190
  onClick={handleAdd}
188
191
  disabled={!!readonly}
189
- classNames='w-full'
190
192
  />
191
- </div>
193
+ </OrderedList.Content>
192
194
  )}
193
- </List.Root>
195
+ </OrderedList.Root>
194
196
  )}
195
197
  </div>
196
198
  </Input.Root>
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './SelectOptionField';
@@ -0,0 +1,53 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Schema from 'effect/Schema';
7
+ import React, { useState } from 'react';
8
+
9
+ import { Format } from '@dxos/echo';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+
12
+ import { translations } from '#translations';
13
+
14
+ import { TestLayout } from '../../../../../testing';
15
+ import { Form } from '../../../Form';
16
+
17
+ const schema = Schema.Struct({
18
+ notes: Format.Text.annotations({ title: 'Notes' }),
19
+ }).pipe(Schema.mutable);
20
+
21
+ type Values = Schema.Schema.Type<typeof schema>;
22
+
23
+ const DefaultStory = () => {
24
+ const [values, setValues] = useState<Values>({ notes: 'Multi-line\nplain text.' });
25
+ return (
26
+ <TestLayout json={values}>
27
+ <Form.Root
28
+ schema={schema}
29
+ values={values}
30
+ onValuesChanged={(values) => setValues((prev) => ({ ...prev, ...values }))}
31
+ >
32
+ <Form.Viewport>
33
+ <Form.Content>
34
+ <Form.FieldSet />
35
+ </Form.Content>
36
+ </Form.Viewport>
37
+ </Form.Root>
38
+ </TestLayout>
39
+ );
40
+ };
41
+
42
+ const meta = {
43
+ title: 'ui/react-ui-form/FormField/TextAreaField',
44
+ render: DefaultStory,
45
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
46
+ parameters: { layout: 'fullscreen', translations },
47
+ } satisfies Meta<typeof DefaultStory>;
48
+
49
+ export default meta;
50
+
51
+ type Story = StoryObj<typeof meta>;
52
+
53
+ export const Default: Story = {};
@@ -6,7 +6,9 @@ import React, { useCallback } from 'react';
6
6
 
7
7
  import { Input, type TextAreaProps } from '@dxos/react-ui';
8
8
 
9
- import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
9
+ import { type FormFieldRendererProps } from '#types';
10
+
11
+ import { FormRow } from '../../FormRow';
10
12
 
11
13
  export const TextAreaField = ({
12
14
  type,
@@ -15,14 +17,14 @@ export const TextAreaField = ({
15
17
  onValueChange,
16
18
  onBlur,
17
19
  ...props
18
- }: FormFieldComponentProps<string>) => {
20
+ }: FormFieldRendererProps<string>) => {
19
21
  const handleChange = useCallback<NonNullable<TextAreaProps['onChange']>>(
20
22
  (event) => onValueChange(type, event.target.value),
21
23
  [type, onValueChange],
22
24
  );
23
25
 
24
26
  return (
25
- <FormFieldWrapper<string> readonly={readonly} {...props}>
27
+ <FormRow<string> readonly={readonly} {...props}>
26
28
  {({ value = '' }) => (
27
29
  <Input.TextArea
28
30
  rows={5}
@@ -33,6 +35,6 @@ export const TextAreaField = ({
33
35
  onBlur={onBlur}
34
36
  />
35
37
  )}
36
- </FormFieldWrapper>
38
+ </FormRow>
37
39
  );
38
40
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './TextAreaField';
@@ -0,0 +1,52 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Schema from 'effect/Schema';
7
+ import React, { useState } from 'react';
8
+
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
+
11
+ import { translations } from '#translations';
12
+
13
+ import { TestLayout } from '../../../../../testing';
14
+ import { Form } from '../../../Form';
15
+
16
+ const schema = Schema.Struct({
17
+ name: Schema.String.annotations({ title: 'Name' }),
18
+ }).pipe(Schema.mutable);
19
+
20
+ type Values = Schema.Schema.Type<typeof schema>;
21
+
22
+ const DefaultStory = () => {
23
+ const [values, setValues] = useState<Values>({ name: 'Alice' });
24
+ return (
25
+ <TestLayout json={values}>
26
+ <Form.Root
27
+ schema={schema}
28
+ values={values}
29
+ onValuesChanged={(values) => setValues((prev) => ({ ...prev, ...values }))}
30
+ >
31
+ <Form.Viewport>
32
+ <Form.Content>
33
+ <Form.FieldSet />
34
+ </Form.Content>
35
+ </Form.Viewport>
36
+ </Form.Root>
37
+ </TestLayout>
38
+ );
39
+ };
40
+
41
+ const meta = {
42
+ title: 'ui/react-ui-form/FormField/TextField',
43
+ render: DefaultStory,
44
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
45
+ parameters: { layout: 'fullscreen', translations },
46
+ } satisfies Meta<typeof DefaultStory>;
47
+
48
+ export default meta;
49
+
50
+ type Story = StoryObj<typeof meta>;
51
+
52
+ export const Default: Story = {};
@@ -6,7 +6,9 @@ import React, { useCallback } from 'react';
6
6
 
7
7
  import { Input, type TextInputProps } from '@dxos/react-ui';
8
8
 
9
- import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
9
+ import { type FormFieldRendererProps } from '#types';
10
+
11
+ import { FormRow } from '../../FormRow';
10
12
 
11
13
  export const TextField = ({
12
14
  type,
@@ -15,14 +17,14 @@ export const TextField = ({
15
17
  onBlur,
16
18
  onValueChange,
17
19
  ...props
18
- }: FormFieldComponentProps<string>) => {
20
+ }: FormFieldRendererProps<string>) => {
19
21
  const handleChange = useCallback<NonNullable<TextInputProps['onChange']>>(
20
22
  (event) => onValueChange(type, event.target.value),
21
23
  [type, onValueChange],
22
24
  );
23
25
 
24
26
  return (
25
- <FormFieldWrapper<string> readonly={readonly} {...props}>
27
+ <FormRow<string> readonly={readonly} {...props}>
26
28
  {({ value = '' }) => (
27
29
  <Input.TextInput
28
30
  noAutoFill
@@ -33,6 +35,6 @@ export const TextField = ({
33
35
  onChange={handleChange}
34
36
  />
35
37
  )}
36
- </FormFieldWrapper>
38
+ </FormRow>
37
39
  );
38
40
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './TextField';
@@ -0,0 +1,55 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Schema from 'effect/Schema';
7
+ import React, { useState } from 'react';
8
+
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
+
11
+ import { translations } from '#translations';
12
+
13
+ import { TestLayout } from '../../../../../testing';
14
+ import { Form } from '../../../Form';
15
+ import { TupleField } from './TupleField';
16
+
17
+ // TupleField isn't auto-dispatched and needs a `binding`; wire it via `fieldMap`.
18
+ const schema = Schema.Struct({
19
+ point: Schema.Struct({ x: Schema.Number, y: Schema.Number }).annotations({ title: 'Point' }),
20
+ }).pipe(Schema.mutable);
21
+
22
+ type Values = Schema.Schema.Type<typeof schema>;
23
+
24
+ const DefaultStory = () => {
25
+ const [values, setValues] = useState<Values>({ point: { x: 1, y: 2 } });
26
+ return (
27
+ <TestLayout json={values}>
28
+ <Form.Root
29
+ schema={schema}
30
+ values={values}
31
+ fieldMap={{ point: (props) => <TupleField {...props} binding={['x', 'y']} /> }}
32
+ onValuesChanged={(values) => setValues((prev) => ({ ...prev, ...values }))}
33
+ >
34
+ <Form.Viewport>
35
+ <Form.Content>
36
+ <Form.FieldSet />
37
+ </Form.Content>
38
+ </Form.Viewport>
39
+ </Form.Root>
40
+ </TestLayout>
41
+ );
42
+ };
43
+
44
+ const meta = {
45
+ title: 'ui/react-ui-form/FormField/TupleField',
46
+ render: DefaultStory,
47
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
48
+ parameters: { layout: 'fullscreen', translations },
49
+ } satisfies Meta<typeof DefaultStory>;
50
+
51
+ export default meta;
52
+
53
+ type Story = StoryObj<typeof meta>;
54
+
55
+ export const Default: Story = {};
@@ -8,7 +8,9 @@ import { Input } from '@dxos/react-ui';
8
8
  import { mx } from '@dxos/ui-theme';
9
9
  import { safeParseFloat } from '@dxos/util';
10
10
 
11
- import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
11
+ import { type FormFieldRendererProps } from '#types';
12
+
13
+ import { FormFieldLabel } from '../../FormRow';
12
14
 
13
15
  const gridCols = ['grid-cols-1', 'grid-cols-2', 'grid-cols-3', 'grid-cols-4'];
14
16
 
@@ -22,7 +24,7 @@ export const TupleField = ({
22
24
  getValue,
23
25
  onValueChange,
24
26
  onBlur,
25
- }: FormFieldComponentProps<Record<string, number>> & {
27
+ }: FormFieldRendererProps<Record<string, number>> & {
26
28
  binding: string[];
27
29
  }) => {
28
30
  const { status, error } = getStatus();
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './TupleField';