@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
@@ -1,25 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- import { createContext, useContext } from 'react';
6
-
7
- /**
8
- * A standalone context for the `tooltips` flag (Form.Root's only label
9
- * decoration today: a JSON-path hover tooltip rendered by
10
- * `FormFieldLabel`).
11
- *
12
- * Lives in its own module so that `FormFieldComponent.tsx` -- imported at
13
- * the top of `Form.tsx` -- can read the flag without re-importing from
14
- * `Form.tsx`. That round-trip used to create a circular module-eval
15
- * dependency that intermittently hit a TDZ ("Cannot access 'FormFieldLabel'
16
- * before initialization") in browser-mode storybook tests.
17
- *
18
- * Defaults to `true` both when `Form.Root` doesn't pass an explicit value
19
- * AND when there is no enclosing `Form.Root` (e.g. `FormFieldWrapper`
20
- * stories that render an input without a Form provider).
21
- */
22
- export const FormTooltipsContext = createContext<boolean>(true);
23
-
24
- /** Returns whether the enclosing `Form.Root` has field tooltips enabled. */
25
- export const useFormTooltips = (): boolean => useContext(FormTooltipsContext);
@@ -1,38 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- import { createAnnotationHelper } from '@dxos/echo/internal';
6
-
7
- /**
8
- * Annotation carrying one or more named `FormLayout` DSL templates that
9
- * control how `Form.FieldSet` / `Form.Layout` arrange a schema's fields.
10
- * Callers select a variant via the `name` prop; the implicit name is
11
- * `DEFAULT_LAYOUT_NAME` (`'default'`).
12
- *
13
- * Templates use a minimal XML grammar — see `parser.ts`. Example:
14
- *
15
- * FormLayoutAnnotation.set({
16
- * default: `
17
- * <grid cols="2">
18
- * <field name="origin"/>
19
- * <field name="destination"/>
20
- * <field name="provider" span="2"/>
21
- * </grid>
22
- * `,
23
- * card: `
24
- * <grid cols="1">
25
- * <field name="provider"/>
26
- * <field name="number"/>
27
- * </grid>
28
- * `,
29
- * })
30
- */
31
- export const FormLayoutAnnotationId = Symbol.for('@dxos/react-ui-form/annotation/Layout');
32
-
33
- export type FormLayoutMap = Record<string, string>;
34
-
35
- export const FormLayoutAnnotation = createAnnotationHelper<FormLayoutMap>(FormLayoutAnnotationId);
36
-
37
- /** Name used when no explicit variant is requested. */
38
- export const DEFAULT_LAYOUT_NAME = 'default';
@@ -1,7 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- export * from './annotation';
6
- export { FormLayout } from './FormLayout';
7
- export { LayoutParseError, parseLayout, type LayoutNode } from './parser';
@@ -1,3 +0,0 @@
1
- # Form
2
-
3
- - [ ] Layout options (e.g., label on the side.)
@@ -1,173 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import * as Option from 'effect/Option';
6
- import * as SchemaAST from 'effect/SchemaAST';
7
- import React, { useCallback } from 'react';
8
-
9
- import { Ref } from '@dxos/echo';
10
- import { SchemaEx } from '@dxos/effect';
11
- import { useTranslation } from '@dxos/react-ui';
12
-
13
- import { translationKey } from '#translations';
14
-
15
- import { getFormProperties } from '../../../util';
16
- import { useFormValues } from '../Form';
17
- import { FormField, IconBlock, type FormFieldProps } from '../FormField';
18
- import { FormFieldLabel, type FormFieldStateProps } from '../FormFieldComponent';
19
-
20
- export type ArrayFieldProps = {
21
- label: string;
22
- fieldProps: FormFieldStateProps;
23
- } & FormFieldProps;
24
-
25
- export const ArrayField = ({
26
- type,
27
- path,
28
- label,
29
- readonly,
30
- layout,
31
- fieldProps: inputProps,
32
- ...props
33
- }: ArrayFieldProps) => {
34
- const { t } = useTranslation(translationKey);
35
- const elementType = SchemaEx.getArrayElementType(type);
36
- const { onValueChange } = inputProps;
37
- const values = useFormValues(ArrayField.displayName, path, () => []);
38
-
39
- const getDefaultObjectValue = (typeNode: SchemaAST.AST): any => {
40
- const baseNode = SchemaEx.findNode(typeNode, SchemaEx.isDiscriminatedUnion);
41
- const typeLiteral = baseNode
42
- ? SchemaEx.getDiscriminatedType(baseNode, {})
43
- : SchemaEx.findNode(typeNode, SchemaAST.isTypeLiteral);
44
- if (!typeLiteral) {
45
- return {};
46
- }
47
-
48
- return Object.fromEntries(
49
- getFormProperties(typeLiteral).map((prop) => {
50
- const defaultValue = SchemaAST.getDefaultAnnotation(prop.type).pipe((annotation) =>
51
- Option.getOrUndefined(annotation),
52
- );
53
- return [prop.name, defaultValue];
54
- }),
55
- );
56
- };
57
-
58
- const handleAdd = useCallback(() => {
59
- const defaultValue =
60
- SchemaEx.isNestedType(type) && elementType ? getDefaultObjectValue(elementType) : getDefaultValue(elementType);
61
- // `values` is `undefined` on first render for arrays whose parent path
62
- // hasn't been materialised in the form values yet (e.g. `package.repos`
63
- // when the form starts with no `package`). `useFormValues`'s default-
64
- // value effect would eventually backfill it to `[]`, but until then the
65
- // old `values && ...` guard silently swallowed the click. Treat a
66
- // missing array as empty so Add always produces `[defaultValue]`.
67
- onValueChange(type, [...(values ?? []), defaultValue]);
68
- }, [onValueChange, type, elementType, values]);
69
-
70
- const handleDelete = useCallback(
71
- (idx: number) => {
72
- onValueChange(
73
- type,
74
- values?.filter((_, i) => i !== idx),
75
- );
76
- },
77
- [onValueChange, type, values],
78
- );
79
-
80
- if (!elementType || ((readonly || layout === 'static') && values && values.length < 1)) {
81
- return null;
82
- }
83
-
84
- const renderItemAsObject = elementType && SchemaEx.isNestedType(elementType) && !Ref.isRefType(elementType);
85
-
86
- return (
87
- <>
88
- {(layout !== 'static' || (values && values.length > 0)) && (
89
- <div className='flex items-center gap-2'>
90
- <div className='flex-1 min-w-0'>
91
- <FormFieldLabel readonly={readonly} label={label} path={SchemaEx.createJsonPath(path ?? [])} asChild />
92
- </div>
93
- {!readonly && layout !== 'static' && (
94
- <IconBlock inline icon='ph--plus--regular' label={t('add-item.button')} onClick={handleAdd} />
95
- )}
96
- </div>
97
- )}
98
-
99
- <div className='flex flex-col'>
100
- {values?.map((_, index) => {
101
- const isLast = index === values.length - 1;
102
-
103
- // Object items: each row contains a recursively-rendered FormField
104
- // (multiple sub-rows for the object's fields) wrapped in a border,
105
- // with the delete button bottom-aligned next to it.
106
- // Scalar items: a single-row inline FormField with a center-aligned
107
- // delete button. Refs and primitive arrays use this layout.
108
- const fieldField = (
109
- <FormField
110
- {...props}
111
- autoFocus={isLast}
112
- type={elementType}
113
- // Suppress the per-item header for object items only — the recursive
114
- // form already renders labels for each sub-field. Scalar items
115
- // (refs, primitives) keep the parent name so inline-layout
116
- // children (e.g. RefField) have a real label to use as a
117
- // fallback placeholder.
118
- {...(renderItemAsObject && { name: null })}
119
- path={[...(path ?? []), index]}
120
- readonly={readonly || layout === 'static'}
121
- layout={renderItemAsObject ? (layout === 'static' ? 'static' : undefined) : 'inline'}
122
- />
123
- );
124
-
125
- return (
126
- <div key={index} className='grid grid-cols-[1fr_min-content] items-center mb-1 last:mb-form-gap'>
127
- {fieldField}
128
- {!readonly && layout !== 'static' && (
129
- <IconBlock
130
- inline={!renderItemAsObject}
131
- icon='ph--x--regular'
132
- label={t('remove-item.button')}
133
- onClick={() => handleDelete(index)}
134
- />
135
- )}
136
- </div>
137
- );
138
- })}
139
- </div>
140
- </>
141
- );
142
- };
143
-
144
- ArrayField.displayName = 'Form.ArrayField';
145
-
146
- /**
147
- * Returns the default empty value for a given AST.
148
- * Used for initializing new array values etc.
149
- */
150
- // TODO(wittjosiah): Factor out?
151
- export const getDefaultValue = (ast?: SchemaAST.AST): any => {
152
- switch (ast?._tag) {
153
- case 'StringKeyword': {
154
- return '';
155
- }
156
- case 'NumberKeyword': {
157
- return 0;
158
- }
159
- case 'BooleanKeyword': {
160
- return false;
161
- }
162
- case 'Suspend': {
163
- return getDefaultValue(ast.f());
164
- }
165
- default: {
166
- if (ast && SchemaEx.isNestedType(ast)) {
167
- return {};
168
- } else {
169
- throw new Error(`Unsupported type: ${ast?._tag}`);
170
- }
171
- }
172
- }
173
- };
@@ -1,22 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { useCallback } from 'react';
6
-
7
- import { Input, type SwitchProps } from '@dxos/react-ui';
8
-
9
- import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
10
-
11
- export const BooleanField = ({ type, readonly, onValueChange, ...props }: FormFieldComponentProps<boolean>) => {
12
- const handleChange = useCallback<NonNullable<SwitchProps['onCheckedChange']>>(
13
- (value) => onValueChange?.(type, value),
14
- [type, onValueChange],
15
- );
16
-
17
- return (
18
- <FormFieldWrapper<boolean> readonly={readonly} {...props}>
19
- {({ value }) => <Input.Switch disabled={!!readonly} checked={value} onCheckedChange={handleChange} />}
20
- </FormFieldWrapper>
21
- );
22
- };
@@ -1,76 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { useCallback, useEffect, useState } from 'react';
6
-
7
- import { Input, type TextInputProps } from '@dxos/react-ui';
8
- import { safeParseFloat } from '@dxos/util';
9
-
10
- import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
11
-
12
- export const NumberField = ({
13
- type,
14
- readonly,
15
- placeholder,
16
- getValue,
17
- onValueChange,
18
- onBlur,
19
- ...props
20
- }: FormFieldComponentProps<number>) => {
21
- // Track raw string input so the user can clear the field before typing a new number.
22
- // We only commit to onValueChange when the raw string parses to a valid number.
23
- const [raw, setRaw] = useState<string>(() => {
24
- const v = getValue();
25
- return v !== undefined ? String(v) : '';
26
- });
27
-
28
- // Sync display when an external change updates the committed value (e.g. reactive form
29
- // calculations). Only overwrite raw when the external value differs from what raw parses
30
- // to, preserving partial edits like "1." which correctly parse to 1.
31
- const externalValue = getValue();
32
- useEffect(() => {
33
- if (externalValue !== safeParseFloat(raw)) {
34
- setRaw(externalValue !== undefined ? String(externalValue) : '');
35
- }
36
- }, [externalValue]); // eslint-disable-line react-hooks/exhaustive-deps
37
-
38
- const handleChange = useCallback<NonNullable<TextInputProps['onChange']>>(
39
- (event) => {
40
- const value = event.target.value;
41
- setRaw(value);
42
- const parsed = safeParseFloat(value);
43
- if (parsed !== undefined) {
44
- onValueChange(type, parsed);
45
- }
46
- },
47
- [type, onValueChange],
48
- );
49
-
50
- const handleBlur = useCallback(
51
- (event: React.FocusEvent<HTMLElement>) => {
52
- // If the field was left empty or invalid, reset to the last committed value.
53
- if (safeParseFloat(raw) === undefined) {
54
- const committed = getValue();
55
- setRaw(committed !== undefined ? String(committed) : '');
56
- }
57
- onBlur(event);
58
- },
59
- [raw, getValue, onBlur],
60
- );
61
-
62
- return (
63
- <FormFieldWrapper<number> readonly={readonly} getValue={getValue} {...props}>
64
- {() => (
65
- <Input.TextInput
66
- type='number'
67
- disabled={!!readonly}
68
- placeholder={placeholder}
69
- value={raw}
70
- onChange={handleChange}
71
- onBlur={handleBlur}
72
- />
73
- )}
74
- </FormFieldWrapper>
75
- );
76
- };
@@ -1,77 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import React, { useCallback } from 'react';
6
-
7
- import { Icon, Input, Select, type SelectRootProps } from '@dxos/react-ui';
8
- import { getStyles } from '@dxos/ui-theme';
9
-
10
- import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
11
-
12
- export type SelectFieldOptions = FormFieldComponentProps & {
13
- options?: Array<{ value: string | number; label?: string; secondaryLabel?: string; icon?: string; iconHue?: string }>;
14
- };
15
-
16
- export const SelectField = ({
17
- type,
18
- readonly,
19
- label,
20
- jsonPath,
21
- layout,
22
- placeholder,
23
- options,
24
- getStatus,
25
- getValue,
26
- onValueChange,
27
- }: SelectFieldOptions) => {
28
- const { status, error } = getStatus();
29
- const value = getValue() as string | undefined;
30
-
31
- const handleValueChange = useCallback<NonNullable<SelectRootProps['onValueChange']>>(
32
- (value) => onValueChange(type, value),
33
- [type, onValueChange],
34
- );
35
-
36
- if ((readonly || layout === 'static') && value == null) {
37
- return null;
38
- }
39
-
40
- return (
41
- <Input.Root validationValence={status}>
42
- {layout !== 'inline' && <FormFieldLabel error={error} readonly={readonly} label={label} path={jsonPath} />}
43
- {layout === 'static' ? (
44
- <p>{options?.find(({ value: optionValue }) => optionValue === value)?.label ?? String(value)}</p>
45
- ) : (
46
- <Select.Root value={value} onValueChange={handleValueChange}>
47
- {/* TODO(burdon): Placeholder not working? */}
48
- <Select.TriggerButton classNames='w-full' disabled={!!readonly} placeholder={placeholder} />
49
- <Select.Portal>
50
- <Select.Content>
51
- <Select.Viewport>
52
- {options?.map(({ value, label, secondaryLabel, icon, iconHue }) => (
53
- // NOTE: Numeric values are converted to and from strings.
54
- <Select.Option key={String(value)} value={String(value)}>
55
- <span className='flex items-center flex-row gap-2'>
56
- {icon && <Icon icon={icon} classNames={getIconHueStyles(iconHue)} />}
57
- {label ?? String(value)}
58
- {secondaryLabel && <span className='text-subdued text-xs'>{secondaryLabel}</span>}
59
- </span>
60
- </Select.Option>
61
- ))}
62
- </Select.Viewport>
63
- <Select.Arrow />
64
- </Select.Content>
65
- </Select.Portal>
66
- </Select.Root>
67
- )}
68
- {layout === 'full' && <Input.DescriptionAndValidation>{error}</Input.DescriptionAndValidation>}
69
- </Input.Root>
70
- );
71
- };
72
-
73
- const getIconHueStyles = (iconHue?: string): string | undefined => {
74
- const styles = iconHue ? getStyles(iconHue) : undefined;
75
-
76
- return styles?.fg;
77
- };
@@ -1,51 +0,0 @@
1
- # Plugin Settings Audit
2
-
3
- Tracks which plugin settings panels use schema-driven `Settings.FieldSet` and which still hand-roll their controls.
4
-
5
- The target shape for a plugin settings panel is:
6
-
7
- ```tsx
8
- <SettingsForm.Viewport>
9
- <SettingsForm.Section title={t('settings.title', { ns: meta.id })}>
10
- <SettingsForm.FieldSet
11
- readonly={!onSettingsChange}
12
- schema={Settings.Settings}
13
- values={settings}
14
- onValuesChanged={(values) => onSettingsChange?.(() => values)}
15
- />
16
- </SettingsForm.Section>
17
- </SettingsForm.Viewport>
18
- ```
19
-
20
- Field labels and descriptions come from `.annotations({ title, description })` on each schema field. Use `fieldMap` for runtime-driven option lists (model pickers, etc.). Use the `visible` callback to gate fields on environment or sibling values.
21
-
22
- ## FieldSet adopters
23
-
24
- | Plugin | Notes |
25
- | ---------------------- | -------------------------------------------------------------------------------------------------------- |
26
- | `plugin-assistant` | Nested `modelDefaults` struct; `fieldMap` provides per-provider model selectors via `createSelectField`. |
27
- | `plugin-crx` | Two booleans. |
28
- | `plugin-deck` | Five booleans; `enableNativeRedirect` hidden via `visible` when `isSocket`. |
29
- | `plugin-inbox` | Single boolean. |
30
- | `plugin-markdown` | Original reference adopter. `snippets` text field gated via `visible`/`fieldMap`. |
31
- | `plugin-meeting` | Single boolean. |
32
- | `plugin-observability` | Boolean; info `Message.Root` banner kept above `FieldSet`. |
33
- | `plugin-presenter` | Single boolean. |
34
- | `plugin-sample` | Single boolean. |
35
- | `plugin-script` | Mixed: auth `Button` retained as a manual `SettingsForm.Item`; `editorInputMode` rendered by `FieldSet`. |
36
- | `plugin-sketch` | Boolean + `gridType` literal union (rendered as a Select — was previously a Switch). |
37
-
38
- ## Skipped
39
-
40
- | Plugin | Reason |
41
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
- | `plugin-debug` | Action buttons (download diagnostics, download logs, repair), `Toast`, and a storage-adapter selector wired to `client.config` rather than the plugin settings atom. |
43
- | `plugin-space` | Renders a list of spaces with per-space "open settings" buttons — not bound to any schema field. |
44
- | `plugin-spacetime` | Section is currently empty; nothing to render. |
45
- | `plugin-thread` | Settings schema is `Schema.Struct({})` — nothing to render. |
46
-
47
- ## When to extend `SettingsFieldSet` vs. add a custom field
48
-
49
- - **Extend `SettingsFieldSet`** when the rendering rule applies generally to a schema construct (e.g. nested structs recursing into sibling fields, literal unions becoming Selects). Keep auto-detection in `detectFieldType`.
50
- - **Use `fieldMap`** when the schema can't fully describe the rendering — runtime-driven option lists, custom inputs, or override of the auto-rendered control. Use the typed form `SettingsFieldMap<T>` (or `satisfies SettingsFieldMap<Settings>`) so the entries are checked against the values shape.
51
- - **Drop back to manual `SettingsForm.Item`** when the panel needs UI that isn't bound to a settings field at all (action buttons, info banners, lists of external entities). These coexist as siblings of `FieldSet` inside the same `Section`.
@@ -1,104 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { type Meta, type StoryObj } from '@storybook/react-vite';
6
- import * as Schema from 'effect/Schema';
7
- import React from 'react';
8
-
9
- import { random } from '@dxos/random';
10
- import { Button, Input } from '@dxos/react-ui';
11
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
-
13
- import { translations } from '#translations';
14
-
15
- import { Settings } from './Settings';
16
-
17
- random.seed(132);
18
-
19
- const DefaultStory = () => {
20
- return (
21
- <Settings.Viewport>
22
- <Settings.Section title='Settings' description={random.lorem.paragraphs(1)}>
23
- <Settings.Item title={random.lorem.sentence(2)} description={random.lorem.paragraphs(1)}>
24
- <Input.TextInput placeholder='Input' />
25
- </Settings.Item>
26
- <Settings.Item title={random.lorem.sentence(2)} description={random.lorem.paragraphs(2)}>
27
- <Input.Switch />
28
- </Settings.Item>
29
- <Settings.Item title={random.lorem.sentence(3)} description={random.lorem.paragraphs(2)}>
30
- <Button>Test</Button>
31
- </Settings.Item>
32
- </Settings.Section>
33
- <Settings.Section title='Panel Example'>
34
- <Settings.Panel>
35
- <h3 className='text-lg mb-2'>Members</h3>
36
- <p className='text-description'>Content inside a panel.</p>
37
- </Settings.Panel>
38
- </Settings.Section>
39
- </Settings.Viewport>
40
- );
41
- };
42
-
43
- const meta = {
44
- title: 'ui/react-ui-form/Settings',
45
- render: DefaultStory,
46
- decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
47
- parameters: {
48
- layout: 'fullscreen',
49
- translations,
50
- },
51
- } satisfies Meta;
52
-
53
- export default meta;
54
-
55
- type Story = StoryObj<typeof meta>;
56
-
57
- export const Default: Story = {};
58
-
59
- const TestViewModes = ['preview', 'readonly', 'source'] as const;
60
- const TestViewMode = Schema.Union(...TestViewModes.map((mode) => Schema.Literal(mode)));
61
-
62
- const TestSettings = Schema.mutable(
63
- Schema.Struct({
64
- viewMode: TestViewMode.annotations({ title: 'View mode', description: 'Default document view mode.' }),
65
- toolbar: Schema.optional(
66
- Schema.Boolean.annotations({ title: 'Show toolbar', description: 'Display formatting toolbar.' }),
67
- ),
68
- fontSize: Schema.optional(
69
- Schema.Number.annotations({ title: 'Font size', description: 'Editor font size in pixels.' }),
70
- ),
71
- placeholder: Schema.optional(
72
- Schema.String.annotations({ title: 'Placeholder', description: 'Default placeholder text.' }),
73
- ),
74
- debug: Schema.optional(Schema.Boolean.annotations({ title: 'Debug mode', description: 'Enable debug features.' })),
75
- }),
76
- );
77
-
78
- type TestSettings = Schema.Schema.Type<typeof TestSettings>;
79
-
80
- const FieldSetStory = () => {
81
- const [values, setValues] = React.useState<TestSettings>({
82
- viewMode: 'preview',
83
- toolbar: true,
84
- fontSize: 14,
85
- debug: false,
86
- });
87
-
88
- return (
89
- <Settings.Viewport>
90
- <Settings.Section title='Plugin Settings (Auto-generated)'>
91
- <Settings.FieldSet
92
- schema={TestSettings}
93
- values={values}
94
- onValuesChanged={setValues}
95
- visible={(path, values) => path !== 'placeholder' || !!values.debug}
96
- />
97
- </Settings.Section>
98
- </Settings.Viewport>
99
- );
100
- };
101
-
102
- export const FieldSet: Story = {
103
- render: FieldSetStory,
104
- };
@@ -1,81 +0,0 @@
1
- //
2
- // Copyright 2025 DXOS.org
3
- //
4
-
5
- import React, { type PropsWithChildren } from 'react';
6
-
7
- import { type Label, ScrollArea, type ThemedClassName, toLocalizedString, useTranslation } from '@dxos/react-ui';
8
- import { composable, composableProps } from '@dxos/react-ui';
9
- import { mx } from '@dxos/ui-theme';
10
-
11
- import { translationKey } from '#translations';
12
-
13
- import { SettingsFieldSet } from './SettingsFieldSet';
14
- import { SettingsItem, SettingsPanel } from './SettingsItem';
15
-
16
- const SETTINGS_ROOT_NAME = 'Settings.Root';
17
- const SETTINGS_VIEWPORT_NAME = 'Settings.Viewport';
18
- const SETTINGS_SECTION_NAME = 'Settings.Section';
19
-
20
- //
21
- // Root (headless — no styling, no scroll).
22
- //
23
-
24
- type SettingsRootProps = ThemedClassName<PropsWithChildren>;
25
-
26
- const SettingsRoot = ({ children, classNames }: SettingsRootProps) => {
27
- return <div className={mx('flex flex-col gap-2', classNames)}>{children}</div>;
28
- };
29
-
30
- SettingsRoot.displayName = SETTINGS_ROOT_NAME;
31
-
32
- //
33
- // Viewport (scroll area + padding + document layout).
34
- //
35
-
36
- const SettingsViewport = composable<HTMLDivElement>(({ children, ...props }, forwardedRef) => {
37
- return (
38
- <ScrollArea.Root {...composableProps(props)} orientation='vertical' centered thin ref={forwardedRef}>
39
- <ScrollArea.Viewport classNames='px-4 pointer-coarse:px-2'>
40
- <div className='dx-document flex flex-col gap-2 py-4'>{children}</div>
41
- </ScrollArea.Viewport>
42
- </ScrollArea.Root>
43
- );
44
- });
45
-
46
- SettingsViewport.displayName = SETTINGS_VIEWPORT_NAME;
47
-
48
- //
49
- // Section (title + optional description + children with spacing).
50
- //
51
-
52
- type SettingsSectionProps = PropsWithChildren<{
53
- title: Label;
54
- description?: Label;
55
- }>;
56
-
57
- const SettingsSection = ({ title, description, children }: SettingsSectionProps) => {
58
- const { t } = useTranslation(translationKey);
59
- return (
60
- <>
61
- <h2 className='px-trim-md mt-trim-md text-xl'>{toLocalizedString(title, t)}</h2>
62
- {description && <p className='px-trim-md text-description'>{toLocalizedString(description, t)}</p>}
63
- <div className='w-full pt-trim-md space-y-trim-md'>{children}</div>
64
- </>
65
- );
66
- };
67
-
68
- SettingsSection.displayName = SETTINGS_SECTION_NAME;
69
-
70
- //
71
- // Settings
72
- //
73
-
74
- export const Settings = {
75
- Root: SettingsRoot,
76
- Viewport: SettingsViewport,
77
- Section: SettingsSection,
78
- Panel: SettingsPanel,
79
- Item: SettingsItem,
80
- FieldSet: SettingsFieldSet,
81
- };