@cube-dev/ui-kit 0.0.0-canary-c2f337e → 0.0.0-canary-36c17b9

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 (580) hide show
  1. package/dist/_internal/hooks/use-debounced-value.js +1 -1
  2. package/dist/_internal/hooks/use-deprecation-warning.js +1 -1
  3. package/dist/_internal/hooks/use-event.js +1 -1
  4. package/dist/_internal/hooks/use-is-first-render.js +1 -1
  5. package/dist/_internal/hooks/use-sync-ref.js +1 -1
  6. package/dist/_internal/hooks/use-timer/timer.js +1 -1
  7. package/dist/_internal/hooks/use-timer/use-timer.js +1 -1
  8. package/dist/_internal/hooks/use-warn.js +1 -1
  9. package/dist/components/Block.js +1 -1
  10. package/dist/components/CollectionItem.js +1 -1
  11. package/dist/components/GlobalStyles.js +1 -1
  12. package/dist/components/GridProvider.js +1 -1
  13. package/dist/components/HiddenInput.js +1 -1
  14. package/dist/components/Root.js +1 -1
  15. package/dist/components/actions/Action/Action.js +1 -1
  16. package/dist/components/actions/Banner/Banner.js +1 -1
  17. package/dist/components/actions/Button/Button.d.ts +1 -0
  18. package/dist/components/actions/Button/Button.js +1 -1
  19. package/dist/components/actions/ButtonGroup/ButtonGroup.js +1 -1
  20. package/dist/components/actions/ButtonSplit/ButtonSplit.js +1 -1
  21. package/dist/components/actions/ButtonSplit/context.js +1 -1
  22. package/dist/components/actions/CommandMenu/CommandMenu.js +1 -1
  23. package/dist/components/actions/CommandMenu/styled.js +1 -1
  24. package/dist/components/actions/ItemAction/ItemAction.js +1 -1
  25. package/dist/components/actions/ItemActionContext.js +1 -1
  26. package/dist/components/actions/ItemActionsWrapper.js +1 -1
  27. package/dist/components/actions/ItemButton/ItemButton.js +1 -1
  28. package/dist/components/actions/Link/Link.js +1 -1
  29. package/dist/components/actions/Menu/Menu.js +1 -1
  30. package/dist/components/actions/Menu/MenuItem.js +1 -1
  31. package/dist/components/actions/Menu/MenuSection.js +1 -1
  32. package/dist/components/actions/Menu/MenuTrigger.js +1 -1
  33. package/dist/components/actions/Menu/SubMenuTrigger.js +1 -1
  34. package/dist/components/actions/Menu/SubmenuTriggerContext.js +1 -1
  35. package/dist/components/actions/Menu/context.js +1 -1
  36. package/dist/components/actions/Menu/styled.js +1 -1
  37. package/dist/components/actions/actions-run.js +1 -1
  38. package/dist/components/actions/index.js +1 -1
  39. package/dist/components/actions/use-action.js +1 -1
  40. package/dist/components/actions/use-anchored-menu.js +1 -1
  41. package/dist/components/actions/use-context-menu.js +1 -1
  42. package/dist/components/content/ActiveZone/ActiveZone.js +1 -1
  43. package/dist/components/content/Alert/Alert.js +1 -1
  44. package/dist/components/content/Alert/use-alert.js +1 -1
  45. package/dist/components/content/Avatar/Avatar.js +1 -1
  46. package/dist/components/content/Badge/Badge.js +1 -1
  47. package/dist/components/content/Card/Card.js +1 -1
  48. package/dist/components/content/Content.js +1 -1
  49. package/dist/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
  50. package/dist/components/content/CopySnippet/CopySnippet.js +1 -1
  51. package/dist/components/content/Disclosure/Disclosure.js +1 -1
  52. package/dist/components/content/Divider.js +1 -1
  53. package/dist/components/content/Footer.js +1 -1
  54. package/dist/components/content/Header.js +1 -1
  55. package/dist/components/content/HotKeys/HotKeys.js +1 -1
  56. package/dist/components/content/InfoBadge/InfoBadge.js +1 -1
  57. package/dist/components/content/InlineInput/InlineInput.js +1 -1
  58. package/dist/components/content/Item/Item.js +1 -1
  59. package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
  60. package/dist/components/content/ItemCard/ItemCard.js +1 -1
  61. package/dist/components/content/Layout/GridLayout.js +1 -1
  62. package/dist/components/content/Layout/Layout.js +1 -1
  63. package/dist/components/content/Layout/LayoutBlock.js +1 -1
  64. package/dist/components/content/Layout/LayoutCenter.js +1 -1
  65. package/dist/components/content/Layout/LayoutContainer.js +1 -1
  66. package/dist/components/content/Layout/LayoutContent.js +1 -1
  67. package/dist/components/content/Layout/LayoutContext.js +1 -1
  68. package/dist/components/content/Layout/LayoutFlex.js +1 -1
  69. package/dist/components/content/Layout/LayoutFooter.js +1 -1
  70. package/dist/components/content/Layout/LayoutGrid.js +1 -1
  71. package/dist/components/content/Layout/LayoutHeader.js +1 -1
  72. package/dist/components/content/Layout/LayoutPane.js +1 -1
  73. package/dist/components/content/Layout/LayoutPanel.js +1 -1
  74. package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
  75. package/dist/components/content/Layout/LayoutToolbar.js +1 -1
  76. package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
  77. package/dist/components/content/Layout/index.js +1 -1
  78. package/dist/components/content/Layout/utils.js +1 -1
  79. package/dist/components/content/Paragraph.js +1 -1
  80. package/dist/components/content/Placeholder/Placeholder.js +1 -1
  81. package/dist/components/content/PrismCode/PrismCode.js +1 -1
  82. package/dist/components/content/PrismCode/prismSetup.js +1 -1
  83. package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
  84. package/dist/components/content/Result/Result.js +1 -1
  85. package/dist/components/content/Skeleton/Skeleton.js +1 -1
  86. package/dist/components/content/Tag/Tag.js +1 -1
  87. package/dist/components/content/Text.js +1 -1
  88. package/dist/components/content/TextItem/TextItem.js +1 -1
  89. package/dist/components/content/Title.js +1 -1
  90. package/dist/components/content/Tree/Tree.js +1 -1
  91. package/dist/components/content/Tree/TreeNode.js +1 -1
  92. package/dist/components/content/Tree/styled.js +1 -1
  93. package/dist/components/content/Tree/tree-index.js +1 -1
  94. package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
  95. package/dist/components/content/Tree/use-load-data.js +1 -1
  96. package/dist/components/content/highlightText.js +1 -1
  97. package/dist/components/content/use-auto-tooltip.js +1 -1
  98. package/dist/components/data/DataTable/DataTable.js +1 -1
  99. package/dist/components/data/ItemTable/ItemTable.js +1 -1
  100. package/dist/components/data/ItemTable/ItemTableBulkBar.js +1 -1
  101. package/dist/components/data/ItemTable/ItemTableDragPreview.js +1 -1
  102. package/dist/components/data/ItemTable/ItemTableFooter.js +1 -1
  103. package/dist/components/data/ItemTable/ItemTableToolbar.js +1 -1
  104. package/dist/components/data/TableBase/ColumnResizer.js +1 -1
  105. package/dist/components/data/TableBase/RowCollection.js +1 -1
  106. package/dist/components/data/TableBase/TableHeaderCell.js +1 -1
  107. package/dist/components/data/TableBase/TableRow.js +1 -1
  108. package/dist/components/data/TableBase/TableView.js +1 -1
  109. package/dist/components/data/TableBase/column-menu.js +1 -1
  110. package/dist/components/data/TableBase/column-tint.js +1 -1
  111. package/dist/components/data/TableBase/row-menu.js +1 -1
  112. package/dist/components/data/TableBase/styled.d.ts +2 -1
  113. package/dist/components/data/TableBase/styled.js +1 -1
  114. package/dist/components/data/TableBase/table-tree.js +1 -1
  115. package/dist/components/data/TableBase/types.js +1 -1
  116. package/dist/components/data/TableBase/use-cell-selection.d.ts +1 -0
  117. package/dist/components/data/TableBase/use-cell-selection.js +0 -0
  118. package/dist/components/data/TableBase/use-column-order.js +1 -1
  119. package/dist/components/data/TableBase/use-container-width.js +1 -1
  120. package/dist/components/data/TableBase/use-row-move-animation.js +1 -1
  121. package/dist/components/data/TableBase/use-scrollability.js +1 -1
  122. package/dist/components/data/TableBase/use-table-columns.js +1 -1
  123. package/dist/components/data/TableBase/use-table-search.js +1 -1
  124. package/dist/components/data/TableBase/use-table-selection.js +1 -1
  125. package/dist/components/data/TableBase/use-table-sort.js +1 -1
  126. package/dist/components/data/TableBase/use-table-sorts.js +1 -1
  127. package/dist/components/data/TableBase/use-table-storage.js +1 -1
  128. package/dist/components/data/TableBase/use-table-tree-state.js +1 -1
  129. package/dist/components/fields/Checkbox/Checkbox.js +1 -1
  130. package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
  131. package/dist/components/fields/Checkbox/context.js +1 -1
  132. package/dist/components/fields/ColorInput/ColorInput.js +1 -1
  133. package/dist/components/fields/ColorPicker/ColorPicker.js +1 -1
  134. package/dist/components/fields/ColorSwatch/ColorSwatch.js +1 -1
  135. package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js +1 -1
  136. package/dist/components/fields/ComboBox/ComboBox.js +1 -1
  137. package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
  138. package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
  139. package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
  140. package/dist/components/fields/DatePicker/DateInput.js +1 -1
  141. package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
  142. package/dist/components/fields/DatePicker/DatePicker.js +1 -1
  143. package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
  144. package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
  145. package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
  146. package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
  147. package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
  148. package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
  149. package/dist/components/fields/DatePicker/MonthPicker.js +1 -1
  150. package/dist/components/fields/DatePicker/PeriodPicker.js +1 -1
  151. package/dist/components/fields/DatePicker/QuarterPicker.js +1 -1
  152. package/dist/components/fields/DatePicker/TimeInput.js +1 -1
  153. package/dist/components/fields/DatePicker/WeekPicker.js +1 -1
  154. package/dist/components/fields/DatePicker/YearPicker.js +1 -1
  155. package/dist/components/fields/DatePicker/parseDate.js +1 -1
  156. package/dist/components/fields/DatePicker/period.js +1 -1
  157. package/dist/components/fields/DatePicker/props.js +1 -1
  158. package/dist/components/fields/DatePicker/utils.js +1 -1
  159. package/dist/components/fields/FileInput/FileInput.js +1 -1
  160. package/dist/components/fields/FilterListBox/FilterListBox.js +1 -1
  161. package/dist/components/fields/FilterPicker/FilterPicker.js +1 -1
  162. package/dist/components/fields/Input/Input.js +1 -1
  163. package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
  164. package/dist/components/fields/ListBox/ListBox.js +1 -1
  165. package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
  166. package/dist/components/fields/ListBoxPopover/index.d.ts +1 -0
  167. package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
  168. package/dist/components/fields/ListBoxPopover/useCompositeFocus.d.ts +2 -0
  169. package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
  170. package/dist/components/fields/NumberInput/NumberInput.js +1 -1
  171. package/dist/components/fields/NumberInput/StepButton.js +1 -1
  172. package/dist/components/fields/PasswordInput/PasswordInput.js +1 -1
  173. package/dist/components/fields/Picker/Picker.js +1 -1
  174. package/dist/components/fields/RadioGroup/Radio.js +1 -1
  175. package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
  176. package/dist/components/fields/RadioGroup/context.js +1 -1
  177. package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
  178. package/dist/components/fields/SearchInput/SearchInput.js +1 -1
  179. package/dist/components/fields/Select/Select.js +1 -1
  180. package/dist/components/fields/Slider/Gradation.js +1 -1
  181. package/dist/components/fields/Slider/HueSlider.js +1 -1
  182. package/dist/components/fields/Slider/RangeSlider.js +1 -1
  183. package/dist/components/fields/Slider/Slider.js +1 -1
  184. package/dist/components/fields/Slider/SliderBase.js +1 -1
  185. package/dist/components/fields/Slider/SliderThumb.js +1 -1
  186. package/dist/components/fields/Slider/SliderTrack.js +1 -1
  187. package/dist/components/fields/Slider/elements.js +1 -1
  188. package/dist/components/fields/Slider/index.js +1 -1
  189. package/dist/components/fields/Switch/Switch.js +1 -1
  190. package/dist/components/fields/TextArea/TextArea.js +1 -1
  191. package/dist/components/fields/TextInput/TextInput.js +1 -1
  192. package/dist/components/fields/TextInput/TextInputBase.js +1 -1
  193. package/dist/components/fields/TextInput/useAutoSizeTextArea.js +1 -1
  194. package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
  195. package/dist/components/fields/TriggerActions.js +1 -1
  196. package/dist/components/fields/color/ColorPanel.js +1 -1
  197. package/dist/components/fields/color/channels.js +1 -1
  198. package/dist/components/fields/color/color.js +1 -1
  199. package/dist/components/fields/color/context.js +1 -1
  200. package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
  201. package/dist/components/form/Form/Field.js +1 -1
  202. package/dist/components/form/Form/Form.js +1 -1
  203. package/dist/components/form/Form/ModernFormRoot.js +1 -1
  204. package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
  205. package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
  206. package/dist/components/form/Form/SubmitError.js +1 -1
  207. package/dist/components/form/Form/backend.js +1 -1
  208. package/dist/components/form/Form/index.js +1 -1
  209. package/dist/components/form/Form/modern/actions.js +1 -1
  210. package/dist/components/form/Form/modern/context.d.ts +1 -0
  211. package/dist/components/form/Form/modern/context.js +1 -1
  212. package/dist/components/form/Form/modern/controller.js +1 -1
  213. package/dist/components/form/Form/modern/field-binding.js +2 -2
  214. package/dist/components/form/Form/modern/field-binding.js.map +1 -1
  215. package/dist/components/form/Form/modern/field.js +5 -5
  216. package/dist/components/form/Form/modern/field.js.map +1 -1
  217. package/dist/components/form/Form/modern/react.js +1 -1
  218. package/dist/components/form/Form/modern/store.js +3 -3
  219. package/dist/components/form/Form/modern/store.js.map +1 -1
  220. package/dist/components/form/Form/modern/types.d.ts +1 -1
  221. package/dist/components/form/Form/modern/validation.js +3 -3
  222. package/dist/components/form/Form/modern/validation.js.map +1 -1
  223. package/dist/components/form/Form/modern/values.js +1 -1
  224. package/dist/components/form/Form/use-field/use-field-binding.js +1 -1
  225. package/dist/components/form/Form/use-field/use-field-props.js +1 -1
  226. package/dist/components/form/Form/use-field/use-field.js +1 -1
  227. package/dist/components/form/Form/use-form.js +1 -1
  228. package/dist/components/form/Form/validation.js +1 -1
  229. package/dist/components/form/Label.js +1 -1
  230. package/dist/components/form/validation/ValidationIndicator.js +1 -1
  231. package/dist/components/form/validation/resolve-validation-props.js +1 -1
  232. package/dist/components/form/validation/use-validation-props.js +1 -1
  233. package/dist/components/form/wrapper.js +1 -1
  234. package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
  235. package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
  236. package/dist/components/layout/Board/Board.js +1 -1
  237. package/dist/components/layout/Board/BoardProvider.js +1 -1
  238. package/dist/components/layout/Board/BoardResponsive.js +1 -1
  239. package/dist/components/layout/Board/Widget.js +1 -1
  240. package/dist/components/layout/Board/WidgetHost.js +1 -1
  241. package/dist/components/layout/Board/board-context.js +1 -1
  242. package/dist/components/layout/Board/board-store.js +1 -1
  243. package/dist/components/layout/Board/grid-core/calculate.js +1 -1
  244. package/dist/components/layout/Board/grid-core/collision-modes.js +1 -1
  245. package/dist/components/layout/Board/grid-core/collision.js +1 -1
  246. package/dist/components/layout/Board/grid-core/compactors.js +1 -1
  247. package/dist/components/layout/Board/grid-core/constraints.js +1 -1
  248. package/dist/components/layout/Board/grid-core/group-move.js +1 -1
  249. package/dist/components/layout/Board/grid-core/layout.js +1 -1
  250. package/dist/components/layout/Board/grid-core/placement.js +1 -1
  251. package/dist/components/layout/Board/grid-core/sort.js +1 -1
  252. package/dist/components/layout/Board/index.js +1 -1
  253. package/dist/components/layout/Board/responsive-utils.js +1 -1
  254. package/dist/components/layout/Board/use-board-layout.js +1 -1
  255. package/dist/components/layout/Board/use-board-registry.js +1 -1
  256. package/dist/components/layout/Board/use-board-select-modifier-key.js +1 -1
  257. package/dist/components/layout/Board/use-board-selection.js +1 -1
  258. package/dist/components/layout/Flex.js +1 -1
  259. package/dist/components/layout/Flow.js +1 -1
  260. package/dist/components/layout/Grid.js +1 -1
  261. package/dist/components/layout/Panel.js +1 -1
  262. package/dist/components/layout/Prefix.js +1 -1
  263. package/dist/components/layout/ResizablePanel.js +1 -1
  264. package/dist/components/layout/Space.js +1 -1
  265. package/dist/components/layout/Suffix.js +1 -1
  266. package/dist/components/navigation/Pagination/Pagination.js +1 -1
  267. package/dist/components/navigation/Pagination/use-pagination.js +1 -1
  268. package/dist/components/navigation/Tabs/DraggableTabList.js +1 -1
  269. package/dist/components/navigation/Tabs/TabButton.js +1 -1
  270. package/dist/components/navigation/Tabs/TabDropIndicator.js +1 -1
  271. package/dist/components/navigation/Tabs/TabPanel.js +1 -1
  272. package/dist/components/navigation/Tabs/TabPicker.js +1 -1
  273. package/dist/components/navigation/Tabs/Tabs.js +1 -1
  274. package/dist/components/navigation/Tabs/TabsAction.js +1 -1
  275. package/dist/components/navigation/Tabs/TabsContext.js +1 -1
  276. package/dist/components/navigation/Tabs/popover-placement.js +1 -1
  277. package/dist/components/navigation/Tabs/styled.js +1 -1
  278. package/dist/components/navigation/Tabs/types.js +1 -1
  279. package/dist/components/navigation/Tabs/use-tab-editing.js +1 -1
  280. package/dist/components/navigation/Tabs/use-tab-indicator.js +1 -1
  281. package/dist/components/organisms/StatsCard/StatsCard.js +1 -1
  282. package/dist/components/other/Calendar/Calendar.js +1 -1
  283. package/dist/components/other/Calendar/CalendarCell.js +1 -1
  284. package/dist/components/other/Calendar/CalendarGrid.js +1 -1
  285. package/dist/components/other/Calendar/CalendarHeader.js +1 -1
  286. package/dist/components/other/Calendar/CalendarPanel.js +1 -1
  287. package/dist/components/other/Calendar/PeriodCalendar.js +1 -1
  288. package/dist/components/other/Calendar/PeriodGrid.js +1 -1
  289. package/dist/components/other/Calendar/RangeCalendar.js +1 -1
  290. package/dist/components/other/Calendar/styled.js +1 -1
  291. package/dist/components/other/CubeLogo/CubeLogo.js +1 -1
  292. package/dist/components/other/NoDataIcon/NoDataIcon.js +1 -1
  293. package/dist/components/overlays/AlertDialog/AlertDialog.js +1 -1
  294. package/dist/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
  295. package/dist/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
  296. package/dist/components/overlays/Dialog/Dialog.js +1 -1
  297. package/dist/components/overlays/Dialog/DialogContainer.js +1 -1
  298. package/dist/components/overlays/Dialog/DialogForm.js +1 -1
  299. package/dist/components/overlays/Dialog/DialogTrigger.js +1 -1
  300. package/dist/components/overlays/Dialog/context.js +1 -1
  301. package/dist/components/overlays/Dialog/use-dialog-container.js +1 -1
  302. package/dist/components/overlays/Modal/Modal.d.ts +2 -1
  303. package/dist/components/overlays/Modal/Modal.js +1 -1
  304. package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -1
  305. package/dist/components/overlays/Modal/Overlay.d.ts +1 -0
  306. package/dist/components/overlays/Modal/Overlay.js +1 -1
  307. package/dist/components/overlays/Modal/Popover.js +1 -1
  308. package/dist/components/overlays/Modal/Tray.js +1 -1
  309. package/dist/components/overlays/Modal/Underlay.js +1 -1
  310. package/dist/components/overlays/Modal/types.d.ts +1 -0
  311. package/dist/components/overlays/Notifications/Notification.js +1 -1
  312. package/dist/components/overlays/Notifications/NotificationAction.js +1 -1
  313. package/dist/components/overlays/Notifications/NotificationCard.js +1 -1
  314. package/dist/components/overlays/Notifications/NotificationContext.d.ts +2 -0
  315. package/dist/components/overlays/Notifications/NotificationContext.js +1 -1
  316. package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
  317. package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
  318. package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
  319. package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
  320. package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
  321. package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
  322. package/dist/components/overlays/Notifications/index.js +1 -1
  323. package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
  324. package/dist/components/overlays/Notifications/use-notifications.js +1 -1
  325. package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
  326. package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
  327. package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
  328. package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
  329. package/dist/components/overlays/Toast/ToastItem.js +1 -1
  330. package/dist/components/overlays/Toast/index.js +1 -1
  331. package/dist/components/overlays/Toast/useProgressToast.js +1 -1
  332. package/dist/components/overlays/Toast/useToast.js +1 -1
  333. package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
  334. package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
  335. package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
  336. package/dist/components/overlays/Tooltip/context.js +1 -1
  337. package/dist/components/portal/Portal.js +1 -1
  338. package/dist/components/portal/PortalProvider.d.ts +2 -0
  339. package/dist/components/portal/PortalProvider.js +1 -1
  340. package/dist/components/portal/index.d.ts +1 -0
  341. package/dist/components/portal/usePortal.js +1 -1
  342. package/dist/components/shared/DraggableCollection.js +1 -1
  343. package/dist/components/shared/InvalidIcon.js +1 -1
  344. package/dist/components/shared/ValidIcon.js +1 -1
  345. package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
  346. package/dist/components/status/Spin/Cube.js +1 -1
  347. package/dist/components/status/Spin/InternalSpinner.js +1 -1
  348. package/dist/components/status/Spin/Spin.js +1 -1
  349. package/dist/components/status/Spin/SpinsContainer.js +1 -1
  350. package/dist/data/item-themes.js +1 -1
  351. package/dist/data/themes.js +1 -1
  352. package/dist/eslint-plugin/defaults.generated.js +1 -1
  353. package/dist/eslint-plugin/index.js +1 -1
  354. package/dist/eslint-plugin/rules/no-redundant-default-prop.js +1 -1
  355. package/dist/i18n/I18nProvider.js +1 -1
  356. package/dist/i18n/createFormatter.js +1 -1
  357. package/dist/i18n/index.js +1 -1
  358. package/dist/i18n/instance.js +1 -1
  359. package/dist/i18n/locales/de-DE/uikit.js +1 -1
  360. package/dist/i18n/locales/en-US/uikit.js +1 -1
  361. package/dist/i18n/locales/es-ES/uikit.js +1 -1
  362. package/dist/i18n/locales/es-MX/uikit.js +1 -1
  363. package/dist/i18n/locales/fr-FR/uikit.js +1 -1
  364. package/dist/i18n/locales/it-IT/uikit.js +1 -1
  365. package/dist/i18n/locales/ja-JP/uikit.js +1 -1
  366. package/dist/i18n/locales/nb-NO/uikit.js +1 -1
  367. package/dist/i18n/locales/pt-BR/uikit.js +1 -1
  368. package/dist/i18n/locales/pt-PT/uikit.js +1 -1
  369. package/dist/i18n/locales/sv-SE/uikit.js +1 -1
  370. package/dist/i18n/locales/vi-VN/uikit.js +1 -1
  371. package/dist/i18n/locales.js +1 -1
  372. package/dist/i18n/useFormatter.js +1 -1
  373. package/dist/i18n/useI18n.js +1 -1
  374. package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
  375. package/dist/icons/AdjustmentsIcon.js +1 -1
  376. package/dist/icons/AiIcon.js +1 -1
  377. package/dist/icons/AreaChartIcon.js +1 -1
  378. package/dist/icons/ArrowNarrowDownIcon.js +1 -1
  379. package/dist/icons/ArrowNarrowUpIcon.js +1 -1
  380. package/dist/icons/BackwardIcon.js +1 -1
  381. package/dist/icons/BarChartIcon.js +1 -1
  382. package/dist/icons/BellFilledIcon.js +1 -1
  383. package/dist/icons/BellIcon.js +1 -1
  384. package/dist/icons/BooleanIcon.js +1 -1
  385. package/dist/icons/CalendarEditIcon.js +1 -1
  386. package/dist/icons/CalendarIcon.js +1 -1
  387. package/dist/icons/CaretDownIcon.js +1 -1
  388. package/dist/icons/CaretUpIcon.js +1 -1
  389. package/dist/icons/ChartAreaStackedIcon.js +1 -1
  390. package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
  391. package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
  392. package/dist/icons/ChartBarGroupedIcon.js +1 -1
  393. package/dist/icons/ChartBarHorizontalIcon.js +1 -1
  394. package/dist/icons/ChartBarLineIcon.js +1 -1
  395. package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
  396. package/dist/icons/ChartBarStackedIcon.js +1 -1
  397. package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
  398. package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
  399. package/dist/icons/ChartBoxPlot2Icon.js +1 -1
  400. package/dist/icons/ChartBoxPlotIcon.js +1 -1
  401. package/dist/icons/ChartBubbleIcon.js +1 -1
  402. package/dist/icons/ChartDonut2Icon.js +1 -1
  403. package/dist/icons/ChartFunnelIcon.js +1 -1
  404. package/dist/icons/ChartHeatmapIcon.js +1 -1
  405. package/dist/icons/ChartKPIIcon.js +1 -1
  406. package/dist/icons/ChartPie2Icon.js +1 -1
  407. package/dist/icons/ChartScatterIcon.js +1 -1
  408. package/dist/icons/CheckCircleFilledIcon.js +1 -1
  409. package/dist/icons/CheckCircleIcon.js +1 -1
  410. package/dist/icons/CheckIcon.js +1 -1
  411. package/dist/icons/CircleFilledIcon.js +1 -1
  412. package/dist/icons/ClearIcon.js +1 -1
  413. package/dist/icons/CloseCircleFilledIcon.js +1 -1
  414. package/dist/icons/CloseCircleIcon.js +1 -1
  415. package/dist/icons/CloseIcon.js +1 -1
  416. package/dist/icons/CodeIcon.js +1 -1
  417. package/dist/icons/ColumnTotalIcon.js +1 -1
  418. package/dist/icons/CopyIcon.js +1 -1
  419. package/dist/icons/CountIcon.js +1 -1
  420. package/dist/icons/CubeIcon.js +1 -1
  421. package/dist/icons/CubePauseIcon.js +1 -1
  422. package/dist/icons/CubePlayIcon.js +1 -1
  423. package/dist/icons/CurrencyDollarIcon.js +1 -1
  424. package/dist/icons/DangerIcon.js +1 -1
  425. package/dist/icons/DashboardIcon.js +1 -1
  426. package/dist/icons/DatabaseIcon.js +1 -1
  427. package/dist/icons/DecimalDecreaseIcon.js +1 -1
  428. package/dist/icons/DecimalIncreaseIcon.js +1 -1
  429. package/dist/icons/DirectionIcon.js +1 -1
  430. package/dist/icons/DonutIcon.js +1 -1
  431. package/dist/icons/DownIcon.js +1 -1
  432. package/dist/icons/EditIcon.js +1 -1
  433. package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
  434. package/dist/icons/ExclamationCircleIcon.js +1 -1
  435. package/dist/icons/ExclamationIcon.js +1 -1
  436. package/dist/icons/EyeIcon.js +1 -1
  437. package/dist/icons/EyeInvisibleIcon.js +1 -1
  438. package/dist/icons/FilterIcon.js +1 -1
  439. package/dist/icons/FolderFilledIcon.js +1 -1
  440. package/dist/icons/FolderIcon.js +1 -1
  441. package/dist/icons/FolderOpenFilledIcon.js +1 -1
  442. package/dist/icons/FolderOpenIcon.js +1 -1
  443. package/dist/icons/ForwardIcon.js +1 -1
  444. package/dist/icons/GripVerticalIcon.js +1 -1
  445. package/dist/icons/HierarchyIcon.js +1 -1
  446. package/dist/icons/HierarchyOpenIcon.js +1 -1
  447. package/dist/icons/Icon.js +1 -1
  448. package/dist/icons/InfoCircleIcon.js +1 -1
  449. package/dist/icons/InfoIcon.js +1 -1
  450. package/dist/icons/KeyIcon.js +1 -1
  451. package/dist/icons/LeftIcon.js +1 -1
  452. package/dist/icons/LineChartIcon.js +1 -1
  453. package/dist/icons/LoadingIcon.js +1 -1
  454. package/dist/icons/LockFilledIcon.js +1 -1
  455. package/dist/icons/LockIcon.js +1 -1
  456. package/dist/icons/MoreIcon.js +1 -1
  457. package/dist/icons/NotAllowedIcon.js +1 -1
  458. package/dist/icons/Number123Icon.js +1 -1
  459. package/dist/icons/NumberIcon.js +1 -1
  460. package/dist/icons/PauseCircleFilledIcon.js +1 -1
  461. package/dist/icons/PauseCircleIcon.js +1 -1
  462. package/dist/icons/PauseIcon.js +1 -1
  463. package/dist/icons/PercentageIcon.js +1 -1
  464. package/dist/icons/PieChartIcon.js +1 -1
  465. package/dist/icons/PipetteIcon.js +1 -1
  466. package/dist/icons/PlayCircleIcon.js +1 -1
  467. package/dist/icons/PlayIcon.js +1 -1
  468. package/dist/icons/PlusIcon.js +1 -1
  469. package/dist/icons/ProgressBarIcon.js +1 -1
  470. package/dist/icons/ReloadIcon.js +1 -1
  471. package/dist/icons/ReportIcon.js +1 -1
  472. package/dist/icons/ReturnIcon.js +1 -1
  473. package/dist/icons/RightIcon.js +1 -1
  474. package/dist/icons/RowTotalsIcon.js +1 -1
  475. package/dist/icons/SchemeIcon.js +1 -1
  476. package/dist/icons/SearchIcon.js +1 -1
  477. package/dist/icons/SemanticQueryIcon.js +1 -1
  478. package/dist/icons/SettingsIcon.js +1 -1
  479. package/dist/icons/ShieldFilledIcon.js +1 -1
  480. package/dist/icons/ShieldIcon.js +1 -1
  481. package/dist/icons/SlashIcon.js +1 -1
  482. package/dist/icons/SparklesIcon.js +1 -1
  483. package/dist/icons/SqlIcon.js +1 -1
  484. package/dist/icons/StatsIcon.js +1 -1
  485. package/dist/icons/StopIcon.js +1 -1
  486. package/dist/icons/StringIcon.js +1 -1
  487. package/dist/icons/SubtotalsIcon.js +1 -1
  488. package/dist/icons/SwitchIcon.js +1 -1
  489. package/dist/icons/TableIcon.js +1 -1
  490. package/dist/icons/ThumbsDownIcon.js +1 -1
  491. package/dist/icons/ThumbsUpIcon.js +1 -1
  492. package/dist/icons/ThunderboltCrossedIcon.js +1 -1
  493. package/dist/icons/ThunderboltFilledIcon.js +1 -1
  494. package/dist/icons/ThunderboltIcon.js +1 -1
  495. package/dist/icons/TimeIcon.js +1 -1
  496. package/dist/icons/TrashIcon.js +1 -1
  497. package/dist/icons/UnlockIcon.js +1 -1
  498. package/dist/icons/UpIcon.js +1 -1
  499. package/dist/icons/UserGroupIcon.js +1 -1
  500. package/dist/icons/UserIcon.js +1 -1
  501. package/dist/icons/UserLockIcon.js +1 -1
  502. package/dist/icons/ViewIcon.js +1 -1
  503. package/dist/icons/WarningFilledIcon.js +1 -1
  504. package/dist/icons/WarningIcon.js +1 -1
  505. package/dist/icons/wrap-icon.js +1 -1
  506. package/dist/index.js +1 -1
  507. package/dist/probe/canonicalize.js +1 -1
  508. package/dist/probe/css.js +1 -1
  509. package/dist/probe/index.js +1 -1
  510. package/dist/provider.js +1 -1
  511. package/dist/providers/TrackingProvider.js +1 -1
  512. package/dist/providers/navigationAdapter.default.js +1 -1
  513. package/dist/shared/form.d.ts +1 -1
  514. package/dist/tokens/all-tokens.js +1 -1
  515. package/dist/tokens/base.js +1 -1
  516. package/dist/tokens/color-seed.js +1 -1
  517. package/dist/tokens/color-theme.js +1 -1
  518. package/dist/tokens/colors.js +1 -1
  519. package/dist/tokens/layout.js +1 -1
  520. package/dist/tokens/lazy-styles.js +1 -1
  521. package/dist/tokens/legacy-color.js +1 -1
  522. package/dist/tokens/palette-config.js +1 -1
  523. package/dist/tokens/palette.js +1 -1
  524. package/dist/tokens/resolve.js +1 -1
  525. package/dist/tokens/shadows.js +1 -1
  526. package/dist/tokens/sizes.js +1 -1
  527. package/dist/tokens/spacing.js +1 -1
  528. package/dist/tokens/typography.js +1 -1
  529. package/dist/utils/ResizeSensor.js +1 -1
  530. package/dist/utils/colors.js +1 -1
  531. package/dist/utils/dotize.js +1 -1
  532. package/dist/utils/is-dev-env.js +1 -1
  533. package/dist/utils/modules.js +1 -1
  534. package/dist/utils/promise.js +1 -1
  535. package/dist/utils/raf.js +1 -1
  536. package/dist/utils/random.js +1 -1
  537. package/dist/utils/range.js +1 -1
  538. package/dist/utils/react/RenderCache.js +1 -1
  539. package/dist/utils/react/Slots.js +1 -1
  540. package/dist/utils/react/chain.js +1 -1
  541. package/dist/utils/react/disabledProps.js +1 -1
  542. package/dist/utils/react/forwardRefWithGenerics.js +1 -1
  543. package/dist/utils/react/index.js +1 -1
  544. package/dist/utils/react/interactions.js +1 -1
  545. package/dist/utils/react/isTextOnly.js +1 -1
  546. package/dist/utils/react/mapProps.js +1 -1
  547. package/dist/utils/react/mergeProps.js +1 -1
  548. package/dist/utils/react/nullableValue.js +1 -1
  549. package/dist/utils/react/resolveIcon.js +1 -1
  550. package/dist/utils/react/sharedStore.js +1 -1
  551. package/dist/utils/react/useBufferedValue.js +1 -1
  552. package/dist/utils/react/useCombinedRefs.js +1 -1
  553. package/dist/utils/react/useControlledFocusVisible.js +1 -1
  554. package/dist/utils/react/useEventBus.js +1 -1
  555. package/dist/utils/react/useId.js +1 -1
  556. package/dist/utils/react/useIsDarwin.js +1 -1
  557. package/dist/utils/react/useKeySymbols.js +1 -1
  558. package/dist/utils/react/useLayoutEffect.js +1 -1
  559. package/dist/utils/react/useLocalStorage.js +1 -1
  560. package/dist/utils/react/useMergeStyles.js +1 -1
  561. package/dist/utils/react/usePopoverSync.js +1 -1
  562. package/dist/utils/react/useQaProps.js +1 -1
  563. package/dist/utils/react/useScheme.js +1 -1
  564. package/dist/utils/react/useViewportSize.js +1 -1
  565. package/dist/utils/react/wrapNodeIfPlain.js +1 -1
  566. package/dist/utils/selection.js +1 -1
  567. package/dist/utils/styles.js +1 -1
  568. package/dist/utils/tree.js +1 -1
  569. package/dist/utils/warnings.js +1 -1
  570. package/dist/version.js +2 -2
  571. package/docs/CreateComponent.md +1 -1
  572. package/docs/FieldProperties.md +17 -13
  573. package/docs/Usage.md +17 -33
  574. package/docs/components/form/Field.md +2 -2
  575. package/docs/components/form/Form.md +12 -72
  576. package/docs/components/form/FormInstance.md +5 -9
  577. package/docs/components/form/ModernForm.md +268 -0
  578. package/docs/modern-form-guide.md +268 -0
  579. package/docs/modern-form-migration.md +18 -101
  580. package/package.json +1 -1
