@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.
- package/dist/_internal/hooks/use-debounced-value.js +1 -1
- package/dist/_internal/hooks/use-deprecation-warning.js +1 -1
- package/dist/_internal/hooks/use-event.js +1 -1
- package/dist/_internal/hooks/use-is-first-render.js +1 -1
- package/dist/_internal/hooks/use-sync-ref.js +1 -1
- package/dist/_internal/hooks/use-timer/timer.js +1 -1
- package/dist/_internal/hooks/use-timer/use-timer.js +1 -1
- package/dist/_internal/hooks/use-warn.js +1 -1
- package/dist/components/Block.js +1 -1
- package/dist/components/CollectionItem.js +1 -1
- package/dist/components/GlobalStyles.js +1 -1
- package/dist/components/GridProvider.js +1 -1
- package/dist/components/HiddenInput.js +1 -1
- package/dist/components/Root.js +1 -1
- package/dist/components/actions/Action/Action.js +1 -1
- package/dist/components/actions/Banner/Banner.js +1 -1
- package/dist/components/actions/Button/Button.d.ts +1 -0
- package/dist/components/actions/Button/Button.js +1 -1
- package/dist/components/actions/ButtonGroup/ButtonGroup.js +1 -1
- package/dist/components/actions/ButtonSplit/ButtonSplit.js +1 -1
- package/dist/components/actions/ButtonSplit/context.js +1 -1
- package/dist/components/actions/CommandMenu/CommandMenu.js +1 -1
- package/dist/components/actions/CommandMenu/styled.js +1 -1
- package/dist/components/actions/ItemAction/ItemAction.js +1 -1
- package/dist/components/actions/ItemActionContext.js +1 -1
- package/dist/components/actions/ItemActionsWrapper.js +1 -1
- package/dist/components/actions/ItemButton/ItemButton.js +1 -1
- package/dist/components/actions/Link/Link.js +1 -1
- package/dist/components/actions/Menu/Menu.js +1 -1
- package/dist/components/actions/Menu/MenuItem.js +1 -1
- package/dist/components/actions/Menu/MenuSection.js +1 -1
- package/dist/components/actions/Menu/MenuTrigger.js +1 -1
- package/dist/components/actions/Menu/SubMenuTrigger.js +1 -1
- package/dist/components/actions/Menu/SubmenuTriggerContext.js +1 -1
- package/dist/components/actions/Menu/context.js +1 -1
- package/dist/components/actions/Menu/styled.js +1 -1
- package/dist/components/actions/actions-run.js +1 -1
- package/dist/components/actions/index.js +1 -1
- package/dist/components/actions/use-action.js +1 -1
- package/dist/components/actions/use-anchored-menu.js +1 -1
- package/dist/components/actions/use-context-menu.js +1 -1
- package/dist/components/content/ActiveZone/ActiveZone.js +1 -1
- package/dist/components/content/Alert/Alert.js +1 -1
- package/dist/components/content/Alert/use-alert.js +1 -1
- package/dist/components/content/Avatar/Avatar.js +1 -1
- package/dist/components/content/Badge/Badge.js +1 -1
- package/dist/components/content/Card/Card.js +1 -1
- package/dist/components/content/Content.js +1 -1
- package/dist/components/content/CopyPasteBlock/CopyPasteBlock.js +1 -1
- package/dist/components/content/CopySnippet/CopySnippet.js +1 -1
- package/dist/components/content/Disclosure/Disclosure.js +1 -1
- package/dist/components/content/Divider.js +1 -1
- package/dist/components/content/Footer.js +1 -1
- package/dist/components/content/Header.js +1 -1
- package/dist/components/content/HotKeys/HotKeys.js +1 -1
- package/dist/components/content/InfoBadge/InfoBadge.js +1 -1
- package/dist/components/content/InlineInput/InlineInput.js +1 -1
- package/dist/components/content/Item/Item.js +1 -1
- package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
- package/dist/components/content/ItemCard/ItemCard.js +1 -1
- package/dist/components/content/Layout/GridLayout.js +1 -1
- package/dist/components/content/Layout/Layout.js +1 -1
- package/dist/components/content/Layout/LayoutBlock.js +1 -1
- package/dist/components/content/Layout/LayoutCenter.js +1 -1
- package/dist/components/content/Layout/LayoutContainer.js +1 -1
- package/dist/components/content/Layout/LayoutContent.js +1 -1
- package/dist/components/content/Layout/LayoutContext.js +1 -1
- package/dist/components/content/Layout/LayoutFlex.js +1 -1
- package/dist/components/content/Layout/LayoutFooter.js +1 -1
- package/dist/components/content/Layout/LayoutGrid.js +1 -1
- package/dist/components/content/Layout/LayoutHeader.js +1 -1
- package/dist/components/content/Layout/LayoutPane.js +1 -1
- package/dist/components/content/Layout/LayoutPanel.js +1 -1
- package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
- package/dist/components/content/Layout/LayoutToolbar.js +1 -1
- package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
- package/dist/components/content/Layout/index.js +1 -1
- package/dist/components/content/Layout/utils.js +1 -1
- package/dist/components/content/Paragraph.js +1 -1
- package/dist/components/content/Placeholder/Placeholder.js +1 -1
- package/dist/components/content/PrismCode/PrismCode.js +1 -1
- package/dist/components/content/PrismCode/prismSetup.js +1 -1
- package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
- package/dist/components/content/Result/Result.js +1 -1
- package/dist/components/content/Skeleton/Skeleton.js +1 -1
- package/dist/components/content/Tag/Tag.js +1 -1
- package/dist/components/content/Text.js +1 -1
- package/dist/components/content/TextItem/TextItem.js +1 -1
- package/dist/components/content/Title.js +1 -1
- package/dist/components/content/Tree/Tree.js +1 -1
- package/dist/components/content/Tree/TreeNode.js +1 -1
- package/dist/components/content/Tree/styled.js +1 -1
- package/dist/components/content/Tree/tree-index.js +1 -1
- package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
- package/dist/components/content/Tree/use-load-data.js +1 -1
- package/dist/components/content/highlightText.js +1 -1
- package/dist/components/content/use-auto-tooltip.js +1 -1
- package/dist/components/data/DataTable/DataTable.js +1 -1
- package/dist/components/data/ItemTable/ItemTable.js +1 -1
- package/dist/components/data/ItemTable/ItemTableBulkBar.js +1 -1
- package/dist/components/data/ItemTable/ItemTableDragPreview.js +1 -1
- package/dist/components/data/ItemTable/ItemTableFooter.js +1 -1
- package/dist/components/data/ItemTable/ItemTableToolbar.js +1 -1
- package/dist/components/data/TableBase/ColumnResizer.js +1 -1
- package/dist/components/data/TableBase/RowCollection.js +1 -1
- package/dist/components/data/TableBase/TableHeaderCell.js +1 -1
- package/dist/components/data/TableBase/TableRow.js +1 -1
- package/dist/components/data/TableBase/TableView.js +1 -1
- package/dist/components/data/TableBase/column-menu.js +1 -1
- package/dist/components/data/TableBase/column-tint.js +1 -1
- package/dist/components/data/TableBase/row-menu.js +1 -1
- package/dist/components/data/TableBase/styled.d.ts +2 -1
- package/dist/components/data/TableBase/styled.js +1 -1
- package/dist/components/data/TableBase/table-tree.js +1 -1
- package/dist/components/data/TableBase/types.js +1 -1
- package/dist/components/data/TableBase/use-cell-selection.d.ts +1 -0
- package/dist/components/data/TableBase/use-cell-selection.js +0 -0
- package/dist/components/data/TableBase/use-column-order.js +1 -1
- package/dist/components/data/TableBase/use-container-width.js +1 -1
- package/dist/components/data/TableBase/use-row-move-animation.js +1 -1
- package/dist/components/data/TableBase/use-scrollability.js +1 -1
- package/dist/components/data/TableBase/use-table-columns.js +1 -1
- package/dist/components/data/TableBase/use-table-search.js +1 -1
- package/dist/components/data/TableBase/use-table-selection.js +1 -1
- package/dist/components/data/TableBase/use-table-sort.js +1 -1
- package/dist/components/data/TableBase/use-table-sorts.js +1 -1
- package/dist/components/data/TableBase/use-table-storage.js +1 -1
- package/dist/components/data/TableBase/use-table-tree-state.js +1 -1
- package/dist/components/fields/Checkbox/Checkbox.js +1 -1
- package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
- package/dist/components/fields/Checkbox/context.js +1 -1
- package/dist/components/fields/ColorInput/ColorInput.js +1 -1
- package/dist/components/fields/ColorPicker/ColorPicker.js +1 -1
- package/dist/components/fields/ColorSwatch/ColorSwatch.js +1 -1
- package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js +1 -1
- package/dist/components/fields/ComboBox/ComboBox.js +1 -1
- package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
- package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
- package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
- package/dist/components/fields/DatePicker/DateInput.js +1 -1
- package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
- package/dist/components/fields/DatePicker/DatePicker.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
- package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
- package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
- package/dist/components/fields/DatePicker/MonthPicker.js +1 -1
- package/dist/components/fields/DatePicker/PeriodPicker.js +1 -1
- package/dist/components/fields/DatePicker/QuarterPicker.js +1 -1
- package/dist/components/fields/DatePicker/TimeInput.js +1 -1
- package/dist/components/fields/DatePicker/WeekPicker.js +1 -1
- package/dist/components/fields/DatePicker/YearPicker.js +1 -1
- package/dist/components/fields/DatePicker/parseDate.js +1 -1
- package/dist/components/fields/DatePicker/period.js +1 -1
- package/dist/components/fields/DatePicker/props.js +1 -1
- package/dist/components/fields/DatePicker/utils.js +1 -1
- package/dist/components/fields/FileInput/FileInput.js +1 -1
- package/dist/components/fields/FilterListBox/FilterListBox.js +1 -1
- package/dist/components/fields/FilterPicker/FilterPicker.js +1 -1
- package/dist/components/fields/Input/Input.js +1 -1
- package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
- package/dist/components/fields/ListBox/ListBox.js +1 -1
- package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
- package/dist/components/fields/ListBoxPopover/index.d.ts +1 -0
- package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
- package/dist/components/fields/ListBoxPopover/useCompositeFocus.d.ts +2 -0
- package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
- package/dist/components/fields/NumberInput/NumberInput.js +1 -1
- package/dist/components/fields/NumberInput/StepButton.js +1 -1
- package/dist/components/fields/PasswordInput/PasswordInput.js +1 -1
- package/dist/components/fields/Picker/Picker.js +1 -1
- package/dist/components/fields/RadioGroup/Radio.js +1 -1
- package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
- package/dist/components/fields/RadioGroup/context.js +1 -1
- package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
- package/dist/components/fields/SearchInput/SearchInput.js +1 -1
- package/dist/components/fields/Select/Select.js +1 -1
- package/dist/components/fields/Slider/Gradation.js +1 -1
- package/dist/components/fields/Slider/HueSlider.js +1 -1
- package/dist/components/fields/Slider/RangeSlider.js +1 -1
- package/dist/components/fields/Slider/Slider.js +1 -1
- package/dist/components/fields/Slider/SliderBase.js +1 -1
- package/dist/components/fields/Slider/SliderThumb.js +1 -1
- package/dist/components/fields/Slider/SliderTrack.js +1 -1
- package/dist/components/fields/Slider/elements.js +1 -1
- package/dist/components/fields/Slider/index.js +1 -1
- package/dist/components/fields/Switch/Switch.js +1 -1
- package/dist/components/fields/TextArea/TextArea.js +1 -1
- package/dist/components/fields/TextInput/TextInput.js +1 -1
- package/dist/components/fields/TextInput/TextInputBase.js +1 -1
- package/dist/components/fields/TextInput/useAutoSizeTextArea.js +1 -1
- package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
- package/dist/components/fields/TriggerActions.js +1 -1
- package/dist/components/fields/color/ColorPanel.js +1 -1
- package/dist/components/fields/color/channels.js +1 -1
- package/dist/components/fields/color/color.js +1 -1
- package/dist/components/fields/color/context.js +1 -1
- package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/dist/components/form/Form/Field.js +1 -1
- package/dist/components/form/Form/Form.js +1 -1
- package/dist/components/form/Form/ModernFormRoot.js +1 -1
- package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
- package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
- package/dist/components/form/Form/SubmitError.js +1 -1
- package/dist/components/form/Form/backend.js +1 -1
- package/dist/components/form/Form/index.js +1 -1
- package/dist/components/form/Form/modern/actions.js +1 -1
- package/dist/components/form/Form/modern/context.d.ts +1 -0
- package/dist/components/form/Form/modern/context.js +1 -1
- package/dist/components/form/Form/modern/controller.js +1 -1
- package/dist/components/form/Form/modern/field-binding.js +2 -2
- package/dist/components/form/Form/modern/field-binding.js.map +1 -1
- package/dist/components/form/Form/modern/field.js +5 -5
- package/dist/components/form/Form/modern/field.js.map +1 -1
- package/dist/components/form/Form/modern/react.js +1 -1
- package/dist/components/form/Form/modern/store.js +3 -3
- package/dist/components/form/Form/modern/store.js.map +1 -1
- package/dist/components/form/Form/modern/types.d.ts +1 -1
- package/dist/components/form/Form/modern/validation.js +3 -3
- package/dist/components/form/Form/modern/validation.js.map +1 -1
- package/dist/components/form/Form/modern/values.js +1 -1
- package/dist/components/form/Form/use-field/use-field-binding.js +1 -1
- package/dist/components/form/Form/use-field/use-field-props.js +1 -1
- package/dist/components/form/Form/use-field/use-field.js +1 -1
- package/dist/components/form/Form/use-form.js +1 -1
- package/dist/components/form/Form/validation.js +1 -1
- package/dist/components/form/Label.js +1 -1
- package/dist/components/form/validation/ValidationIndicator.js +1 -1
- package/dist/components/form/validation/resolve-validation-props.js +1 -1
- package/dist/components/form/validation/use-validation-props.js +1 -1
- package/dist/components/form/wrapper.js +1 -1
- package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
- package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
- package/dist/components/layout/Board/Board.js +1 -1
- package/dist/components/layout/Board/BoardProvider.js +1 -1
- package/dist/components/layout/Board/BoardResponsive.js +1 -1
- package/dist/components/layout/Board/Widget.js +1 -1
- package/dist/components/layout/Board/WidgetHost.js +1 -1
- package/dist/components/layout/Board/board-context.js +1 -1
- package/dist/components/layout/Board/board-store.js +1 -1
- package/dist/components/layout/Board/grid-core/calculate.js +1 -1
- package/dist/components/layout/Board/grid-core/collision-modes.js +1 -1
- package/dist/components/layout/Board/grid-core/collision.js +1 -1
- package/dist/components/layout/Board/grid-core/compactors.js +1 -1
- package/dist/components/layout/Board/grid-core/constraints.js +1 -1
- package/dist/components/layout/Board/grid-core/group-move.js +1 -1
- package/dist/components/layout/Board/grid-core/layout.js +1 -1
- package/dist/components/layout/Board/grid-core/placement.js +1 -1
- package/dist/components/layout/Board/grid-core/sort.js +1 -1
- package/dist/components/layout/Board/index.js +1 -1
- package/dist/components/layout/Board/responsive-utils.js +1 -1
- package/dist/components/layout/Board/use-board-layout.js +1 -1
- package/dist/components/layout/Board/use-board-registry.js +1 -1
- package/dist/components/layout/Board/use-board-select-modifier-key.js +1 -1
- package/dist/components/layout/Board/use-board-selection.js +1 -1
- package/dist/components/layout/Flex.js +1 -1
- package/dist/components/layout/Flow.js +1 -1
- package/dist/components/layout/Grid.js +1 -1
- package/dist/components/layout/Panel.js +1 -1
- package/dist/components/layout/Prefix.js +1 -1
- package/dist/components/layout/ResizablePanel.js +1 -1
- package/dist/components/layout/Space.js +1 -1
- package/dist/components/layout/Suffix.js +1 -1
- package/dist/components/navigation/Pagination/Pagination.js +1 -1
- package/dist/components/navigation/Pagination/use-pagination.js +1 -1
- package/dist/components/navigation/Tabs/DraggableTabList.js +1 -1
- package/dist/components/navigation/Tabs/TabButton.js +1 -1
- package/dist/components/navigation/Tabs/TabDropIndicator.js +1 -1
- package/dist/components/navigation/Tabs/TabPanel.js +1 -1
- package/dist/components/navigation/Tabs/TabPicker.js +1 -1
- package/dist/components/navigation/Tabs/Tabs.js +1 -1
- package/dist/components/navigation/Tabs/TabsAction.js +1 -1
- package/dist/components/navigation/Tabs/TabsContext.js +1 -1
- package/dist/components/navigation/Tabs/popover-placement.js +1 -1
- package/dist/components/navigation/Tabs/styled.js +1 -1
- package/dist/components/navigation/Tabs/types.js +1 -1
- package/dist/components/navigation/Tabs/use-tab-editing.js +1 -1
- package/dist/components/navigation/Tabs/use-tab-indicator.js +1 -1
- package/dist/components/organisms/StatsCard/StatsCard.js +1 -1
- package/dist/components/other/Calendar/Calendar.js +1 -1
- package/dist/components/other/Calendar/CalendarCell.js +1 -1
- package/dist/components/other/Calendar/CalendarGrid.js +1 -1
- package/dist/components/other/Calendar/CalendarHeader.js +1 -1
- package/dist/components/other/Calendar/CalendarPanel.js +1 -1
- package/dist/components/other/Calendar/PeriodCalendar.js +1 -1
- package/dist/components/other/Calendar/PeriodGrid.js +1 -1
- package/dist/components/other/Calendar/RangeCalendar.js +1 -1
- package/dist/components/other/Calendar/styled.js +1 -1
- package/dist/components/other/CubeLogo/CubeLogo.js +1 -1
- package/dist/components/other/NoDataIcon/NoDataIcon.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialogApiProvider.js +1 -1
- package/dist/components/overlays/AlertDialog/AlertDialogZone.js +1 -1
- package/dist/components/overlays/Dialog/Dialog.js +1 -1
- package/dist/components/overlays/Dialog/DialogContainer.js +1 -1
- package/dist/components/overlays/Dialog/DialogForm.js +1 -1
- package/dist/components/overlays/Dialog/DialogTrigger.js +1 -1
- package/dist/components/overlays/Dialog/context.js +1 -1
- package/dist/components/overlays/Dialog/use-dialog-container.js +1 -1
- package/dist/components/overlays/Modal/Modal.d.ts +2 -1
- package/dist/components/overlays/Modal/Modal.js +1 -1
- package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -1
- package/dist/components/overlays/Modal/Overlay.d.ts +1 -0
- package/dist/components/overlays/Modal/Overlay.js +1 -1
- package/dist/components/overlays/Modal/Popover.js +1 -1
- package/dist/components/overlays/Modal/Tray.js +1 -1
- package/dist/components/overlays/Modal/Underlay.js +1 -1
- package/dist/components/overlays/Modal/types.d.ts +1 -0
- package/dist/components/overlays/Notifications/Notification.js +1 -1
- package/dist/components/overlays/Notifications/NotificationAction.js +1 -1
- package/dist/components/overlays/Notifications/NotificationCard.js +1 -1
- package/dist/components/overlays/Notifications/NotificationContext.d.ts +2 -0
- package/dist/components/overlays/Notifications/NotificationContext.js +1 -1
- package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
- package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
- package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
- package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
- package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
- package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
- package/dist/components/overlays/Notifications/index.js +1 -1
- package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
- package/dist/components/overlays/Notifications/use-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
- package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
- package/dist/components/overlays/Toast/ToastItem.js +1 -1
- package/dist/components/overlays/Toast/index.js +1 -1
- package/dist/components/overlays/Toast/useProgressToast.js +1 -1
- package/dist/components/overlays/Toast/useToast.js +1 -1
- package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
- package/dist/components/overlays/Tooltip/context.js +1 -1
- package/dist/components/portal/Portal.js +1 -1
- package/dist/components/portal/PortalProvider.d.ts +2 -0
- package/dist/components/portal/PortalProvider.js +1 -1
- package/dist/components/portal/index.d.ts +1 -0
- package/dist/components/portal/usePortal.js +1 -1
- package/dist/components/shared/DraggableCollection.js +1 -1
- package/dist/components/shared/InvalidIcon.js +1 -1
- package/dist/components/shared/ValidIcon.js +1 -1
- package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
- package/dist/components/status/Spin/Cube.js +1 -1
- package/dist/components/status/Spin/InternalSpinner.js +1 -1
- package/dist/components/status/Spin/Spin.js +1 -1
- package/dist/components/status/Spin/SpinsContainer.js +1 -1
- package/dist/data/item-themes.js +1 -1
- package/dist/data/themes.js +1 -1
- package/dist/eslint-plugin/defaults.generated.js +1 -1
- package/dist/eslint-plugin/index.js +1 -1
- package/dist/eslint-plugin/rules/no-redundant-default-prop.js +1 -1
- package/dist/i18n/I18nProvider.js +1 -1
- package/dist/i18n/createFormatter.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/instance.js +1 -1
- package/dist/i18n/locales/de-DE/uikit.js +1 -1
- package/dist/i18n/locales/en-US/uikit.js +1 -1
- package/dist/i18n/locales/es-ES/uikit.js +1 -1
- package/dist/i18n/locales/es-MX/uikit.js +1 -1
- package/dist/i18n/locales/fr-FR/uikit.js +1 -1
- package/dist/i18n/locales/it-IT/uikit.js +1 -1
- package/dist/i18n/locales/ja-JP/uikit.js +1 -1
- package/dist/i18n/locales/nb-NO/uikit.js +1 -1
- package/dist/i18n/locales/pt-BR/uikit.js +1 -1
- package/dist/i18n/locales/pt-PT/uikit.js +1 -1
- package/dist/i18n/locales/sv-SE/uikit.js +1 -1
- package/dist/i18n/locales/vi-VN/uikit.js +1 -1
- package/dist/i18n/locales.js +1 -1
- package/dist/i18n/useFormatter.js +1 -1
- package/dist/i18n/useI18n.js +1 -1
- package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
- package/dist/icons/AdjustmentsIcon.js +1 -1
- package/dist/icons/AiIcon.js +1 -1
- package/dist/icons/AreaChartIcon.js +1 -1
- package/dist/icons/ArrowNarrowDownIcon.js +1 -1
- package/dist/icons/ArrowNarrowUpIcon.js +1 -1
- package/dist/icons/BackwardIcon.js +1 -1
- package/dist/icons/BarChartIcon.js +1 -1
- package/dist/icons/BellFilledIcon.js +1 -1
- package/dist/icons/BellIcon.js +1 -1
- package/dist/icons/BooleanIcon.js +1 -1
- package/dist/icons/CalendarEditIcon.js +1 -1
- package/dist/icons/CalendarIcon.js +1 -1
- package/dist/icons/CaretDownIcon.js +1 -1
- package/dist/icons/CaretUpIcon.js +1 -1
- package/dist/icons/ChartAreaStackedIcon.js +1 -1
- package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarGroupedIcon.js +1 -1
- package/dist/icons/ChartBarHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarLineIcon.js +1 -1
- package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBoxPlot2Icon.js +1 -1
- package/dist/icons/ChartBoxPlotIcon.js +1 -1
- package/dist/icons/ChartBubbleIcon.js +1 -1
- package/dist/icons/ChartDonut2Icon.js +1 -1
- package/dist/icons/ChartFunnelIcon.js +1 -1
- package/dist/icons/ChartHeatmapIcon.js +1 -1
- package/dist/icons/ChartKPIIcon.js +1 -1
- package/dist/icons/ChartPie2Icon.js +1 -1
- package/dist/icons/ChartScatterIcon.js +1 -1
- package/dist/icons/CheckCircleFilledIcon.js +1 -1
- package/dist/icons/CheckCircleIcon.js +1 -1
- package/dist/icons/CheckIcon.js +1 -1
- package/dist/icons/CircleFilledIcon.js +1 -1
- package/dist/icons/ClearIcon.js +1 -1
- package/dist/icons/CloseCircleFilledIcon.js +1 -1
- package/dist/icons/CloseCircleIcon.js +1 -1
- package/dist/icons/CloseIcon.js +1 -1
- package/dist/icons/CodeIcon.js +1 -1
- package/dist/icons/ColumnTotalIcon.js +1 -1
- package/dist/icons/CopyIcon.js +1 -1
- package/dist/icons/CountIcon.js +1 -1
- package/dist/icons/CubeIcon.js +1 -1
- package/dist/icons/CubePauseIcon.js +1 -1
- package/dist/icons/CubePlayIcon.js +1 -1
- package/dist/icons/CurrencyDollarIcon.js +1 -1
- package/dist/icons/DangerIcon.js +1 -1
- package/dist/icons/DashboardIcon.js +1 -1
- package/dist/icons/DatabaseIcon.js +1 -1
- package/dist/icons/DecimalDecreaseIcon.js +1 -1
- package/dist/icons/DecimalIncreaseIcon.js +1 -1
- package/dist/icons/DirectionIcon.js +1 -1
- package/dist/icons/DonutIcon.js +1 -1
- package/dist/icons/DownIcon.js +1 -1
- package/dist/icons/EditIcon.js +1 -1
- package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
- package/dist/icons/ExclamationCircleIcon.js +1 -1
- package/dist/icons/ExclamationIcon.js +1 -1
- package/dist/icons/EyeIcon.js +1 -1
- package/dist/icons/EyeInvisibleIcon.js +1 -1
- package/dist/icons/FilterIcon.js +1 -1
- package/dist/icons/FolderFilledIcon.js +1 -1
- package/dist/icons/FolderIcon.js +1 -1
- package/dist/icons/FolderOpenFilledIcon.js +1 -1
- package/dist/icons/FolderOpenIcon.js +1 -1
- package/dist/icons/ForwardIcon.js +1 -1
- package/dist/icons/GripVerticalIcon.js +1 -1
- package/dist/icons/HierarchyIcon.js +1 -1
- package/dist/icons/HierarchyOpenIcon.js +1 -1
- package/dist/icons/Icon.js +1 -1
- package/dist/icons/InfoCircleIcon.js +1 -1
- package/dist/icons/InfoIcon.js +1 -1
- package/dist/icons/KeyIcon.js +1 -1
- package/dist/icons/LeftIcon.js +1 -1
- package/dist/icons/LineChartIcon.js +1 -1
- package/dist/icons/LoadingIcon.js +1 -1
- package/dist/icons/LockFilledIcon.js +1 -1
- package/dist/icons/LockIcon.js +1 -1
- package/dist/icons/MoreIcon.js +1 -1
- package/dist/icons/NotAllowedIcon.js +1 -1
- package/dist/icons/Number123Icon.js +1 -1
- package/dist/icons/NumberIcon.js +1 -1
- package/dist/icons/PauseCircleFilledIcon.js +1 -1
- package/dist/icons/PauseCircleIcon.js +1 -1
- package/dist/icons/PauseIcon.js +1 -1
- package/dist/icons/PercentageIcon.js +1 -1
- package/dist/icons/PieChartIcon.js +1 -1
- package/dist/icons/PipetteIcon.js +1 -1
- package/dist/icons/PlayCircleIcon.js +1 -1
- package/dist/icons/PlayIcon.js +1 -1
- package/dist/icons/PlusIcon.js +1 -1
- package/dist/icons/ProgressBarIcon.js +1 -1
- package/dist/icons/ReloadIcon.js +1 -1
- package/dist/icons/ReportIcon.js +1 -1
- package/dist/icons/ReturnIcon.js +1 -1
- package/dist/icons/RightIcon.js +1 -1
- package/dist/icons/RowTotalsIcon.js +1 -1
- package/dist/icons/SchemeIcon.js +1 -1
- package/dist/icons/SearchIcon.js +1 -1
- package/dist/icons/SemanticQueryIcon.js +1 -1
- package/dist/icons/SettingsIcon.js +1 -1
- package/dist/icons/ShieldFilledIcon.js +1 -1
- package/dist/icons/ShieldIcon.js +1 -1
- package/dist/icons/SlashIcon.js +1 -1
- package/dist/icons/SparklesIcon.js +1 -1
- package/dist/icons/SqlIcon.js +1 -1
- package/dist/icons/StatsIcon.js +1 -1
- package/dist/icons/StopIcon.js +1 -1
- package/dist/icons/StringIcon.js +1 -1
- package/dist/icons/SubtotalsIcon.js +1 -1
- package/dist/icons/SwitchIcon.js +1 -1
- package/dist/icons/TableIcon.js +1 -1
- package/dist/icons/ThumbsDownIcon.js +1 -1
- package/dist/icons/ThumbsUpIcon.js +1 -1
- package/dist/icons/ThunderboltCrossedIcon.js +1 -1
- package/dist/icons/ThunderboltFilledIcon.js +1 -1
- package/dist/icons/ThunderboltIcon.js +1 -1
- package/dist/icons/TimeIcon.js +1 -1
- package/dist/icons/TrashIcon.js +1 -1
- package/dist/icons/UnlockIcon.js +1 -1
- package/dist/icons/UpIcon.js +1 -1
- package/dist/icons/UserGroupIcon.js +1 -1
- package/dist/icons/UserIcon.js +1 -1
- package/dist/icons/UserLockIcon.js +1 -1
- package/dist/icons/ViewIcon.js +1 -1
- package/dist/icons/WarningFilledIcon.js +1 -1
- package/dist/icons/WarningIcon.js +1 -1
- package/dist/icons/wrap-icon.js +1 -1
- package/dist/index.js +1 -1
- package/dist/probe/canonicalize.js +1 -1
- package/dist/probe/css.js +1 -1
- package/dist/probe/index.js +1 -1
- package/dist/provider.js +1 -1
- package/dist/providers/TrackingProvider.js +1 -1
- package/dist/providers/navigationAdapter.default.js +1 -1
- package/dist/shared/form.d.ts +1 -1
- package/dist/tokens/all-tokens.js +1 -1
- package/dist/tokens/base.js +1 -1
- package/dist/tokens/color-seed.js +1 -1
- package/dist/tokens/color-theme.js +1 -1
- package/dist/tokens/colors.js +1 -1
- package/dist/tokens/layout.js +1 -1
- package/dist/tokens/lazy-styles.js +1 -1
- package/dist/tokens/legacy-color.js +1 -1
- package/dist/tokens/palette-config.js +1 -1
- package/dist/tokens/palette.js +1 -1
- package/dist/tokens/resolve.js +1 -1
- package/dist/tokens/shadows.js +1 -1
- package/dist/tokens/sizes.js +1 -1
- package/dist/tokens/spacing.js +1 -1
- package/dist/tokens/typography.js +1 -1
- package/dist/utils/ResizeSensor.js +1 -1
- package/dist/utils/colors.js +1 -1
- package/dist/utils/dotize.js +1 -1
- package/dist/utils/is-dev-env.js +1 -1
- package/dist/utils/modules.js +1 -1
- package/dist/utils/promise.js +1 -1
- package/dist/utils/raf.js +1 -1
- package/dist/utils/random.js +1 -1
- package/dist/utils/range.js +1 -1
- package/dist/utils/react/RenderCache.js +1 -1
- package/dist/utils/react/Slots.js +1 -1
- package/dist/utils/react/chain.js +1 -1
- package/dist/utils/react/disabledProps.js +1 -1
- package/dist/utils/react/forwardRefWithGenerics.js +1 -1
- package/dist/utils/react/index.js +1 -1
- package/dist/utils/react/interactions.js +1 -1
- package/dist/utils/react/isTextOnly.js +1 -1
- package/dist/utils/react/mapProps.js +1 -1
- package/dist/utils/react/mergeProps.js +1 -1
- package/dist/utils/react/nullableValue.js +1 -1
- package/dist/utils/react/resolveIcon.js +1 -1
- package/dist/utils/react/sharedStore.js +1 -1
- package/dist/utils/react/useBufferedValue.js +1 -1
- package/dist/utils/react/useCombinedRefs.js +1 -1
- package/dist/utils/react/useControlledFocusVisible.js +1 -1
- package/dist/utils/react/useEventBus.js +1 -1
- package/dist/utils/react/useId.js +1 -1
- package/dist/utils/react/useIsDarwin.js +1 -1
- package/dist/utils/react/useKeySymbols.js +1 -1
- package/dist/utils/react/useLayoutEffect.js +1 -1
- package/dist/utils/react/useLocalStorage.js +1 -1
- package/dist/utils/react/useMergeStyles.js +1 -1
- package/dist/utils/react/usePopoverSync.js +1 -1
- package/dist/utils/react/useQaProps.js +1 -1
- package/dist/utils/react/useScheme.js +1 -1
- package/dist/utils/react/useViewportSize.js +1 -1
- package/dist/utils/react/wrapNodeIfPlain.js +1 -1
- package/dist/utils/selection.js +1 -1
- package/dist/utils/styles.js +1 -1
- package/dist/utils/tree.js +1 -1
- package/dist/utils/warnings.js +1 -1
- package/dist/version.js +2 -2
- package/docs/CreateComponent.md +1 -1
- package/docs/FieldProperties.md +17 -13
- package/docs/Usage.md +17 -33
- package/docs/components/form/Field.md +2 -2
- package/docs/components/form/Form.md +12 -72
- package/docs/components/form/FormInstance.md +5 -9
- package/docs/components/form/ModernForm.md +268 -0
- package/docs/modern-form-guide.md +268 -0
- package/docs/modern-form-migration.md +18 -101
- package/package.json +1 -1
|
@@ -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.
|
|
@@ -23,7 +23,7 @@ The following API mapping describes migration choices; names are not mechanicall
|
|
|
23
23
|
| `const [form] = Form.useForm()` | `const form = Form.useController<T>()` |
|
|
24
24
|
| `form.isDirty` in JSX | `Form.useSelector(form, state => state.isDirty)` |
|
|
25
25
|
| `getFieldValue(name)` / `getFieldsValue()` | Imperative `getValue(path)` / `getValues()` |
|
|
26
|
-
| Read a value during render | `Form.
|
|
26
|
+
| Read a value during render | `Form.useValue(form, path)`; selectors / `Subscribe` for derived or inline UI |
|
|
27
27
|
| `setFieldsValue(values)` | `setValues(values)`; review touch/notification/validation options |
|
|
28
28
|
| `setInitialFieldsValue(values)` | `setDefaultValues(values)` to change the baseline; `adoptDefaultValues` to load data into eligible fields |
|
|
29
29
|
| `resetFields()` | `reset()`; `reset({ values })` replaces baseline and current values |
|
|
@@ -31,108 +31,25 @@ The following API mapping describes migration choices; names are not mechanicall
|
|
|
31
31
|
| `submit()` | `submit()` returns a tagged result such as `submitted`, `invalid`, or `failed` |
|
|
32
32
|
| `Form.Item` wrapping a custom control | `useFieldProps` plus `wrapWithField` inside that control |
|
|
33
33
|
|
|
34
|
-
`DialogForm` and Cloud's `NarrowForm` / `SaveableCard` currently expose legacy instance contracts. Keep their callers legacy until the wrapper itself is migrated and verified. Passing a modern controller through a cast does not migrate the wrapper. `Form.Item`, legacy mutable flags, and the legacy `
|
|
34
|
+
`DialogForm` and Cloud's `NarrowForm` / `SaveableCard` currently expose legacy instance contracts. Keep their callers legacy until the wrapper itself is migrated and verified. Passing a modern controller through a cast does not migrate the wrapper. `Form.Item`, legacy mutable flags, and the legacy `FormContext` instance shape remain compatibility APIs.
|
|
35
35
|
|
|
36
|
-
##
|
|
36
|
+
## Review the behavior changes
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
The [Modern Form guide](modern-form-guide.md) is the reference for implementing forms. Start there for [API choices](modern-form-guide.md#pick-one-binding-and-one-owner-for-each-concern), [reactive reads](modern-form-guide.md#read-a-value-show-status-or-reveal-a-section), [incoming data](modern-form-guide.md#load-server-data-refresh-defaults-or-discard-edits), [validation](modern-form-guide.md#validate-simple-rules-sibling-fields-or-an-api-response), and [submission](modern-form-guide.md#submit-display-server-errors-and-reset). The following differences need particular attention during migration:
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})}
|
|
54
|
-
label="Email"
|
|
55
|
-
/>;
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
`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).
|
|
59
|
-
|
|
60
|
-
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. 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.
|
|
61
|
-
|
|
62
|
-
## Subscribe where the UI reads state
|
|
63
|
-
|
|
64
|
-
Creation does not subscribe the component. A selector subscribes its caller; a `Form.Subscribe` render function subscribes only that subtree. A colocated selector is valid when the whole creator should render on that selection. Otherwise place the selector in a child or use `Subscribe`.
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
<Form.Subscribe form={form} selector={state => state.values.name}>
|
|
68
|
-
{name => <output>{name}</output>}
|
|
69
|
-
</Form.Subscribe>
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Selectors and equality functions must be pure. Select a primitive or a stable snapshot branch. A newly allocated object compares unequal with the default `Object.is`; supply `isEqual` when selecting several values into a fresh object. `Form.useControllerContext<T>()` gives a descendant the controller without subscribing it. The generic describes that root's values; it cannot verify an ancestor's type.
|
|
73
|
-
|
|
74
|
-
A leaf component can get its controller from context without prop threading, while retaining checked paths and inferred values:
|
|
75
|
-
|
|
76
|
-
```tsx
|
|
77
|
-
function EmailPreview() {
|
|
78
|
-
const form = Form.useControllerContext<Profile>();
|
|
79
|
-
const email = Form.useValue(form, 'email');
|
|
80
|
-
return <output>{email}</output>;
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
`getValue`, `getValues`, `getActiveValues`, `getFieldSnapshot`, and `getSnapshot` are imperative reads for handlers and effects. They do not make JSX reactive. `subscribe(listener)` supports imperative observers and returns an unsubscribe function. `batch(fn)` groups synchronous commands into one publication; it is not a rollback transaction, and the callback must not be async.
|
|
85
|
-
|
|
86
|
-
Omitted `form` props use context. Explicit `form={undefined}` detaches an input. `Form.Subscribe` and `useControllerContext` require modern context; legacy roots and `FormScopeMask` mask it. An explicit modern controller can be used outside a root. Use only one owning root for each controller.
|
|
87
|
-
|
|
88
|
-
## Retained data and active fields
|
|
89
|
-
|
|
90
|
-
| View | Contents | Typical use |
|
|
91
|
-
| --- | --- | --- |
|
|
92
|
-
| `state.values` / `getValues()` | All retained values, including defaults for unmounted fields | Draft previews, autosave, restoring hidden sections |
|
|
93
|
-
| `state.activeValues` / `getActiveValues()` | Values at registered field paths | The default validated submission payload |
|
|
94
|
-
|
|
95
|
-
Hiding a field unregisters it immediately. Its value stays retained by default, so showing it again restores the draft. `preserve={false}` removes that value after cleanup; the default baseline remains, so reset can restore it. An intervening update or Strict Mode reconnection prevents stale cleanup from removing a live value. Removing an array path keeps other indices stable.
|
|
96
|
-
|
|
97
|
-
`submit()` validates active fields and submits active values. Use `submit({ include: 'all' })` only when retained fields belong in the payload; validation still covers active fields only. Registering a parent object includes its complete object; register leaf paths instead when only selected children should be active. A form with no active fields is invalid. Dirty/touched metadata includes retained fields; validity considers active fields.
|
|
98
|
-
|
|
99
|
-
Named UI Kit inputs accept literal string names. Prefer `field={form.field(path)}` for checked field names, inferred validator values, and nested tuple bindings. Controller commands accept the same paths. `'user.email'` is one literal key, while `['user', 'email']` addresses an object. Numeric array indices and numeric string segments address the same path. Known keys and tuples infer values; misspelled literal paths are rejected. Widened string/tuple paths remain dynamic; open `Record` models retain typed values. Declare an explicit model with `Form.useController<Model>()` when defaults omit fields or contain values narrower than the intended model. The declaration surface requires TypeScript 5.4 or newer.
|
|
100
|
-
|
|
101
|
-
```tsx
|
|
102
|
-
form.setValue('name', 'New name');
|
|
103
|
-
form.setValue(['rows', 0, 'email'], 'person@example.com');
|
|
104
|
-
// Static keys and tuple leaves reject values of the wrong type.
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Snapshots own copies of plain objects and arrays. Public `FormValues<T>` / `FormReadValue<T>` types reflect readonly, potentially incomplete nested data. Treat dates, files, other non-plain objects, and error payloads as immutable. Defaults and values on the controller take precedence over field defaults, including explicit null and undefined. Reusing a mutated input object does not replace its previously captured snapshot; send a new object.
|
|
108
|
-
|
|
109
|
-
## Load defaults without erasing edits
|
|
110
|
-
|
|
111
|
-
Use `adoptDefaultValues(response, { when: 'untouched' })` for a response that may arrive after typing. It replaces the baseline and adopts values at eligible paths, preserving touched edits. `when: 'clean'` protects dirty fields, while `when: 'always'` deliberately replaces them. Abort or ignore obsolete requests; the complete `AsyncDefaults` example demonstrates both request cleanup and a stale-response guard.
|
|
112
|
-
|
|
113
|
-
Use `setDefaultValues(response)` when only the baseline should change. `{ currentValues: 'replace' }` replaces current values too. `reset({ values: response })` replaces baseline and values and clears interaction, validation, and submission error state. Defaults commands replace the baseline object, so omitted keys are removed from it.
|
|
114
|
-
|
|
115
|
-
Programmatic writes do not touch fields or invoke `onValuesChange` unless requested. User writes do both by default. Review `{ source, touch, notify, validate }` for each imperative write. `onValuesChange` receives retained values and metadata describing the changed paths/source/kind.
|
|
116
|
-
|
|
117
|
-
## Validation, custom controls, and submission
|
|
118
|
-
|
|
119
|
-
Built-in named inputs register after commit and select only their value, errors, and validation status. Custom controls call `useFieldProps`, map their event/value API, then give the resolved props to `wrapWithField`. Forward the generated id, blur, disabled, read-only, and invalid state to the actual control; do not spread a controller onto a DOM element. The `CustomControl` example is typechecked against the public API.
|
|
120
|
-
|
|
121
|
-
For modern custom validators, return an error (including a ReactNode), or throw/reject it. Return undefined, null, or an empty string on success. A legacy validator that resolves a data object must be adapted: a modern validator treats that result as an error. Use `ModernValidationRule` to check authored modern rules strictly; shared input props remain permissive enough for existing legacy rules. Legacy forms keep their existing validator behavior.
|
|
122
|
-
|
|
123
|
-
Validators receive `{ signal, name, getValue, getValues }` as the third argument. Pass the signal to network requests. Superseded work settles as stale even if the validator ignores cancellation. List external captured inputs in `deps` (for example, `deps: [organizationId, checkEmail]`). Use `dependsOn` for field-triggered revalidation; read tracking only cancels in-flight work. Rule constraints and function source are compared automatically. `rulesKey` opts into manual versioning and skips that comparison; update it when any rule changes. Prefer `deps` for ordinary captured inputs, including string IDs: strings in `deps` are values, while strings in `dependsOn` are field paths.
|
|
124
|
-
|
|
125
|
-
`validationDelay` coalesces automatic validation; explicit validation and submission run immediately by default. Auto writes revalidate on-change fields and fields already showing errors. On-blur fields otherwise wait for blur. `errorPolicy` chooses first/all rule errors. Errors remain visible while revalidating and clear on nonvalidating edits.
|
|
126
|
-
|
|
127
|
-
Root `onSubmit` receives the selected payload and an abort signal; `onSubmitFailed` receives `{ status: 'invalid', errors }` or `{ status: 'failed', error }`. Concurrent submits are ignored. Reset and owning-root release cancel pending submission. Submit start and reset clear `submitError`; ordinary edits keep it. `Form.Submit`, `Form.Reset`, and `Form.SubmitError` subscribe to the modern state. Native `action`/`method` forms continue browser navigation and bypass this pipeline.
|
|
128
|
-
|
|
129
|
-
## Modern actions and errors
|
|
130
|
-
|
|
131
|
-
`<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.
|
|
132
|
-
|
|
133
|
-
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.
|
|
134
|
-
|
|
135
|
-
`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.
|
|
40
|
+
| Area | Migration decision |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| Field bindings and paths | Prefer `field={form.field(path, options)}`. Strings are literal keys; convert legacy dot notation to tuples for nested data. Do not configure the same binding through `field`, `name`, and `form`. |
|
|
43
|
+
| Empty API values | Include `null` in the model where the API returns it. Built-in typed bindings display an empty state without rewriting the stored null. |
|
|
44
|
+
| Render-time reads | Use `useValue`, `useFieldState`, or selectors. Imperative getters and the controller creator do not subscribe React. |
|
|
45
|
+
| Late defaults | Defaults initialize once. Choose adoption to preserve edits, reset for a new editing session, or baseline-only updates deliberately. |
|
|
46
|
+
| Programmatic writes | `setValue` / `setValues` do not touch or invoke `onValuesChange` by default. Review `source`, `touch`, `notify`, and `validate` options. |
|
|
47
|
+
| Validator result | `undefined`, `null`, and an empty string succeed. Return an error or throw/reject to fail. Adapt validators that resolve a data object. |
|
|
48
|
+
| Validator dependencies | `deps` contains external captures; `dependsOn` contains form paths for revalidation. Reads only cancel stale in-flight work. Ordinary validators do not need `rulesKey`. |
|
|
49
|
+
| Hidden fields and payload | Unmounted fields retain drafts by default but leave the default active submission payload. `submitValues="all"` includes retained values and still validates only active fields. |
|
|
50
|
+
| Actions | Modern Submit remains enabled after errors by default. Opt into `disableOnInvalid` if required. Reset follows `state.canReset`, which includes touched/validation/error state. |
|
|
51
|
+
| Errors and cancellation | `onSubmitFailed` distinguishes `invalid` from `failed`. Reset and root unmount cancel submission; ordinary edits retain submit errors. |
|
|
52
|
+
| Custom controls | Use `useFieldProps` and `wrapWithField`; `Form.Item` remains legacy-only. |
|
|
136
53
|
|
|
137
54
|
## Per-form migration checklist
|
|
138
55
|
|
|
@@ -142,7 +59,7 @@ Root business callbacks override hook callbacks while mounted. Omitted or undefi
|
|
|
142
59
|
4. Replace render-time getters and flags with narrow selectors or `Subscribe`. Update custom controls through `useFieldProps`.
|
|
143
60
|
5. Adapt validators' success values and cancellation. Declare external captured inputs in `deps` and sibling form paths in `dependsOn`.
|
|
144
61
|
6. Decide whether hidden fields are retained and whether submission uses active or all values. Verify the actual payload with conditional sections both visible and hidden.
|
|
145
|
-
7. Test required/async errors, double submit, server failure, reset, unmount during requests, keyboard focus, and navigation guards. Confirm unaffected fields and the creator do not rerender on each keystroke.
|
|
62
|
+
7. Test required/async errors, double submit, server failure, reset, unmount during requests, keyboard focus, and navigation guards. Modern Submit stays enabled after validation errors; pass `disableOnInvalid` to retain the legacy disabled-button behavior. Verify this visible change with QA. Confirm unaffected fields and the creator do not rerender on each keystroke.
|
|
146
63
|
8. Run source and built-consumer type checks, the frozen legacy contract suite, React 18/19 compiler checks, and relevant browser checks. Review visual changes before merging.
|
|
147
64
|
|
|
148
65
|
To revert a migrated form, render the preserved legacy component again and restore its legacy defaults/callback/validator contracts. Remount the boundary and deliberately transfer serializable draft values if needed. Do not cast the modern controller to a legacy instance or toggle hook implementations in place.
|