@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,60 @@
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
+ // DateField covers all three temporal formats; show each.
18
+ const schema = Schema.Struct({
19
+ date: Format.DateOnly.annotations({ title: 'Date' }),
20
+ time: Format.TimeOnly.annotations({ title: 'Time' }),
21
+ dateTime: Format.DateTime.annotations({ title: 'Date & time' }),
22
+ }).pipe(Schema.mutable);
23
+
24
+ type Values = Schema.Schema.Type<typeof schema>;
25
+
26
+ const DefaultStory = () => {
27
+ const [values, setValues] = useState<Values>({
28
+ date: '1990-05-12',
29
+ time: '09:00:00',
30
+ dateTime: '2026-06-01T15:30:00.000Z',
31
+ });
32
+ return (
33
+ <TestLayout json={values}>
34
+ <Form.Root
35
+ schema={schema}
36
+ values={values}
37
+ onValuesChanged={(values) => setValues((prev) => ({ ...prev, ...values }))}
38
+ >
39
+ <Form.Viewport>
40
+ <Form.Content>
41
+ <Form.FieldSet />
42
+ </Form.Content>
43
+ </Form.Viewport>
44
+ </Form.Root>
45
+ </TestLayout>
46
+ );
47
+ };
48
+
49
+ const meta = {
50
+ title: 'ui/react-ui-form/FormField/DateField',
51
+ render: DefaultStory,
52
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
53
+ parameters: { layout: 'fullscreen', translations },
54
+ } satisfies Meta<typeof DefaultStory>;
55
+
56
+ export default meta;
57
+
58
+ type Story = StoryObj<typeof meta>;
59
+
60
+ export const Default: Story = {};
@@ -8,7 +8,9 @@ import React, { useCallback } from 'react';
8
8
  import { Format } from '@dxos/echo';
9
9
  import { Input } from '@dxos/react-ui';
10
10
 
11
- import { type FormFieldComponentProps, FormFieldWrapper } from '../FormFieldComponent';
11
+ import { type FormFieldRendererProps } from '#types';
12
+
13
+ import { FormRow } from '../../FormRow';
12
14
 