@@ -4,6 +4,8 @@ All input components in UI Kit (`TextInput`, `Select`, `ComboBox`, `Checkbox`, `
4
4
 
5
5
  When used inside a [Form](./components/form/Form.md), these properties are automatically inherited from the form context and can be overridden at the field level.
6
6
 
7
+ For modern forms, follow the [use-case guide](./components/form/ModernForm.md). Put binding and validation options on `form.field(path, options)` and presentation props on the input. The prop reference below also covers `name` bindings for shared controls and legacy forms; these are alternatives to the typed descriptor, not additional required setup.
8
+
7
9
  ## Identity & Form Integration
8
10
 
9
11
  - **`field`** `FormField<Value>` — Typed modern binding created by `form.field(path, options)`. Supports nested paths and takes precedence over `form` and `name`. Built-in bindings accept `null` and `undefined` alongside their normal model value; display fallbacks do not replace stored nulls.
@@ -72,7 +74,7 @@ When used inside a [Form](./components/form/Form.md), these properties are autom
72
74
  - **`validationDelay`** `number` — Debounce delay in milliseconds before running validation.
73
75
  - **`deps`** `readonly unknown[]` — Modern validator inputs captured from outside the form. Compared with `Object.is`; changes invalidate prior validation.
74
76
  - **`dependsOn`** `readonly FormPath[]` — Modern form paths that trigger revalidation, including conditional reads. Validator reads only cancel in-flight work.
75
- - **`rulesKey`** `string` — Manual modern rules revision. Skips automatic rule comparison; update when any rule changes.
77
+ - **`rulesKey`** `string` — Manual modern function revision. Skips validator/transform source comparison; declarative constraints are always compared. Update it when a function or its captures change.
76
78
  - **`errorPolicy`** `'first' | 'all'` — Modern rule error collection policy, inherited from the controller by default.
77
79
  - **`showValid`** `boolean` — Whether to show the valid state icon after successful validation.
78
80
  - **`errorMessage`** `ReactNode` — Error message always displayed in danger state, regardless of validation state.
@@ -94,38 +96,40 @@ The `rules` prop accepts an array of rule objects. Built-in validators include:
94
96
  - **`enum`** `any[]` — Value must be one of the allowed values.
95
97
  - **`whitespace`** `boolean` — Value must contain non-whitespace characters.
96
98
  - **`message`** `string` — Custom error message for the rule.
97
- - **`validator`** `(rule, value) => Promise<string | void>` — Custom async validation function.
99
+ - **`validator`** `(rule, value, context) => result` — Custom rule function. In modern forms, return an error or throw/reject to fail; `undefined`, `null`, and an empty string succeed. The context provides `signal`, `name`, `getValue`, and `getValues`. Prefer descriptor `validate(value, context)` for an ordinary custom check with an inferred value type. Legacy validators retain their existing contract.
98
100
 
99
- ```jsx
101
+ ```tsx
100
102
  <TextInput
101
- name="email"
103
+ field={form.field('email', {
104
+ rules: [{ type: 'email', message: 'Enter a valid email' }],
105
+ })}
102
106
  label="Email Address"
103
107
  isRequired
104
- rules={[
105
- { required: true, message: 'Email is required' },
106
- { type: 'email', message: 'Enter a valid email' },
107
- ]}
108
108
  />
109
109
  ```
110
110
 
111
111
  ## Usage Example
112
112
 
113
- ```jsx
113
+ ```tsx
114
114
  import { Form, TextInput, Select } from '@cube-dev/ui-kit';
115
115
 
116
116
  function ExampleForm() {
117
+ const form = Form.useController<{
118
+ name: string;
119
+ role: 'admin' | 'member' | null;
120
+ }>({ defaultValues: { name: '', role: null } });
121
+
117
122
  return (
118
- <Form defaultValues={{ name: '', role: undefined }}>
123
+ <Form form={form}>
119
124
  <TextInput
120
- name="name"
125
+ field={form.field('name', { rules: [{ min: 2 }] })}
121
126
  label="Full Name"
122
127
  description="As it appears on your ID"
123
128
  isRequired
124
- rules={[{ required: true, min: 2 }]}
125
129
  />
126
130
 
127
131
  <Select
128
- name="role"
132
+ field={form.field('role')}
129
133
  label="Role"
130
134
  tooltip="Your primary role in the organization"
131
135
  necessityIndicator="label"
package/docs/Usage.md CHANGED
@@ -456,46 +456,30 @@ DataTable also accepts nested column definitions for already-shaped pivot result
456
456
 
457
457
  ## Form System
458
458
 
459
- ### Form Component
459
+ ### Modern forms
460
460
 
461
- `<Form>` wraps a native `<form>` and provides validation context:
461
+ For a new modern form, create a typed controller, put defaults on the controller, and bind inputs with descriptors:
462
462
 
463
- ```jsx
464
- const [form] = useForm();
465
-
466
- <Form form={form} onSubmit={(data) => save(data)}>
467
- <TextInput name="email" label="Email" rules={[{ required: true }, { type: 'email' }]} />
468
- <SubmitButton>Save</SubmitButton>
463
+ ```tsx
464
+ const form = Form.useController<{ email: string | null }>({
465
+ defaultValues: { email: null },
466
+ });
467
+
468
+ <Form form={form} onSubmit={(values, { signal }) => save(values, signal)}>
469
+ <TextInput field={form.field('email')} label="Email" isRequired />
470
+ <Form.SubmitError />
471
+ <Form.Submit>Save</Form.Submit>
469
472
  </Form>
470
473
  ```
471
474
 
472
- ### useForm Hook
473
-
474
- `Form.useController()` is the explicit modern alternative. Its creator does not subscribe; use `Form.useSelector(controller, selector, { isEqual })` or `<Form.Subscribe>` for reactive reads, and `Form.useControllerContext()` for descendant access. Named UI Kit inputs bind to modern controllers through commit-time registration and per-field subscriptions. Custom controls use `useFieldProps`; `Form.Item` remains legacy-only. Modern rules support cancellation, delayed validation, and ReactNode errors. Root callbacks and `Form.Submit`, `Form.Reset`, and `Form.SubmitError` use the modern pipeline; native action forms keep browser submission. Known keys and nested tuple commands infer their value types; dynamic paths stay supported. See the [Form documentation](./components/form/Form.md) for scope, defaults, and SSR contracts, and the [migration checklist](https://github.com/cube-js/cube-ui-kit/blob/main/docs/modern-form-migration.md) before converting an existing form.
475
+ Inputs subscribe to their own values and errors. For other reactive UI, use `Form.useValue(form, path)` for one value, `Form.useFieldState(form, path)` for field metadata, or a selector for derived state. `<Form.Subscribe>` keeps an inline region's subscription separate from its parent. Keep imperative getters in handlers and effects.
475
476
 
476
- For new modern forms, prefer `<TextInput field={form.field('email', { validate, deps })} />`; descriptors check names and value types and support nested tuple paths. Built-in bindings accept nullable model values without replacing stored `null` with display fallbacks; declare `null` in the model when it can come from the API. `Form.useValue(form, path)` and `Form.useFieldState(form, path)` provide narrow reactive reads; date-control values retain their methods and types. Hook callbacks stay fresh after commit; defaults change through explicit commands. Declare sibling validation dependencies with `dependsOn` and external captures with `deps`; reads only cancel stale in-flight work. Modern Submit stays enabled after validation errors by default. Both action buttons honor `onClick` cancellation; `state.canReset` exposes reset availability. Submission failures are discriminated by `status`, and explicit-controller action/error helpers work in external footers. `<Form submitValues="all">` includes retained values while continuing to validate active fields.
477
+ [Modern Form](./components/form/ModernForm.md) explains which API to choose for server data, nullable values, nested fields, conditional sections, cross-field and remote validation, errors, and external actions. Use that guide for implementation recipes and the [migration checklist](https://github.com/cube-js/cube-ui-kit/blob/main/docs/modern-form-migration.md) when converting an existing form.
477
478
 
478
- Returns a `CubeFormInstance` with:
479
+ ### Legacy forms
479
480
 
480
- - **Get/Set:** `getFieldValue`, `setFieldValue`, `getFieldsValue`, `setFieldsValue`, `getFormData`
481
- - **Validation:** `validateField`, `validateFields`, `resetFieldsValidation`
482
- - **State queries:** `isFieldValid`, `isFieldInvalid`, `isFieldTouched`, `isValid`, `isDirty`
483
- - **Errors:** `getFieldError`, `setFieldError`
484
-
485
- ### Validation Rules
486
-
487
- Async rule-based system. Each rule is an object with one of these properties:
488
-
489
- | Rule | Description |
490
- | --- | --- |
491
- | `required` | Field must have a value |
492
- | `type` | Type check: `email`, `url`, `number`, `integer`, `date`, `hex`, etc. |
493
- | `pattern` | Regex pattern match |
494
- | `min` / `max` | Length or value constraints |
495
- | `enum` | List of allowed values |
496
- | `whitespace` | Must contain non-whitespace content |
497
- | `validator` | Custom async function: `(rule, value) => Promise<void>` |
481
+ `Form.useForm()` and roots without a modern controller keep the legacy backend. `DialogForm` and `Form.Item` still use this contract. See [Form](./components/form/Form.md) and [FormInstance](./components/form/FormInstance.md) for legacy instance methods, defaults, and dot notation.
498
482
 
499
- ### Field Integration
483
+ ### Shared field integration
500
484
 
501
- Fields with a `name` prop inside `<Form>` automatically register with the form instance — no `<Field>` wrapper needed. The `useFieldProps` hook handles this internally.
485
+ Built-in inputs have field support; they do not need a `Field` wrapper. Modern descriptors and legacy `name` bindings both connect through `useFieldProps`. Custom controls use that hook and `wrapWithField`. [Field Properties](./FieldProperties.md) documents shared labels, validation, state, and presentation props.
@@ -1,12 +1,12 @@
1
1
  # Field
2
2
 
3
- The Field component is a **legacy wrapper** for form inputs that provides field-specific styling and behavior. **In modern usage, all input components have built-in field support**, so you should pass field properties directly to input components instead of using the Field wrapper.
3
+ The Field component is a **legacy wrapper** for form inputs that provides field-specific styling and behavior. Built-in input components already provide field support on both backends, so pass field properties directly to them. For custom controls in a modern controller form, use `useFieldProps` and `wrapWithField` as described in [Modern Form](./ModernForm.md#implement-a-reusable-custom-control); `Field` / `Form.Item` does not support that backend.
4
4
 
5
5
  ## When to Use
6
6
 
7
7
  - **❌ Don't use** for regular input components (TextInput, Select, etc.) - they have built-in field support
8
8
  - **✅ Use only** when wrapping read-only content to make it appear as a form field
9
- - **✅ Use only** when wrapping custom components that don't have built-in field support
9
+ - **✅ Use only** when wrapping custom components in legacy forms that don't have built-in field support
10
10
 
11
11
  ## Component
12
12
 
@@ -2,89 +2,29 @@
2
2
 
3
3
  Forms allow users to enter data that can be submitted while providing alignment and styling for form fields. The Form component provides structure, validation, and state management for user input through a collection of input components with built-in field support.
4
4
 
5
- The form system is inspired by AntD Forms and [rc-field-form](https://field-form-react-component.vercel.app/) with a similar API.
5
+ ## Choose the form API
6
6
 
7
- ## Modern controller and subscriptions (migration preview)
8
-
9
- The [per-form migration guide](https://github.com/cube-js/cube-ui-kit/blob/main/docs/modern-form-migration.md) covers backend selection, rollback, active versus retained values, async defaults, and custom controls. Its [public API examples](https://github.com/cube-js/cube-ui-kit/blob/main/typecheck/consumer/modern-form-examples.tsx) compile against the built package declarations. Existing legacy forms need no API changes when upgrading.
10
-
11
- `Form.useForm()` and forms without an explicit modern controller continue to use the legacy backend described below. `Form.useController<T>()` creates a stable modern controller with immutable snapshots. Defaults and store policy are captured once. Business callbacks update after every committed render without resetting values. Use `reset({ values })`, `setDefaultValues()`, or `adoptDefaultValues()` for later data.
7
+ For new modern forms, follow [Modern Form](./ModernForm.md): typed bindings, loading server data, conditional sections, validation, subscriptions, and submission. The guide recommends one starting point for each case and explains when the alternatives are useful.
12
8
 
13
9
  ```tsx
14
- function AmountPreview() {
15
- const form = Form.useController({ defaultValues: { amount: 10 } });
10
+ function EmailForm() {
11
+ const form = Form.useController<{ email: string | null }>({
12
+ defaultValues: { email: null },
13
+ });
16
14
 
17
15
  return (
18
- <Form form={form}>
19
- <NumberInput name="amount" label="Amount" />
20
- <button type="button" onClick={() => form.setValue('amount', 20)}>
21
- Set amount
22
- </button>
23
- <Form.Subscribe selector={(state) => state.values.amount}>
24
- {(amount) => <output>{String(amount)}</output>}
25
- </Form.Subscribe>
16
+ <Form form={form} onSubmit={(values, { signal }) => save(values, signal)}>
17
+ <TextInput field={form.field('email')} label="Email" isRequired />
18
+ <Form.SubmitError />
19
+ <Form.Submit>Save</Form.Submit>
26
20
  </Form>
27
21
  );
28
22
  }
29
23
  ```
30
24
 
31
- The creator does not subscribe its owner. `Form.useSelector(form, selector, { isEqual })` subscribes the calling component; `Form.Subscribe` subscribes only its render-prop subtree. Equality defaults to `Object.is`. Selectors and equality functions must be pure. Use an `isEqual` function when returning a fresh object and equivalent results should retain their identity. Controller, selector, and equality changes are supported without stale subscriptions.
32
-
33
- `Form.Subscribe` accepts `form`, `selector`, optional `isEqual`, and a `children(selected)` render function. Omit `form` to use the surrounding modern root; an explicit controller takes precedence, while explicit `form={undefined}` detaches and reports a missing-controller error. `Form.useControllerContext<T>()` reads a modern root explicitly. These context APIs reject legacy roots, missing roots, and `FormScopeMask`; an explicit modern controller can still be used outside a root.
34
-
35
- Use selectors for render-time state. `getValue`, `getValues`, `getActiveValues`, `getFieldSnapshot`, and `getSnapshot` are imperative reads; `subscribe` supports imperative observers. `values` contains retained data and `activeValues` contains registered fields. Commands include `setValue`, `setValues`, `batch`, `touch`, the defaults/reset commands, and explicit field/submit error setters. String paths are literal names; tuples such as `['rows', 0, 'amount']` address nested data. `setValue` accepts `{ source, touch, notify, validate }`; programmatic changes do not touch or notify `onValuesChange` unless requested, while user changes do both by default. The committed `onValuesChange(values, change)` callback receives retained values and `{ names, source, kind }`.
36
-
37
- Named UI Kit inputs bind to the modern controller automatically; `<TextInput name="email" form={form} />` also works outside a root. Inputs subscribe only to their own value, errors, and validation status. Custom controls use `useFieldProps` and `wrapWithField`; `Form.Item` stays legacy-only. Controller values and defaults win over field defaults, including explicit `undefined` and `null`. Duplicate fields share a value but receive unique accessible ids. Groups register once and keep their options detached.
38
-
39
- `getValue` and `setValue` infer value types for known literal keys, nested tuples, and array indices without enumerating every path in the model. Misspelled literal paths are rejected; widened dynamic paths remain supported; strings containing dots remain literal keys. Use an explicit `Form.useController<Model>()` model when defaults are partial or narrower than the intended values. `FormValueAtPath<Model, Path>` exports the same lookup type. The modern declaration surface requires TypeScript 5.4 or newer.
40
-
41
- Removing a field removes it from `activeValues` immediately and retains its value by default. Use `preserve={false}` to remove its retained value after cleanup; the baseline remains available to reset. Changing a name or controller releases the old registration. Explicit `form={undefined}` detaches an input. `Form.Submit`, `Form.Reset`, and `Form.SubmitError` subscribe to modern state. Modern roots reject `defaultValues`; seed the creator or use a defaults command. Legacy wrappers such as `DialogForm` keep legacy-only types.
42
-
43
- ### Typed fields and focused reads
44
-
45
- Prefer typed descriptors for new modern forms. `form.field(path, options)` is pure configuration: it does not read current values, register a field, or subscribe the owner. Inputs register after commit and infer their allowed value type from `FieldBaseProps<Value>`. A descriptor takes precedence over `form`/`name`; only options it supplies override matching input options. Put `rules` and `validate` together on the descriptor: supplying either replaces input-level `rules`, while a descriptor with neither preserves them. Keep presentation such as labels and `isRequired` on the input. Existing `name` bindings remain available for legacy-compatible controls.
46
-
47
- Typed built-in field bindings accept `null` and `undefined` alongside their normal model value, so nullable API responses can be used directly. Display normalization does not change the stored value: a switch displays `null` as unchecked and a text input displays it as empty, while the form retains `null` until an edit or explicit command changes it. Controls keep their existing change payloads (for example, switches emit booleans), and reset restores nullable defaults. Declare nullable fields in the model so validators and value selectors also include `null`.
48
-
49
- ```tsx
50
- const form = Form.useController<Profile>({
51
- defaultValues: initialProfile,
52
- onSubmit: (values, { signal }) => save(accountId, values, signal),
53
- });
54
-
55
- <TextInput field={form.field(['profile', 'name'])} label="Name" />;
56
- <TextInput
57
- field={form.field('email', {
58
- deps: [organizationId],
59
- validate: (value, { signal }) => checkEmail(organizationId, value, signal),
60
- })}
61
- label="Email"
62
- />;
63
- ```
64
-
65
- `validate(value, context)` infers the field value and checked paths in `context.getValue(path)`. Use `deps` for external inputs, compared by `Object.is`, and `dependsOn` for form paths that should trigger revalidation. Declare conditional reads too: `dependsOn: ['password']` reruns confirmation validation when the password changes, even if the previous run stopped at an empty confirmation. Each run reads one captured snapshot. Reads through `getValue`/`getValues` cancel in-flight work if those values change, but do not schedule another run; revalidation requires `dependsOn`. Declared dependency changes revalidate previously validated or validating fields unless a value command requests `validate: 'never'`. Rule/dependency changes preserve visible errors while the replacement run is pending. Equivalent inline functions do not restart validation. Function source detects replacements; use `deps` for captures and distinct functions with identical source (including bound/native functions).
66
-
67
- Use `Form.useValue(form, path)` for a reactive value and `Form.useFieldState(form, path)` for typed value/defaults, errors, status, dirty/touched, and active state. Both support nested tuples and subscribe only to their selection; place them in leaf components when the form owner should not rerender. Descendants can get a typed controller with `Form.useControllerContext<Model>()` instead of receiving a prop. State may be `undefined` before a field has registered. Plain objects and arrays have deeply readonly, potentially incomplete read types; use controller commands for writes. Platform values and date-control values (`CalendarDate`, `CalendarDateTime`, `ZonedDateTime`, and `Time`) retain their types and methods.
68
-
69
- ### Modern actions and errors
70
-
71
- `<Form submitValues="all">` includes retained values for native Enter and button submission; the default is `active`. Validation still targets active registrations. Explicit-controller Submit buttons target that controller even in an external footer or another DOM form, preserve native action forms, and submit once. Modern Submit stays enabled while validation errors are visible, so another submission can display feedback; opt into disabling with `disableOnInvalid`. Legacy Submit keeps its existing default. `state.canReset` enables Reset when edits, touched/validation state, or submit errors can be cleared, and is false during submission. Both buttons preserve `onPress`; use `onClick` with `event.preventDefault()` to cancel the action. A controller root's `onReset` runs before reset and can cancel with `preventDefault()`. Reset interception also prevents nested controls from restoring their own mount-time defaults, including when reset is cancelled; `onResetCapture` is reserved for this interception. Native `action` forms retain browser reset behavior.
72
-
73
- Root business callbacks override hook callbacks while mounted. Omitted or undefined root callbacks restore the latest committed hook callback. Changing defaults remains an explicit command. Unmounting the owning root cancels pending submission. Use one owning root per controller; duplicate roots report a development error and the newest binding wins.
74
-
75
- `onSubmitFailed` receives `{ status: 'invalid', errors }` for validation failures and `{ status: 'failed', error }` for submission exceptions. `<Form.SubmitError form={form} renderError={error => ...} />` supports external placement and application-specific formatting. Omit `renderError` for the existing safe generic fallback.
76
-
77
- ### Modern validation and submission
78
-
79
- Use `rules`, `isRequired`, `validateTrigger`, and `validationDelay` on named inputs. Modern validators receive `(rule, value, { name, signal, getValue, getValues })` and return an error message (including a ReactNode), or throw/reject; `undefined`, `null`, and an empty string mean success. The abort signal lets a validator cancel its own network work. Superseded validation settles with `stale: true` even if a validator ignores the signal, and late results cannot replace current errors.
80
-
81
- `form.validate()` validates active fields immediately; `form.validate(['email'])` selects literal names and `form.validate([['users', 0, 'email']])` selects a nested path. `{ immediate: false }` honors field delays. `form.blur(name)` touches the field and runs an on-blur rule. No-rule fields become valid synchronously. The form is valid only when at least one field is active and every active field is valid. Existing errors stay visible during revalidation; an edit that does not revalidate clears them. `setValue` and `setValues` accept `validate: 'auto' | 'always' | 'never'`: auto revalidates on-change fields or fields showing errors. Once an on-blur field becomes valid, subsequent edits await its next blur.
82
-
83
- `errorPolicy: 'first' | 'all'` controls rule-order errors (default `first`), on the creator or individual field. Equivalent inline rules do not restart validation: primitive constraints, RegExp source/flags, and function source form the signature; messages and function identity do not. Use `deps` for external captured inputs. `rulesKey` opts into manual versioning, skipping automatic rule comparison; update it when any rule changes. The latest updated duplicate registration owns its rules and trigger.
84
-
85
- `form.submit()` validates and submits `activeValues`; `form.submit({ include: 'all' })` includes retained values deliberately. `onSubmit(values, { include, signal })` may return a promise. Concurrent submissions return `{ status: 'ignored', reason: 'submitting' }`; other results are `submitted`, `invalid` with an error map, `failed` with an error, or `stale` after cancellation. Validation failures call `onSubmitFailed({ status: 'invalid', errors })` without setting `submitError`; submission failures call it with `{ status: 'failed', error }` and set the error. Submit start and reset clear `submitError`; ordinary edits keep it. Explicit error commands remain available. A modern root without `action` prevents navigation and routes submission to the controller. A native `action`/`method` form preserves browser submission and bypasses the controller pipeline.
25
+ `Form.useForm()` and roots without a modern controller keep the legacy backend. Existing forms need no API changes when upgrading. Use the [migration checklist](https://github.com/cube-js/cube-ui-kit/blob/main/docs/modern-form-migration.md) before converting one; `DialogForm` and `Form.Item` still require legacy forms.
86
26
 
87
- For SSR, seed the controller with the same serializable `defaultValues` on server and client. Server rendering and initial hydration select the cached creation snapshot; after hydration, subscribers catch up to current client state. Prepare server data before creating the controller. Each mount owns a separate controller, and subscriptions clean up on unmount; Strict Mode effect replay does not dispose live controllers.
27
+ **The reference and examples below describe the legacy backend.** Its instance methods, root `defaultValues`, and dot-separated paths do not apply to modern controllers. Shared layout and field presentation props work with both backends. See [Modern Form](./ModernForm.md) for modern defaults and commands.
88
28
 
89
29
  ## When to Use
90
30
 
@@ -1,4 +1,6 @@
1
- # FormInstance
1
+ # FormInstance (legacy)
2
+
3
+ This page describes `Form.useForm()` and `CubeFormInstance`. New modern forms use `Form.useController<Model>()`; see [Modern Form](./ModernForm.md) for its commands and recipes. The methods and dot notation below are legacy-only.
2
4
 
3
5
  The `CubeFormInstance` is the core form management class that provides programmatic control over form state, validation, and data handling. It serves as the central API for interacting with form fields, managing validation states, and handling form submission workflows.
4
6
 
@@ -16,13 +18,7 @@ function MyComponent() {
16
18
  }
17
19
  ```
18
20
 
19
- Alternatively, you can create an instance directly:
20
-
21
- ```tsx
22
- import { CubeFormInstance } from '@cube-dev/ui-kit';
23
-
24
- const formInstance = new CubeFormInstance();
25
- ```
21
+ `CubeFormInstance` is exported as a type for wrapper props and references. Use the hook to create a React form; the package does not export its constructor as a runtime API.
26
22
 
27
23
  ## Field Management
28
24
 
@@ -295,7 +291,7 @@ type CubeFieldData<Name extends string, Value> = {
295
291
 
296
292
  ## Best Practices
297
293
 
298
- 1. **Always use the `useForm` hook** in React components rather than creating instances manually
294
+ 1. **For legacy forms, use the `useForm` hook** in React components rather than creating instances manually
299
295
  2. **Handle async validation errors** appropriately using try-catch blocks
300
296
  3. **Set initial values early** in the component lifecycle to avoid field state inconsistencies
301
297
  4. **Use dot notation** for nested object structures instead of managing complex object hierarchies manually
@@ -0,0 +1,268 @@
1
+ # Modern Form: choose the API for the job
2
+
3
+ For a new modern form, start with `Form.useController<Model>()`, bind inputs with `field={form.field(path)}`, and submit through `<Form onSubmit={...}>` and `<Form.Submit>`. Add subscriptions only where other UI needs to read form state. The input components already subscribe to their own values and errors.
4
+
5
+ Existing `Form.useForm()` forms and roots without a modern controller use the legacy backend. Follow the [migration checklist](https://github.com/cube-js/cube-ui-kit/blob/main/docs/modern-form-migration.md) when converting one. `DialogForm` still requires a legacy instance; do not pass a modern controller through a cast.
6
+
7
+ Recipes: [API choices](#pick-one-binding-and-one-owner-for-each-concern), [reactive UI](#read-a-value-show-status-or-reveal-a-section), [server data](#load-server-data-refresh-defaults-or-discard-edits), [programmatic edits](#edit-values-from-an-event-handler), [validation](#validate-simple-rules-sibling-fields-or-an-api-response), [conditional fields and wizards](#hide-fields-use-nested-data-or-build-a-wizard), [submission](#submit-display-server-errors-and-reset), and [custom controls](#implement-a-reusable-custom-control).
8
+
9
+ ## Start with an ordinary edit form
10
+
11
+ ```tsx
12
+ import { Form, Switch, TextInput } from '@cube-dev/ui-kit';
13
+ import type { FormValues } from '@cube-dev/ui-kit';
14
+
15
+ interface Profile {
16
+ email: string | null;
17
+ notifications: boolean | null;
18
+ }
19
+
20
+ function ProfileForm({
21
+ initialProfile,
22
+ save,
23
+ }: {
24
+ initialProfile: Profile;
25
+ save: (values: FormValues<Profile>, signal: AbortSignal) => Promise<void>;
26
+ }) {
27
+ const form = Form.useController<Profile>({ defaultValues: initialProfile });
28
+
29
+ return (
30
+ <Form form={form} onSubmit={(values, { signal }) => save(values, signal)}>
31
+ <TextInput
32
+ field={form.field('email', {
33
+ rules: [{ type: 'email', message: 'Enter a valid email' }],
34
+ })}
35
+ label="Email"
36
+ isRequired
37
+ />
38
+ <Switch field={form.field('notifications')} label="Notifications" />
39
+ <Form.SubmitError />
40
+ <Form.Submit>Save</Form.Submit>
41
+ <Form.Reset>Reset</Form.Reset>
42
+ </Form>
43
+ );
44
+ }
45
+ ```
46
+
47
+ The model describes possible values, including API `null`s. A text input displays `null` as empty and a switch displays it as unchecked; neither writes that display fallback into the form. Editing uses the control's normal change payload, and reset restores the nullable default. `FormValues<Model>` describes readonly, potentially incomplete data: registration and validation do not prove that every model property is present. Map to your API's request type explicitly where it requires complete data.
48
+
49
+ `defaultValues` initializes this controller once. A later `initialProfile` prop does not overwrite edits. Use the loading commands below, or remount the form with a record key when switching records should start a new editing session. Modern roots do not accept `defaultValues`.
50
+
51
+ ## Pick one binding and one owner for each concern
52
+
53
+ | Concern | Start here | Use the alternative when… |
54
+ | --- | --- | --- |
55
+ | Connect an input | `field={form.field(path, options)}` | `name="email"` keeps a shared legacy/modern wrapper working. Names are not checked against the controller's model. |
56
+ | Locate the controller | Use the controller you created, or pass it as a prop | `Form.useControllerContext<Model>()` avoids prop threading in a descendant. It reads context without subscribing. |
57
+ | Configure a field | Put `rules`, `validate`, dependencies, and retention on the descriptor | Input-level registration props support reusable controls with their own defaults and legacy callers. Avoid configuring the same option in both places. |
58
+ | Present a field | Input props such as `label`, `description`, `isRequired` | `rules: [{ required: true }]` is useful when required validation needs a custom message or no visible required marker. |
59
+ | Handle submit/change/failure | Callbacks on the owning `<Form>` | Hook callbacks let a controller own behavior independently of a root, or provide defaults to a wrapper. Choose one location per callback. |
60
+ | Initialize values | Controller `defaultValues` | Field `defaultValue` supplies a fallback for a reusable field missing from the controller's data. |
61
+
62
+ `Form.Submit`, `Form.Reset`, and `Form.SubmitError` are aliases of the exported `SubmitButton`, `ResetButton`, and `SubmitError` components. This guide uses the `Form.*` names consistently; importing a standalone name does not select a different implementation.
63
+
64
+ A descriptor is pure configuration, so creating it inline is expected. It neither reads state nor registers a field; the mounted input registers after commit. It supplies the controller and path even outside the root, so adding `form` or `name` to the same input is unnecessary. If both are present, the descriptor wins. Descriptor options override only matching options they supply. In particular, descriptor `rules` or `validate` replaces input-level `rules`; put built-in rules and a custom validator together on the descriptor to run both.
65
+
66
+ Controller values and defaults take precedence over field defaults, including explicit `null` and `undefined`. Root callbacks override the corresponding hook callback while mounted; omitted or undefined root callbacks fall back to the hook callback. Business callbacks update after every committed render. Defaults, `errorPolicy`, and diagnostic handlers are creation options; update values through commands and override error policy per field when needed.
67
+
68
+ Use one owning root per controller. Omitted `form` props use context; explicitly passing `form={undefined}` detaches an input. Legacy roots and `FormScopeMask` hide the surrounding modern context.
69
+
70
+ ## Read a value, show status, or reveal a section
71
+
72
+ | UI needs | Use | Why it exists |
73
+ | --- | --- | --- |
74
+ | One field's value | `Form.useValue(form, path)` | Checked path and inferred value without writing a selector. |
75
+ | A field's value, errors, or metadata | `Form.useFieldState(form, path)` | Checked path with typed value/default, errors, status, dirty, touched, and active state. |
76
+ | A derived result or form-wide flag | `Form.useSelector(form, selector)` | General selection, such as `state.isDirty` or `state.canReset`. |
77
+ | A small inline region that reacts independently | `<Form.Subscribe form={form} selector={...}>` | Keeps the subscription in that subtree without extracting a component. |
78
+ | A value in an event handler or effect | `form.getValue(path)` / `form.getValues()` | One-time imperative read; it does not subscribe React. |
79
+
80
+ The value and field-state hooks are conveniences over selectors. The choice between a hook and `Subscribe` is where rerenders should happen: hooks rerender their component, while `Subscribe` rerenders its children region. Creating a controller does not subscribe its owner. Prefer a leaf component for reusable reactive UI:
81
+
82
+ ```tsx
83
+ function EmailPreview() {
84
+ const form = Form.useControllerContext<Profile>();
85
+ const email = Form.useValue(form, 'email');
86
+ return <output>{email ?? 'No email set'}</output>;
87
+ }
88
+ ```
89
+
90
+ Use `Subscribe` for a conditional section directly inside the form:
91
+
92
+ ```tsx
93
+ <Form.Subscribe form={form} selector={(state) => state.values.notifications}>
94
+ {(enabled) =>
95
+ enabled ? <TextInput field={form.field('email')} label="Email" /> : null
96
+ }
97
+ </Form.Subscribe>
98
+ ```
99
+
100
+ These are alternative placements of the email input, not an instruction to mount it twice. Pass `form` to `Subscribe` for inferred model types. It can also use modern context when `form` is omitted, but React context cannot infer the ancestor's model. The generic on `useControllerContext<Profile>()` is your assertion that the ancestor uses `Profile`.
101
+
102
+ Selectors and equality functions must be pure. Select a primitive or a stable snapshot branch; allocating a fresh object compares unequal under the default `Object.is`. Supply `isEqual` when such an object should compare by its contents. `useFieldState` can return `undefined` before a path is tracked. Getter reads in JSX will not stay current. Plain objects and arrays in snapshots are deeply readonly and potentially incomplete; use commands for writes. Date-control values retain their methods; treat them and other non-plain values as immutable.
103
+
104
+ ## Load server data, refresh defaults, or discard edits
105
+
106
+ Most forms need only initialization, adoption for incoming data, and reset for a new editing session. The other modes let integrations change the reset baseline independently of user interaction.
107
+
108
+ | Situation | Command | Effect |
109
+ | --- | --- | --- |
110
+ | Data is available before mounting | `Form.useController({ defaultValues })` | Seeds values and the reset baseline once. |
111
+ | A response arrives while the user may be typing | `adoptDefaultValues(response, { when: 'untouched' })` | Replaces the baseline and adopts untouched fields, preserving touched values. This is the default adoption policy. |
112
+ | Refresh fields that still match their previous defaults | `adoptDefaultValues(response, { when: 'clean' })` | Preserves dirty values, including programmatic edits; touched-but-clean fields can refresh. |
113
+ | Discard edits and start from a different record | `reset({ values: response })` | Replaces baseline and values, clears interaction/errors, and cancels pending submission. |
114
+ | Discard edits using the existing baseline | `reset()` / `<Form.Reset>` | Restores defaults and clears interaction/errors. |
115
+ | Change what Reset will restore without changing the draft | `setDefaultValues(response)` | Replaces only the baseline; dirtiness is recomputed against it. |
116
+
117
+ All defaults commands replace the baseline object; omitted keys are removed from it. Adoption also starts from the incoming object, then restores protected paths. It is not a partial patch. Use `setValue` or `setValues` for edits to current data.
118
+
119
+ ### Advanced defaults policies
120
+
121
+ Use these only when the ordinary adoption or reset behavior above does not fit the interaction:
122
+
123
+ | Situation | Command | Effect |
124
+ | --- | --- | --- |
125
+ | Protect both touched and dirty fields | `adoptDefaultValues(response, { when: 'untouched', preserveDirty: true })` | Adds dirty-value protection to the touched check. |
126
+ | Replace values but keep touched state and submission state | `adoptDefaultValues(response, { when: 'always' })` | Replaces values and baseline; invalidates affected field validation. |
127
+ | Replace values and clear field interaction, keeping submission state | `setDefaultValues(response, { currentValues: 'replace' })` | Replaces values and baseline; clears touched/field validation, but does not cancel submission or clear its error. |
128
+
129
+ ### Asynchronous loading
130
+
131
+ For asynchronous loading, protect both user edits and request ordering:
132
+
133
+ ```tsx
134
+ useEffect(() => {
135
+ const request = new AbortController();
136
+ void load(request.signal)
137
+ .then((profile) => {
138
+ if (!request.signal.aborted) {
139
+ setLoadError(undefined);
140
+ form.adoptDefaultValues(profile, { when: 'untouched' });
141
+ }
142
+ })
143
+ .catch((error: unknown) => {
144
+ if (!request.signal.aborted) setLoadError(error);
145
+ });
146
+ return () => request.abort();
147
+ }, [form, load]);
148
+ ```
149
+
150
+ Here `load` is a stable loader for the current record and `setLoadError` is local UI state; import `useEffect` from React. Gate editing on loading if a partially loaded record must never be submitted. When switching records, remount or reset the editing session: adopting an unrelated record while preserving old edits would mix the two.
151
+
152
+ ## Edit values from an event handler
153
+
154
+ Use `setValue(path, value)` for one path and `setValues(partial)` for several top-level keys. Nested objects supplied to `setValues` replace those objects; use tuple paths to update an individual nested leaf. Neither command changes the reset baseline.
155
+
156
+ ```tsx
157
+ <button
158
+ type="button"
159
+ onClick={() => form.setValue('notifications', true, { source: 'user' })}
160
+ >
161
+ Enable notifications
162
+ </button>
163
+ ```
164
+
165
+ `source: 'user'` defaults to touching the field and notifying `onValuesChange` when values change. Programmatic writes default to neither; override `touch` and `notify` explicitly when needed. `validate` defaults to `auto`; use `always` to force validation or `never` to invalidate without revalidating. `onValuesChange(values, change)` receives retained values and `{ names, source, kind }`. Use it for user-edit integrations such as a debounced draft saver; decide separately whether programmatic writes should trigger that saver. Defaults adoption, value replacement, and reset also notify this callback when they report changed paths; filter `change.kind` or `change.source` if only direct edits should be saved.
166
+
167
+ `batch(() => { ... })` combines synchronous commands into one publication. It is useful for several tuple writes; it is not a rollback transaction and must not wrap async work. `subscribe(listener)` is for imperative integrations that need every publication; React UI should use the hooks above and observers must call the returned unsubscribe function.
168
+
169
+ ## Validate simple rules, sibling fields, or an API response
170
+
171
+ | Validation case | Start here |
172
+ | --- | --- |
173
+ | Required field with a visible marker | Input `isRequired`; it adds required validation too. |
174
+ | Email, length, range, pattern, or enum | Descriptor `rules` using the built-in constraints. |
175
+ | Custom domain check | Descriptor `validate(value, context)` for an inferred field value and checked reads. |
176
+ | Several custom rules or existing shared rule objects | `rules: [{ validator(rule, value, context) { ... } }]`; use `ModernValidationRule` for strict modern rule typing. |
177
+ | Validation depends on another form value | `dependsOn: ['password']`, or nested tuples such as `dependsOn: [['account', 'password']]`. |
178
+ | Validation captures props or other external values | `deps: [organizationId, checkName]`. Include changing functions too. |
179
+ | An integration explicitly versions function behavior | `rulesKey: revision`; ordinary forms can leave it out. |
180
+
181
+ `deps` and `dependsOn` deliberately have separate jobs. A string in `deps` is an external value; the same string in `dependsOn` names a form field. Use both when a validator reads both sources. `rulesKey` is an advanced function revision, not another place to list ordinary dependencies.
182
+
183
+ A password confirmation can declare its sibling dependency even when an early return skips the read:
184
+
185
+ ```tsx
186
+ <TextInput
187
+ field={form.field('confirmation', {
188
+ dependsOn: ['password'],
189
+ validate: (value, { getValue }) => {
190
+ if (!value) return;
191
+ return value === getValue('password') ? undefined : 'Passwords must match';
192
+ },
193
+ })}
194
+ label="Confirm password"
195
+ type="password"
196
+ isRequired
197
+ />
198
+ ```
199
+
200
+ This example uses a controller whose model contains `password` and `confirmation`. A declared dependency change revalidates fields that were already validated or validating, unless the write requests `validate: 'never'`. Reads through validator `getValue`/`getValues` use one captured snapshot and cancel in-flight work if that data changes; reads alone do not schedule another run.
201
+
202
+ For a remote check, pass the cancellation signal and declare captured inputs:
203
+
204
+ ```tsx
205
+ <TextInput
206
+ field={form.field('name', {
207
+ deps: [organizationId, checkName],
208
+ validateTrigger: 'onChange',
209
+ validationDelay: 200,
210
+ validate: async (value, { signal }) => {
211
+ if (!value) return;
212
+ const available = await checkName(organizationId, value, signal);
213
+ return available ? undefined : 'Name is already in use';
214
+ },
215
+ })}
216
+ label="Name"
217
+ isRequired
218
+ />
219
+ ```
220
+
221
+ Here the model contains a string `name`, and `checkName` returns `Promise<boolean>`. A validator succeeds by returning `undefined`, `null`, or an empty string. Return a ReactNode error, or throw/reject, to fail. Adapt legacy validators that resolve data objects; those are failures in the modern contract. Superseded results cannot overwrite current errors even if the validator ignores its signal.
222
+
223
+ Automatic validation honors `validateTrigger` and `validationDelay`. An `auto` write revalidates on-change fields and fields already showing errors; otherwise on-blur fields wait for blur. Explicit `form.validate()` and submission validate immediately; `form.validate(['email'])` selects a literal path, and `form.validate([['rows', 0, 'email']])` selects a nested path. Inspect `{ isValid, stale, fields }` before advancing a wizard step. Validation covers active fields only. `errorPolicy: 'first' | 'all'` controls rule-error collection, with `first` as the default.
224
+
225
+ Rule constraints and function source are compared automatically so equivalent inline validators do not restart pending work. Captures require `deps`; different functions with identical source, including bound/native functions, also need an explicit dependency or revision. `rulesKey` skips function-source comparison only; constraints such as `min`, `pattern`, and `required` are still compared. Update the key or dependencies when function behavior changes. `deps` alone retains source comparison.
226
+
227
+ ## Hide fields, use nested data, or build a wizard
228
+
229
+ Unmounting the last input at a path removes it from `activeValues` immediately and retains its draft by default. Remounting restores that draft. Use `field={form.field('details', { preserve: false })}` when leaving a section should discard its current value. Cleanup removes the value, but its default baseline remains available to reset. Visually hiding an input while leaving it mounted does not unregister it.
230
+
231
+ | Payload | How to choose it | Validation |
232
+ | --- | --- | --- |
233
+ | Mounted fields | `<Form>` / `form.submit()` defaults | Active registered fields only. |
234
+ | All retained data, including hidden sections | `<Form submitValues="all">` or `form.submit({ include: 'all' })` | Still only active registered fields. |
235
+
236
+ For a wizard, validate a step before unmounting it and choose `submitValues="all"` if previous steps belong in the final payload. That does not revalidate unmounted steps. If final submission must validate every step against the latest data, keep the relevant inputs mounted or perform whole-payload validation explicitly. A form with no active fields is invalid.
237
+
238
+ Bind nested leaves with tuples: `field={form.field(['rows', index, 'email'])}`. A string such as `'user.email'` is one literal key, not dot notation. Numeric indices and numeric string segments address the same path. Removing an array path does not shift the other indices. Registering a parent object makes its complete value active; register leaf paths when only selected children belong in the active payload. Known literal paths are typechecked; widened dynamic paths are supported. The declaration surface requires TypeScript 5.4 or newer.
239
+
240
+ `getValues()` / `state.values` contains all retained data; `getActiveValues()` / `state.activeValues` contains registered paths. Dirty/touched metadata includes retained fields, while validity concerns active fields.
241
+
242
+ ## Submit, display server errors, and reset
243
+
244
+ Use `<Form.Submit>` for normal submission, including Enter in the form. It handles loading and stays enabled after validation errors so users can request feedback again. `disableOnInvalid` opts into disabling it on invalid state. Use `form.submit()` for a workflow controlled from an event handler; inspect its result (`submitted`, `invalid`, `failed`, `ignored`, or `stale`) before continuing. Choose the payload independently for each call: imperative `submit()` defaults to active values even if the root has `submitValues="all"`.
245
+
246
+ To place actions or errors outside the root, pass the controller:
247
+
248
+ ```tsx
249
+ <Form.Submit form={form}>Save</Form.Submit>
250
+ <Form.Reset form={form}>Reset</Form.Reset>
251
+ <Form.SubmitError form={form} />
252
+ ```
253
+
254
+ An explicit-controller Submit targets that controller's owning form even inside another DOM form. Return or await the request in `onSubmit(values, { signal, include })`; concurrent submissions are ignored. Throwing or rejecting sets `submitError`, which `Form.SubmitError` displays with a safe generic fallback. Supply `renderError` to format application errors. Ordinary edits keep that error; another submit or reset clears it.
255
+
256
+ Use `setFieldErrors('email', ['Email is already registered'])` for a server error attached to an input and `clearFieldErrors('email')` to clear it. `setSubmitError` / `clearSubmitError` manage a form-level failure. `onSubmitFailed` receives `{ status: 'invalid', errors }` for field validation or `{ status: 'failed', error }` for a rejected submit callback; field validation does not set `submitError`.
257
+
258
+ `Form.Reset` is enabled when `state.canReset` is true: edits, touched/validation state, or a submit error can be cleared, and no submission is running. Use that selector for a custom reset UI. Direct `form.reset()` can also cancel an active submission; unmounting the owning root cancels it too. Action buttons preserve `onPress`; use `onClick` and `event.preventDefault()` to cancel their action. Root `onReset` can cancel before reset runs; `onResetCapture` is reserved for internal reset handling.
259
+
260
+ Native forms with `action`/`method` use browser submission and bypass the controller's submit pipeline. Use that path only when the browser should own the request.
261
+
262
+ ## Implement a reusable custom control
263
+
264
+ Use the same field integration as built-in inputs: `FieldBaseProps<Value>`, `useFieldProps`, then `wrapWithField`. Map the control's value/event API and forward the generated id, blur, disabled, read-only, and invalid state to the interactive element. Include `null | undefined` in the accepted model type when empty values are supported and normalize only for display. Do not spread controller props onto a DOM element.
265
+
266
+ The [compiled CustomControl example](https://github.com/cube-js/cube-ui-kit/blob/main/typecheck/consumer/modern-form-examples.tsx) shows the complete pattern. The [component creation guide](https://cube-ui-kit.vercel.app/?path=/docs/getting-started-create-component--docs) explains the shared field wrapper. `Form.Item` / `Field` belongs to the legacy backend; it is not a second way to connect a modern custom input.
267
+
268
+ For SSR, seed the controller with the same serializable defaults on server and client. Initial hydration uses the creation snapshot before subscribers catch up with client state. Each mounted creator owns its controller; no manual disposal is needed.