13
15
  /**
14
16
  * Stored value shapes:
@@ -52,7 +54,7 @@ export const DateField = ({
52
54
  onValueChange,
53
55
  onBlur: _onBlur,
54
56
  ...props
55
- }: FormFieldComponentProps<string>) => {
57
+ }: FormFieldRendererProps<string>) => {
56
58
  const handleSimpleChange = useCallback((next: string) => onValueChange(type, next), [type, onValueChange]);
57
59
 
58
60
  const handleDateTimeChange = useCallback(
@@ -64,19 +66,19 @@ export const DateField = ({
64
66
  );
65
67
 
66
68
  return (
67
- <FormFieldWrapper<string> readonly={readonly} format={format} {...props}>
69
+ <FormRow<string> {...props} readonly={readonly} format={format}>
68
70
  {({ value }) => {
69
71
  switch (format) {
70
72
  case Format.TypeFormat.Date:
71
73
  return (
72
- <div className='grid grid-cols-[minmax(0,1fr)_min-content] items-stretch gap-1'>
74
+ <div className='grid grid-cols-[minmax(0,1fr)_min-content] gap-1 items-stretch'>
73
75
  <Input.Date
74
76
  classNames='min-w-0 overflow-hidden'
75
- disabled={!!readonly}
77
+ disabled={readonly}
76
78
  value={value ?? ''}
77
79
  onValueChange={handleSimpleChange}
78
80
  />
79
- <Input.TriggerIcon classNames='h-full' />
81
+ <Input.TriggerIcon />
80
82
  </div>
81
83
  );
82
84
  case Format.TypeFormat.Time:
@@ -84,18 +86,18 @@ export const DateField = ({
84
86
  case Format.TypeFormat.DateTime:
85
87
  default:
86
88
  return (
87
- <div className='grid grid-cols-[minmax(0,1fr)_min-content] items-stretch gap-1'>
89
+ <div className='grid grid-cols-[minmax(0,1fr)_min-content] gap-1 items-stretch'>
88
90
  <Input.DateTime
89
91
  classNames='min-w-0 overflow-hidden'
90
- disabled={!!readonly}
92
+ disabled={readonly}
91
93
  value={isoToLocalDateTime(value)}
92
94
  onValueChange={handleDateTimeChange}
93
95
  />
94
- <Input.TriggerIcon classNames='h-full' />
96
+ <Input.TriggerIcon />
95
97
  </div>
96
98
  );
97
99
  }
98
100
  }}
99
- </FormFieldWrapper>
101
+ </FormRow>
100
102
  );
101
103
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './DateField';
@@ -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
+ location: Format.GeoPoint.annotations({ title: 'Location' }),
19
+ }).pipe(Schema.mutable);
20
+
21
+ type Values = Schema.Schema.Type<typeof schema>;
22
+
23
+ const DefaultStory = () => {
24
+ const [values, setValues] = useState<Values>({ location: [-74.006, 40.7128] });
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/GeoPointField',
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 = {};
@@ -9,22 +9,19 @@ import { Input, useTranslation } from '@dxos/react-ui';
9
9
  import { safeParseFloat } from '@dxos/util';
10
10
 
11
11
  import { translationKey } from '#translations';
12
+ import { type FormFieldRendererProps } from '#types';
12
13
 
13
- import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
14
+ import { FormRow } from '../../FormRow';
14
15
 
15
16
  export const GeoPointField = ({
16
17
  type,
17
- label,
18
- jsonPath,
19
18
  readonly,
20
- layout,
21
- getStatus,
22
19
  getValue,
23
20
  onValueChange,
24
21
  onBlur,
25
- }: FormFieldComponentProps<GeoPoint>) => {
22
+ ...props
23
+ }: FormFieldRendererProps<GeoPoint>) => {
26
24
  const { t } = useTranslation(translationKey);
27
- const { status, error } = getStatus();
28
25
  const geoPoint = useMemo<GeoPoint>(() => getValue() ?? [0, 0], [getValue]);
29
26
  const value = useMemo(() => GeoLocation.fromGeoPoint(geoPoint), [geoPoint]);
30
27
 
@@ -54,22 +51,23 @@ export const GeoPointField = ({
54
51
  [type, getValue, onValueChange],
55
52
  );
56
53
 
57
- if ((readonly || layout === 'static') && !value?.latitude && !value?.longitude) {
58
- return null;
59
- }
60
-
61
54
  return (
62
- <Input.Root validationValence={status}>
63
- {layout !== 'inline' && (
64
- <FormFieldLabel error={error} readonly={readonly} label={label} path={jsonPath} asChild />
65
- )}
66
- {layout === 'static' ? (
67
- <LatLng {...value} />
68
- ) : (
55
+ <FormRow<GeoPoint>
56
+ readonly={readonly}
57
+ getValue={getValue}
58
+ standalone
59
+ renderStatic={(point) => {
60
+ const location = GeoLocation.fromGeoPoint(point ?? [0, 0]);
61
+ // Treat a zero coordinate pair as empty (no meaningful location to display).
62
+ return !location.latitude && !location.longitude ? null : <LatLng {...location} />;
63
+ }}
64
+ {...props}
65
+ >
66
+ {({ presentation }) => (
69
67
  <div className='grid grid-cols-2 gap-form-gap'>
70
68
  <div>
71
69
  <Input.Root>
72
- {layout !== 'inline' && <Input.Label>{t('latitude.label')}</Input.Label>}
70
+ {presentation.showLabel && <Input.Label>{t('latitude.label')}</Input.Label>}
73
71
  <Input.TextInput
74
72
  type='number'
75
73
  step='0.00001'
@@ -85,7 +83,7 @@ export const GeoPointField = ({
85
83
  </div>
86
84
  <div>
87
85
  <Input.Root>
88
- {layout !== 'inline' && <Input.Label>{t('longitude.label')}</Input.Label>}
86
+ {presentation.showLabel && <Input.Label>{t('longitude.label')}</Input.Label>}
89
87
  <Input.TextInput
90
88
  type='number'
91
89
  step='0.00001'
@@ -101,7 +99,7 @@ export const GeoPointField = ({
101
99
  </div>
102
100
  </div>
103
101
  )}
104
- </Input.Root>
102
+ </FormRow>
105
103
  );
106
104
  };
107
105
 
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './GeoPointField';
@@ -16,20 +16,20 @@ import { Text } from '@dxos/schema';
16
16
 
17
17
  import { translations } from '#translations';
18
18
 
19
- import { TestLayout } from '../../testing';
20
- import { Form } from '../Form';
19
+ import { TestLayout } from '../../../../../testing';
20
+ import { Form } from '../../../Form';
21
21
 
22
22
  //
23
23
  // String-backed markdown.
24
24
  //
25
25
 
26
- const StringSchema = Schema.Struct({
26
+ const TestSchema = Schema.Struct({
27
27
  notes: Schema.String.pipe(Format.FormatAnnotation.set(Format.TypeFormat.Markdown)).annotations({ title: 'Notes' }),
28
28
  });
29
29
 
30
30
  const StringStory = () => (
31
31
  <TestLayout>
32
- <Form.Root schema={StringSchema} defaultValues={{ notes: '# Hello\n\nMarkdown text *here*.' }}>
32
+ <Form.Root schema={TestSchema} defaultValues={{ notes: '# Hello\n\nMarkdown text *here*.' }}>
33
33
  <Form.Viewport>
34
34
  <Form.Content>
35
35
  <Form.FieldSet />
@@ -61,7 +61,7 @@ const RefStory = () => {
61
61
  return (
62
62
  <TestLayout>
63
63
  <Panel.Root>
64
- <Panel.Content asChild>
64
+ <Panel.Content>
65
65
  <Form.Root schema={TextNoteHolder} values={values as any} db={space.db}>
66
66
  <Form.Viewport>
67
67
  <Form.Content>
@@ -96,7 +96,7 @@ const EmptyRefStory = () => {
96
96
  return (
97
97
  <TestLayout>
98
98
  <Panel.Root>
99
- <Panel.Content asChild>
99
+ <Panel.Content>
100
100
  <Form.Root schema={EmptyRefSchema} defaultValues={{}} db={space.db}>
101
101
  <Form.Viewport>
102
102
  <Form.Content>
@@ -111,7 +111,7 @@ const EmptyRefStory = () => {
111
111
  };
112
112
 
113
113
  const meta = {
114
- title: 'ui/react-ui-form/MarkdownField',
114
+ title: 'ui/react-ui-form/FormField/MarkdownField',
115
115
  decorators: [withTheme(), withLayout({ layout: 'column' })],
116
116
  parameters: {
117
117
  layout: 'fullscreen',
@@ -134,7 +134,7 @@ export const StringBacked: Story = {
134
134
  export const StringBackedKeepsFocus: Story = {
135
135
  render: () => (
136
136
  <TestLayout>
137
- <Form.Root schema={StringSchema} defaultValues={{ notes: '' }}>
137
+ <Form.Root schema={TestSchema} defaultValues={{ notes: '' }}>
138
138
  <Form.Viewport>
139
139
  <Form.Content>
140
140
  <Form.FieldSet />
@@ -5,19 +5,27 @@
5
5
  import { useAtomValue } from '@effect-atom/atom-react';
6
6
  import React, { useCallback, useMemo } from 'react';
7
7
 
8
- import { type Database, Obj, Ref } from '@dxos/echo';
9
- import { createDocAccessor } from '@dxos/echo-client';
10
- import { Button, Icon, Input, useTranslation } from '@dxos/react-ui';
8
+ import { type Database, Ref } from '@dxos/echo';
9
+ import { Doc } from '@dxos/echo-doc';
10
+ import { IconButton, useTranslation } from '@dxos/react-ui';
11
11
  import { Editor, useBasicMarkdownExtensions } from '@dxos/react-ui-editor';
12
12
  import { Text } from '@dxos/schema';
13
13
  import { createDataExtensions } from '@dxos/ui-editor';
14
14
 
15
15
  import { translationKey } from '#translations';
16
+ import { type FormFieldRendererProps } from '#types';
16
17
 
17
- import { type FormFieldComponentProps, FormFieldLabel } from '../FormFieldComponent';
18
+ import { FormRow } from '../../FormRow';
18
19
 
19
- const editorClassNames =
20
- 'transition-colors bg-input-surface focus-within:bg-focus-surface border border-separator rounded-xs p-1 px-2';
20
+ // Mirror the focus treatment of `Input` (default variant): a `focus-ring-subtle` ring of `dx-focus-line`
21
+ // width rather than a recolored 1px border, and suppress the editor wrapper's `accent-bg` border so a
22
+ // second click never turns the outline blue. Keyed on `focus-within` because focus lands on the inner
23
+ // CodeMirror contenteditable, not this wrapper.
24
+ const editorClassNames = [
25
+ 'min-h-[6lh] transition-colors rounded-xs p-1 px-2 bg-input-surface border border-input-separator',
26
+ 'focus:border-separator focus-within:border-separator focus-within:bg-focus-surface',
27
+ 'focus-within:ring-2 focus-within:ring-offset-0 focus-within:ring-focus-ring-subtle focus-within:z-[1]',
28
+ ];
21
29
 
22
30
  /**
23
31
  * Form field that edits a markdown value in a CodeMirror editor.
@@ -29,28 +37,30 @@ const editorClassNames =
29
37
  export const MarkdownField = ({
30
38
  type,
31
39
  readonly,
32
- label,
33
- jsonPath,
34
40
  placeholder,
35
- layout,
36
41
  db,
37
- getStatus,
38
42
  getValue,
39
43
  onValueChange,
40
- }: FormFieldComponentProps) => {
41
- const { status, error } = getStatus();
44
+ ...props
45
+ }: FormFieldRendererProps) => {
42
46
  const isRef = Ref.isRefType(type);
43
- const value = getValue();
44
47
 
45
- if ((readonly || layout === 'static') && value == null) {
46
- return null;
47
- }
48
+ // The field value is a runtime union the form's value type can't express: a `Ref<Text>` when the
49
+ // property is a markdown ref, or a plain string when it is annotated markdown text. `isRef`
50
+ // selects the branch, so the casts below narrow the opaque value accordingly.
51
+ const renderStatic = (value: unknown) => {
52
+ if (isRef) {
53
+ const reference = value as Ref.Ref<any> | undefined;
54
+ return reference ? <RefStaticText reference={reference} /> : null;
55
+ }
56
+ return <p className='whitespace-pre-wrap'>{(value as string | undefined) ?? ''}</p>;
57
+ };
48
58
 
49
- const renderEditor = () => {
59
+ const renderEditor = (value: unknown) => {
50
60
  if (isRef) {
51
61
  const reference = value as Ref.Ref<any> | undefined;
52
62
  if (reference) {
53
- return <RefMarkdownEditor reference={reference} placeholder={placeholder} />;
63
+ return <RefMarkdownEditor reference={reference} placeholder={placeholder} readonly={!!readonly} />;
54
64
  }
55
65
 
56
66
  if (readonly) {
@@ -70,20 +80,10 @@ export const MarkdownField = ({
70
80
  );
71
81
  };
72
82
 
73
- const renderStatic = () => {
74
- if (isRef) {
75
- const reference = value as Ref.Ref<any> | undefined;
76
- return reference ? <RefStaticText reference={reference} /> : null;
77
- }
78
- return <p className='whitespace-pre-wrap'>{(value as string | undefined) ?? ''}</p>;
79
- };
80
-
81
83
  return (
82
- <Input.Root validationValence={status}>
83
- {layout !== 'inline' && <FormFieldLabel error={error} readonly={readonly} label={label} path={jsonPath} />}
84
- {layout === 'static' ? renderStatic() : renderEditor()}
85
- {layout === 'full' && <Input.Validation>{error}</Input.Validation>}
86
- </Input.Root>
84
+ <FormRow readonly={readonly} getValue={getValue} renderStatic={renderStatic} {...props}>
85
+ {({ value }) => renderEditor(value)}
86
+ </FormRow>
87
87
  );
88
88
  };
89
89
 
@@ -93,21 +93,23 @@ const RefStaticText = ({ reference }: { reference: Ref.Ref<any> }) => {
93
93
  if (!text?.content) {
94
94
  return null;
95
95
  }
96
+
96
97
  return <p className='whitespace-pre-wrap'>{text.content}</p>;
97
98
  };
98
99
 
99
100
  type RefMarkdownEditorProps = {
100
101
  reference: Ref.Ref<any>;
101
102
  placeholder?: string;
103
+ readonly?: boolean;
102
104
  };
103
105
 
104
- const RefMarkdownEditor = ({ reference, placeholder }: RefMarkdownEditorProps) => {
106
+ const RefMarkdownEditor = ({ reference, placeholder, readonly }: RefMarkdownEditorProps) => {
105
107
  const text = useAtomValue(useMemo(() => reference.atom, [reference]));
106
108
  const dataExtensions = useMemo(
107
- () => (text ? [createDataExtensions({ id: reference.uri, text: createDocAccessor(text, ['content']) })] : []),
109
+ () => (text ? [createDataExtensions({ id: reference.uri, text: Doc.createAccessor(text, ['content']) })] : []),
108
110
  [text, reference],
109
111
  );
110
- const extensions = useBasicMarkdownExtensions({ placeholder, extensions: dataExtensions });
112
+ const extensions = useBasicMarkdownExtensions({ placeholder, readonly, extensions: dataExtensions });
111
113
  if (!text) {
112
114
  return null;
113
115
  }
@@ -127,7 +129,7 @@ type StringMarkdownEditorProps = {
127
129
  };
128
130
 
129
131
  const StringMarkdownEditor = ({ value, placeholder, readonly, onChange }: StringMarkdownEditorProps) => {
130
- const extensions = useBasicMarkdownExtensions({ placeholder });
132
+ const extensions = useBasicMarkdownExtensions({ placeholder, readonly });
131
133
  const handleChange = useCallback((next: string) => onChange(next), [onChange]);
132
134
 
133
135
  return (
@@ -150,18 +152,16 @@ type CreateTextButtonProps = {
150
152
 
151
153
  const CreateTextButton = ({ db, disabled, onCreate }: CreateTextButtonProps) => {
152
154
  const { t } = useTranslation(translationKey);
155
+
153
156
  const handleClick = useCallback(() => {
154
157
  if (!db) {
155
158
  return;
156
159
  }
157
- const text = db.add(Obj.make(Text.Text, { content: '' }));
158
- onCreate(Ref.make(text));
160
+
161
+ onCreate(Ref.make(db.add(Text.make())));
159
162
  }, [db, onCreate]);
160
163
 
161
164
  return (
162
- <Button onClick={handleClick} disabled={disabled}>
163
- <Icon icon='ph--plus--regular' size={4} />
164
- <span>{t('create-text.label')}</span>
165
- </Button>
165
+ <IconButton icon='ph--plus--regular' label={t('create-text.label')} onClick={handleClick} disabled={disabled} />
166
166
  );
167
167
  };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './MarkdownField';
@@ -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
+ count: Schema.Number.annotations({ title: 'Count' }),
18
+ }).pipe(Schema.mutable);
19
+
20
+ type Values = Schema.Schema.Type<typeof schema>;
21
+
22
+ const DefaultStory = () => {
23
+ const [values, setValues] = useState<Values>({ count: 42 });
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/NumberField',
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 = {};
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import { getNumericConstraints } from './NumberField';
9
+
10
+ describe('getNumericConstraints', () => {
11
+ test('reads min/max from Schema.between (bounds live on separate nested refinements)', ({ expect }) => {
12
+ const { ast } = Schema.Number.pipe(Schema.between(0, 23));
13
+ expect(getNumericConstraints(ast)).toEqual({ min: 0, max: 23, integer: false });
14
+ });
15
+
16
+ test('detects integer from Schema.int', ({ expect }) => {
17
+ const { ast } = Schema.Number.pipe(Schema.int(), Schema.between(0, 23));
18
+ expect(getNumericConstraints(ast)).toEqual({ min: 0, max: 23, integer: true });
19
+ });
20
+
21
+ test('returns empty constraints for an unconstrained number', ({ expect }) => {
22
+ expect(getNumericConstraints(Schema.Number.ast)).toEqual({ integer: false });
23
+ });
24
+
25
+ test('aggregates stacked bounds to the strictest (intersection semantics)', ({ expect }) => {
26
+ const { ast } = Schema.Number.pipe(Schema.greaterThanOrEqualTo(5), Schema.greaterThanOrEqualTo(10));
27
+ expect(getNumericConstraints(ast)).toEqual({ min: 10, max: undefined, integer: false });
28
+ });
29
+ });