@cube-dev/ui-kit 0.169.1 → 0.171.0
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/README.md +1 -1
- package/dist/CHANGELOG.md +38 -0
- package/dist/README.md +1 -1
- package/dist/_internal/hooks/use-chained-callback.js +1 -1
- 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 +5 -5
- package/dist/components/GlobalStyles.js.map +1 -1
- package/dist/components/GridProvider.js +1 -1
- package/dist/components/HiddenInput.js +1 -1
- package/dist/components/Root.js +3 -5
- package/dist/components/Root.js.map +1 -1
- package/dist/components/actions/Action/Action.js +1 -1
- package/dist/components/actions/Banner/Banner.js +1 -1
- package/dist/components/actions/Banner/Banner.js.map +1 -1
- package/dist/components/actions/Button/Button.d.ts +0 -1
- 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/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/Menu/styled.js.map +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 +2 -2
- package/dist/components/data/TableBase/column-tint.js.map +1 -1
- package/dist/components/data/TableBase/row-menu.js +1 -1
- package/dist/components/data/TableBase/styled.d.ts +1 -2
- 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.d.ts +3 -3
- package/dist/components/data/TableBase/types.js +1 -1
- package/dist/components/data/TableBase/types.js.map +1 -1
- package/dist/components/data/TableBase/use-cell-selection.d.ts +0 -1
- 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/Checkbox.js.map +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 +2 -2
- package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js.map +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 +0 -1
- package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
- 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/Select/Select.js.map +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/color/ColorPanel.js +1 -1
- package/dist/components/fields/color/channels.js +1 -1
- package/dist/components/fields/color/color.js +2 -2
- package/dist/components/fields/color/color.js.map +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/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/index.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.d.ts +6 -4
- package/dist/components/layout/Board/Board.js +2 -1
- package/dist/components/layout/Board/Board.js.map +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 +42 -7
- package/dist/components/layout/Board/WidgetHost.js.map +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 +75 -7
- package/dist/components/layout/Board/grid-core/collision-modes.js.map +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 +95 -88
- package/dist/components/layout/Board/use-board-registry.js.map +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.d.ts +2 -2
- package/dist/components/other/CubeLogo/CubeLogo.js +12 -12
- package/dist/components/other/CubeLogo/CubeLogo.js.map +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 +1 -2
- 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 +0 -1
- 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 +0 -1
- 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 +0 -2
- 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/Tooltip.js.map +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.js +1 -1
- package/dist/components/portal/index.d.ts +0 -1
- 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/item-themes.js.map +1 -1
- package/dist/data/themes.js +1 -1
- package/dist/data/themes.js.map +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.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +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/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.d.ts +2 -2
- package/dist/tokens/color-theme.js +2 -2
- package/dist/tokens/color-theme.js.map +1 -1
- package/dist/tokens/colors.d.ts +3 -3
- package/dist/tokens/colors.js +4 -4
- package/dist/tokens/colors.js.map +1 -1
- package/dist/tokens/layout.js +1 -1
- package/dist/tokens/lazy-styles.js +1 -1
- package/dist/tokens/palette-config.d.ts +1 -1
- package/dist/tokens/palette-config.js +1 -1
- package/dist/tokens/palette-config.js.map +1 -1
- package/dist/tokens/palette.d.ts +5 -5
- package/dist/tokens/palette.js +11 -11
- package/dist/tokens/palette.js.map +1 -1
- package/dist/tokens/resolve.d.ts +1 -1
- package/dist/tokens/resolve.js +12 -31
- package/dist/tokens/resolve.js.map +1 -1
- package/dist/tokens/shadows.d.ts +1 -1
- package/dist/tokens/shadows.js +2 -2
- package/dist/tokens/shadows.js.map +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/index.d.ts +1 -0
- 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.d.ts +1 -0
- package/dist/utils/react/index.js +2 -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/useSchema.d.ts +58 -0
- package/dist/utils/react/useSchema.js +182 -0
- package/dist/utils/react/useSchema.js.map +1 -0
- 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/Colors.md +2 -2
- package/docs/Introduction.md +1 -1
- package/docs/Theming.md +29 -12
- package/docs/Usage.md +28 -11
- package/docs/components/content/ItemCard.md +1 -1
- package/docs/components/content/PrismCode.md +2 -2
- package/docs/components/data/DataTable.md +1 -1
- package/docs/components/fields/Picker.md +1 -1
- package/docs/components/fields/RadioGroup.md +28 -8
- package/docs/components/layout/Board.md +149 -38
- package/docs/components/navigation/Tabs.md +1 -1
- package/docs/components/organisms/StatsCard.md +1 -1
- package/docs/components/other/CubeLogo.md +9 -9
- package/docs/components/overlays/Tooltip.md +2 -2
- package/docs/components/overlays/TooltipProvider.md +1 -1
- package/package.json +2 -2
- package/dist/components/fields/ListBoxPopover/useCompositeFocus.d.ts +0 -2
- package/dist/components/portal/PortalProvider.d.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetHost.js","names":["mergeProps"],"sources":["../../../../src/components/layout/Board/WidgetHost.tsx"],"sourcesContent":["import { Styles, tasty } from '@tenphi/tasty';\nimport { CSSProperties, ReactNode, useMemo, useRef, useState } from 'react';\nimport { useFocusRing, useFocusWithin, useHover, useMove } from 'react-aria';\nimport { createPortal } from 'react-dom';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useI18n } from '../../../i18n';\nimport { mergeProps } from '../../../utils/react';\n\nimport {\n BoardDragState,\n BoardHost,\n BoardHostContext,\n BoardRegistryContextValue,\n ViewportRect,\n} from './board-context';\nimport { WidgetRegistration } from './board-store';\nimport {\n calcGridColWidth,\n calcGridItemPosition,\n LayoutItem,\n PositionParams,\n ResizeHandleAxis,\n} from './grid-core';\nimport { BoardSelectModifierKey } from './use-board-select-modifier-key';\n\nimport type { BoardCornerPlacement, BoardResizeGripPlacement } from './Widget';\n\nexport type ResizePhase = 'start' | 'move' | 'end';\n\n/**\n * Slack (px) absorbed when converting an auto-height widget's content height to\n * whole rows, so sub-pixel measurement/rounding noise never bumps an extra row.\n */\nconst AUTO_HEIGHT_TOLERANCE = 4;\n\n/**\n * Corner grip size in px, and therefore how far a `corner`-placed grip hangs\n * outside the widget: exactly half of it, since it is centred on the corner. The\n * hit-zone reads the same number so what you see is what you can grab.\n */\nconst GRIP_SIZE = 10;\n\nconst WidgetElement = tasty({\n qa: 'BoardWidget',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n // Widgets always carry a `#surface-2` fill and rounded corners. The `card`\n // modifier (board-level `widgetProps.isCard` or per-widget `isCard`) adds a\n // border on top; a non-card widget is borderless so nested boards can align\n // their columns flush with the parent grid.\n fill: '#surface-2',\n radius: '1cr',\n // Selection reads as a focus-like state here - it is transient, it follows\n // what the user is working with, and it is dropped the moment they touch\n // something else - so it is drawn as an edge treatment rather than as a\n // fill. `outline` stays reserved for the real focus ring (the kit's\n // convention everywhere), and the two are kept legible side by side by\n // token: selection is a saturated `#primary` ring, focus a `#primary-text`\n // outline sitting one border-width further out (`outlineOffset`).\n // A widget a live marquee currently covers gets the same treatment with the\n // ring dimmed, so releasing the pointer only changes the strength of an edge\n // that is already there — no geometry shift, nothing to re-read. The border\n // is *not* dimmed with it: `#primary-border` is close to `#border` on a dark\n // scheme, so fading it lands below the border a widget already has and the\n // preview would read as weaker than doing nothing.\n border: {\n '': false,\n card: true,\n 'pre-selected': '#primary-border',\n selected: '#primary-border',\n },\n shadow: {\n '': false,\n 'hovered & !card & !no-hover-ring & (draggable | resizing)':\n '0 0 0 1bw #border',\n 'pre-selected': '0 0 0 1bw #primary.40',\n selected: '0 0 0 1bw #primary',\n // `$dialog-shadow` uses Glaze `#shadow-lg`, which adapts to dark / high-contrast schemes.\n 'drag | resizing': '$dialog-shadow',\n },\n outline: {\n '': '1bw #primary-text.0',\n 'focus-visible': '1bw #primary-text',\n },\n outlineOffset: '1bw',\n zIndex: {\n '': 1,\n 'drag | resizing': 10,\n },\n // The pointer-drag ghost (the clone that floats in the overlay) is slightly\n // translucent so the user can see through it to whatever it hovers over -\n // e.g. a Tabs header underneath - and land a precise drop / tab switch. The\n // in-place host (keyboard drags, which never float) stays fully opaque.\n opacity: {\n '': 1,\n floating: 0.8,\n },\n // Reflowing widgets animate their position and size. The actively\n // dragged/resized element - and the floating overlay clone - must track the\n // pointer with no lag, so they drop geometry from the list. Geometry is also\n // dropped until the board reports `settled`: on init widgets jump to their\n // first measured positions, and without this gate they would slide/grow in\n // from their default box. The board lifts the gate after the first\n // positioned paint so subsequent reflows animate normally.\n transition: {\n '': 'theme, shadow, opacity',\n settled: 'theme, shadow, opacity, inset, width, height',\n 'drag | floating | resizing': 'theme, shadow, opacity',\n },\n boxSizing: 'border-box',\n userSelect: {\n '': 'auto',\n 'drag | resizing': 'none',\n },\n cursor: {\n '': 'auto',\n draggable: 'grab',\n drag: 'grabbing',\n },\n touchAction: 'none',\n // A widget owns its grid cell and must not paint outside it: a nested board\n // with more rows than currently fit, a mid-drag reflow (an auto-height\n // container deliberately cannot grow while a drag is in flight), or a long\n // unbreakable string would otherwise spill over its neighbours. Clipping\n // holds regardless of `isCard` — a borderless widget has no drawn edge, but\n // it still has a cell.\n //\n // The cost is that a descendant's `outline` is cropped at the edge, since an\n // outline is clipped by an *ancestor's* overflow rather than its own. A\n // widget whose content needs to paint outside — a control drawing its own\n // active ring — opts out with `overflow=\"visible\"`, or draws the ring inset\n // with a negative `outlineOffset`.\n overflow: 'hidden',\n },\n});\n\nconst HandleElement = tasty({\n qa: 'BoardResizeHandle',\n styles: {\n position: 'absolute',\n zIndex: 20,\n fill: '#clear',\n // The corner hit-zone is drawn inside the grip layer, which takes no pointer\n // events; `pointer-events` inherits, so it has to opt back in. Inside the\n // widget this is what it already got from the default.\n pointerEvents: 'auto',\n // Overhang: how far the hit-zone extends beyond the widget edge. A\n // `corner`-placed grip hangs out by half its own size, and the hit-zone\n // matches it exactly - a visible grip you cannot grab is worse than no grip.\n '--handle-size': '3x',\n '--handle-overhang': {\n '': '-8px',\n 'placement=corner': `${-GRIP_SIZE / 2}px`,\n },\n '--handle-inset': '1x',\n width: {\n '': '$handle-size',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'auto',\n },\n height: {\n '': '$handle-size',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'auto',\n },\n top: {\n '': 'auto',\n '[data-axis=\"n\"] | [data-axis=\"ne\"] | [data-axis=\"nw\"]':\n '$handle-overhang',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': '$handle-inset',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"s\"] | [data-axis=\"se\"] | [data-axis=\"sw\"]':\n '$handle-overhang',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': '$handle-inset',\n },\n left: {\n '': 'auto',\n '[data-axis=\"w\"] | [data-axis=\"nw\"] | [data-axis=\"sw\"]':\n '$handle-overhang',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '$handle-inset',\n },\n right: {\n '': 'auto',\n '[data-axis=\"e\"] | [data-axis=\"ne\"] | [data-axis=\"se\"]':\n '$handle-overhang',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '$handle-inset',\n },\n cursor: {\n '': 'default',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'ns-resize',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'ew-resize',\n '[data-axis=\"ne\"] | [data-axis=\"sw\"]': 'nesw-resize',\n '[data-axis=\"nw\"] | [data-axis=\"se\"]': 'nwse-resize',\n },\n touchAction: 'none',\n },\n});\n\nconst GripElement = tasty({\n qa: 'BoardResizeGrip',\n styles: {\n position: 'absolute',\n // Both placements derive from one number, so the grip can never drift out of\n // step with its own size: `inside` tucks it into the widget box, `corner`\n // centres it on the widget's corner - exactly half its own size back from\n // each edge. Consumers pick between them with `resizeGripPlacement` instead\n // of re-deriving these offsets from the outside.\n '--grip-size': `${GRIP_SIZE}px`,\n '--grip-inset': '4px',\n '--grip-offset': {\n '': '$grip-inset',\n 'placement=corner': '($grip-size / -2)',\n },\n width: '$grip-size',\n height: '$grip-size',\n boxSizing: 'border-box',\n pointerEvents: 'none',\n opacity: {\n '': 0,\n revealed: 1,\n },\n transition: 'opacity 120ms ease-in-out',\n borderTop: {\n '': '0',\n '[data-axis=\"ne\"] | [data-axis=\"nw\"]': '2px solid #dark.40',\n },\n borderBottom: {\n '': '0',\n '[data-axis=\"se\"] | [data-axis=\"sw\"]': '2px solid #dark.40',\n },\n borderLeft: {\n '': '0',\n '[data-axis=\"nw\"] | [data-axis=\"sw\"]': '2px solid #dark.40',\n },\n borderRight: {\n '': '0',\n '[data-axis=\"ne\"] | [data-axis=\"se\"]': '2px solid #dark.40',\n },\n radius: {\n '': '0',\n '[data-axis=\"se\"]': '4px bottom-right',\n '[data-axis=\"sw\"]': '4px bottom-left',\n '[data-axis=\"ne\"]': '4px top-right',\n '[data-axis=\"nw\"]': '4px top-left',\n },\n top: {\n '': 'auto',\n '[data-axis=\"ne\"] | [data-axis=\"nw\"]': '$grip-offset',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"se\"] | [data-axis=\"sw\"]': '$grip-offset',\n },\n left: {\n '': 'auto',\n '[data-axis=\"nw\"] | [data-axis=\"sw\"]': '$grip-offset',\n },\n right: {\n '': 'auto',\n '[data-axis=\"ne\"] | [data-axis=\"se\"]': '$grip-offset',\n },\n },\n});\n\n/**\n * Where the corner grips are drawn when `resizeGripPlacement` is `'corner'`.\n *\n * `WidgetElement` clips its children (`overflow: hidden`, and that clipping is\n * load-bearing - see its own note), so a grip centred on the widget's corner\n * would be cut in half if it stayed inside. This layer mirrors the widget's grid\n * rect as a *sibling* of it, clips nothing, and never takes pointer events: the\n * transparent `HandleElement` inside the widget still owns the gesture, so\n * escaping the clip costs no hit-testing behaviour.\n *\n * It sits above a resting widget (`zIndex: 1`) so a grip is never hidden by the\n * neighbour it overhangs, and below a dragged or resized one (`zIndex: 10`) so a\n * lifted widget still paints over its neighbours' grips. The board's own content\n * box still clips it, so a grip on a widget flush against the board edge needs\n * `containerPadding` >= half the grip size to show in full.\n */\nconst GripLayerElement = tasty({\n qa: 'BoardResizeGripLayer',\n styles: {\n position: 'absolute',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: 5,\n },\n});\n\n/**\n * A control anchored to one corner of a widget, centred on it.\n *\n * Lives in the same layer as the corner resize grips, which is the layer that\n * exists precisely because a widget clips its own content: a control an app\n * hangs off the corner itself is cropped in half by that clip, or by an\n * ancestor's scroll container when the widget sits in the first row. Here it is\n * a sibling of the widget rather than a descendant, so neither can reach it.\n *\n * Being outside the widget host also means `useMove` is not attached, so a press\n * on the chrome cannot start a drag — no `dragCancel` entry required.\n */\nconst CornerChromeElement = tasty({\n qa: 'BoardWidgetCornerChrome',\n styles: {\n position: 'absolute',\n // The layer takes no pointer events; chrome is interactive, so it opts back in.\n pointerEvents: 'auto',\n zIndex: 1,\n top: {\n '': 'auto',\n 'corner=ne | corner=nw': 0,\n },\n bottom: {\n '': 'auto',\n 'corner=se | corner=sw': 0,\n },\n left: {\n '': 'auto',\n 'corner=nw | corner=sw': 0,\n },\n right: {\n '': 'auto',\n 'corner=ne | corner=se': 0,\n },\n // Centre it on the corner: half of its own size in each direction. The\n // default matches `ne`, which is also the default placement, so chrome is\n // still centred rather than hanging off-centre if no corner mod matches.\n transform: {\n '': 'translate(50%, -50%)',\n 'corner=nw': 'translate(-50%, -50%)',\n 'corner=se': 'translate(50%, 50%)',\n 'corner=sw': 'translate(-50%, 50%)',\n },\n },\n});\n\n// Edge axes (n/s/e/w) get a dotted grip affordance, revealed on\n// hover/focus/resize. The dots line up along the edge (a vertical column for the\n// e/w handles, a horizontal row for n/s), matching the design-system pane grip\n// (see `Layout.Pane`). Purely visual - the interaction still lives on the\n// transparent `HandleElement` hit-zone above.\nconst EdgeGripElement = tasty({\n qa: 'BoardResizeEdgeGrip',\n styles: {\n position: 'absolute',\n display: 'grid',\n gap: '2bw',\n boxSizing: 'border-box',\n pointerEvents: 'none',\n opacity: {\n '': 0,\n revealed: 1,\n },\n transition: 'opacity 120ms ease-in-out',\n // A column of 5 dots for the vertical edges (e/w), a row of 5 for n/s.\n gridColumns: {\n '': '3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '3px 3px 3px 3px 3px',\n },\n gridRows: {\n '': '3px 3px 3px 3px 3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '3px',\n },\n // Anchor to the relevant edge and center along it.\n top: {\n '': '50%',\n '[data-axis=\"n\"]': '3px',\n '[data-axis=\"s\"]': 'auto',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"s\"]': '3px',\n },\n left: {\n '': 'auto',\n '[data-axis=\"w\"]': '3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '50%',\n },\n right: {\n '': 'auto',\n '[data-axis=\"e\"]': '3px',\n },\n transform: {\n '': 'translate(0, 0)',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'translate(0, -50%)',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'translate(-50%, 0)',\n },\n\n Dot: {\n width: '3px',\n height: '3px',\n radius: 'round',\n fill: {\n '': '#dark-03',\n resizing: '#dark-02',\n },\n },\n },\n});\n\n/** Corner axes get a visible grip affordance on hover/focus/resize. */\nfunction isCornerAxis(axis: ResizeHandleAxis): boolean {\n return axis.length === 2;\n}\n\n/** Edge axes (n/s/e/w) get a dotted grip affordance. */\nfunction isEdgeAxis(axis: ResizeHandleAxis): boolean {\n return axis.length === 1;\n}\n\ninterface ResizeHandleProps {\n axis: ResizeHandleAxis;\n placement: BoardResizeGripPlacement;\n onResize: (\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => void;\n}\n\nfunction ResizeHandle({ axis, placement, onResize }: ResizeHandleProps) {\n const { moveProps } = useMove({\n onMoveStart() {\n onResize(axis, 'start', 0, 0);\n },\n onMove(e) {\n onResize(axis, 'move', e.deltaX, e.deltaY);\n },\n onMoveEnd() {\n onResize(axis, 'end', 0, 0);\n },\n });\n\n const stopProps = {\n onPointerDown: (e: React.PointerEvent) => e.stopPropagation(),\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\n onTouchStart: (e: React.TouchEvent) => e.stopPropagation(),\n };\n\n return (\n <HandleElement\n data-axis={axis}\n mods={{ placement }}\n {...mergeProps(stopProps, moveProps)}\n aria-hidden=\"true\"\n />\n );\n}\n\nexport interface WidgetHostProps {\n boardId: string;\n item: LayoutItem;\n positionParams: PositionParams;\n registration: WidgetRegistration | undefined;\n /**\n * Whether this widget renders with card chrome (fill/border/radius). Resolved\n * by the owning `Board` from the per-widget `isCard` and the board-level\n * `widgetProps.isCard` default.\n */\n isCard: boolean;\n /**\n * Whether this widget draws the resting hover ring. Resolved by the owning\n * `Board` from the per-widget `hoverRing` and the board-level\n * `widgetProps.hoverRing` default.\n */\n hoverRing: boolean;\n /** Corner-anchored chrome, drawn outside the widget's clip. */\n cornerChrome?: ReactNode;\n /** Which corner {@link cornerChrome} is centred on. */\n cornerChromePlacement?: BoardCornerPlacement;\n /** App-defined modifiers merged into the host's own, for style maps to match. */\n mods?: Record<string, boolean | string | undefined>;\n /**\n * Resolved style overrides for the rendered widget element (per-widget\n * `styles` falling back to the board-level `widgetProps.styles`).\n */\n styles?: Styles;\n isDraggable: boolean;\n isResizable: boolean;\n resizeHandles: ResizeHandleAxis[];\n /**\n * Where the corner grips sit. Resolved by the owning `Board` from the\n * per-widget `resizeGripPlacement` and the board-level\n * `widgetProps.resizeGripPlacement` default.\n */\n resizeGripPlacement: BoardResizeGripPlacement;\n /**\n * Whether this widget grows to fit its content. Resolved by the owning\n * `Board` from the per-widget `isAutoHeight` and the board-level\n * `widgetProps.isAutoHeight` default.\n */\n isAutoHeight: boolean;\n /**\n * Test id / accessible name for the rendered widget element. Resolved by the\n * owning `Board` from the per-widget `qa` and the board-level `widgetProps.qa`\n * default; falls back to the layout id.\n */\n qa?: string;\n /**\n * CSS selector for elements that must not start a pointer drag (e.g. form\n * controls inside the widget). A pointer-down whose target matches this\n * selector never begins a drag.\n */\n dragCancel?: string;\n /**\n * CSS selector for the only elements from which a pointer drag may start. A\n * pointer-down outside a matching element never begins a drag.\n */\n dragHandle?: string;\n /**\n * Whether the owning board has settled its widgets' initial positions. While\n * false, the widget does not animate `inset` (left/top) so the first\n * positioned paint isn't seen as a transition. Lifted after the board's first\n * measured render.\n */\n settled?: boolean;\n registry: BoardRegistryContextValue;\n dragState: BoardDragState | null;\n onResize: (\n id: string,\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => void;\n /**\n * Report the minimum number of rows this widget needs to fit its content\n * (typically a nested board). The owning board grows the item to this height\n * when it is taller than the current one, and treats it as the resize floor\n * so the widget cannot be dragged shorter than its content requires.\n */\n onAutoHeight: (id: string, neededRows: number) => void;\n /**\n * Notify the owning board of a drag gesture's lifecycle so it can emit the\n * public drag callbacks. Fires after the registry has updated drag state.\n */\n onDragLifecycle?: (id: string, phase: ResizePhase) => void;\n /** Whether this widget can be selected (board selection on and not opted out). */\n isSelectable?: boolean;\n isSelected?: boolean;\n /**\n * A live marquee currently covers this widget, so it *will* be selected when\n * the pointer is released. Provisional: it never reaches the selection model,\n * the callbacks or the live region.\n */\n isPreSelected?: boolean;\n /** CSS selector for descendants whose clicks must not change the selection. */\n selectionCancel?: string;\n /** Id of the board-owned node holding the shared \"Selected\" description. */\n selectedHintId?: string;\n /** Apply a selection gesture. `additive` toggles instead of replacing. */\n onSelect?: (id: string, additive: boolean) => void;\n /** Drop the whole selection. Called when the user interacts elsewhere. */\n onSelectionReset?: () => void;\n /** Pointer-event property carrying the platform additive-selection modifier. */\n selectModifierKey?: BoardSelectModifierKey;\n}\n\n/**\n * The positioned, interactive wrapper a board renders for each layout item it\n * owns. Content is pulled from the shared store (by id), so any board can host\n * any widget. Dragging uses React Aria `useMove`; during a drag the widget\n * renders into the shared overlay portal so it can float outside its board.\n */\nexport function WidgetHost(props: WidgetHostProps) {\n const {\n boardId,\n item,\n positionParams,\n registration,\n isCard,\n hoverRing,\n cornerChrome,\n cornerChromePlacement = 'ne',\n mods: customMods,\n styles: widgetStyles,\n isDraggable,\n isResizable,\n resizeHandles,\n resizeGripPlacement,\n isAutoHeight,\n qa,\n dragCancel,\n dragHandle,\n registry,\n dragState,\n settled,\n onResize,\n onAutoHeight,\n onDragLifecycle,\n isSelectable = false,\n isSelected = false,\n isPreSelected = false,\n selectionCancel,\n selectedHintId,\n onSelect,\n onSelectionReset,\n selectModifierKey = 'metaKey',\n } = props;\n\n const { t } = useI18n();\n const ariaLabel = registration?.['aria-label'];\n const hostRef = useRef<HTMLDivElement | null>(null);\n const isActiveDrag = dragState?.itemId === item.i;\n // Every member of a group drag floats, not just the grabbed one — otherwise\n // the rest sit motionless while their placeholders move, which reads as\n // broken. Only the grabbed host owns a live `useMove` gesture, so hiding the\n // others is trivially safe.\n const isDragMember = !!dragState?.itemIds.includes(item.i);\n\n // Translate a nested board's reported height deficit (signed px: positive when\n // it is squeezed, negative when it has slack) into the absolute number of rows\n // this widget needs, and report it to the owning board. The widget's chrome\n // cancels out: the needed pixel height is the widget's current pixel height\n // plus the deficit. A small tolerance keeps sub-pixel rounding from bumping an\n // extra row. Skipped during a drag (the widget is floating in the overlay).\n const requestHeightDeficit = useEvent((deficitPx: number) => {\n if (!isAutoHeight || isActiveDrag) return;\n const step = positionParams.rowHeight + positionParams.margin[1];\n if (step <= 0) return;\n const current = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n const neededPx = current.height + deficitPx;\n const neededRows = Math.max(\n 1,\n Math.ceil(\n (neededPx + positionParams.margin[1] - AUTO_HEIGHT_TOLERANCE) / step,\n ),\n );\n onAutoHeight(item.i, neededRows);\n });\n\n const hostValue = useMemo<BoardHost>(\n () => ({ isAutoHeight, requestHeightDeficit }),\n [isAutoHeight, requestHeightDeficit],\n );\n // Keyboard drags stay in place: moving the focused element into the overlay\n // portal would unmount it and stop arrow-key move events.\n const useOverlay = isActiveDrag && dragState?.pointerType !== 'keyboard';\n\n const [isResizing, setIsResizing] = useState(false);\n const [isFocusWithin, setIsFocusWithin] = useState(false);\n const { hoverProps, isHovered } = useHover({ isDisabled: isActiveDrag });\n // A `corner` grip and its hit-zone live outside the widget box, so hovering the\n // half that hangs out is not hovering the widget. Without this the grip fades\n // away exactly as the pointer arrives on it - the affordance retreats from the\n // gesture it is inviting.\n const { hoverProps: layerHoverProps, isHovered: isLayerHovered } = useHover({\n isDisabled: isActiveDrag,\n });\n const { focusProps, isFocusVisible } = useFocusRing();\n const { focusWithinProps } = useFocusWithin({\n onFocusWithinChange: setIsFocusWithin,\n });\n\n // Reveal the resize grips when the widget is interacted with (but not while it\n // is being dragged, where the widget floats in the overlay).\n const gripsRevealed =\n isResizable &&\n !item.static &&\n !isActiveDrag &&\n (isHovered || isLayerHovered || isFocusWithin || isResizing);\n\n const { moveProps } = useMove({\n onMoveStart(e) {\n if (!isDraggable) return;\n const rect = hostRef.current?.getBoundingClientRect();\n const pos = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n const vr: ViewportRect = rect\n ? {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n : {\n left: pos.left,\n top: pos.top,\n width: pos.width,\n height: pos.height,\n };\n registry.onDragStart(boardId, item.i, vr, e.pointerType, hostRef.current);\n onDragLifecycle?.(item.i, 'start');\n },\n onMove(e) {\n if (!isDraggable) return;\n if (e.pointerType === 'keyboard') {\n // Amplify arrow-key steps to a full grid cell so items actually move.\n const colWidth = calcGridColWidth(positionParams);\n const stepX = colWidth + positionParams.margin[0];\n const stepY = positionParams.rowHeight + positionParams.margin[1];\n registry.onDragMove(\n Math.sign(e.deltaX) * stepX,\n Math.sign(e.deltaY) * stepY,\n e.pointerType,\n );\n onDragLifecycle?.(item.i, 'move');\n return;\n }\n registry.onDragMove(e.deltaX, e.deltaY, e.pointerType);\n onDragLifecycle?.(item.i, 'move');\n },\n onMoveEnd() {\n if (!isDraggable) return;\n registry.onDragEnd();\n onDragLifecycle?.(item.i, 'end');\n },\n });\n\n // `role=\"group\"` is what makes `aria-roledescription` legal here - it is\n // invalid on a role-less `div`, which is what this element used to be. A\n // collection role (`option`, `gridcell`, ...) would be the only way to carry a\n // real `aria-selected`, but those require presentational children and a\n // widget hosts arbitrary interactive content, so selection is conveyed by the\n // board's live region plus the shared description below instead.\n const a11yProps = {\n role: 'group',\n tabIndex: isDraggable || isSelectable ? 0 : undefined,\n 'aria-roledescription': isDraggable\n ? t('board.draggableWidget', 'Draggable widget')\n : t('board.widget', 'Widget'),\n 'aria-label': ariaLabel ?? qa ?? item.i,\n 'aria-describedby': isSelected ? selectedHintId : undefined,\n 'aria-keyshortcuts': isSelectable ? 'Space' : undefined,\n };\n\n // True from the moment a real move begins until the click that ends the\n // gesture has been swallowed. `useMove` binds only pointerdown/keydown, never\n // click, so a click handler composes with it cleanly - but the click that\n // *terminates* a drag would otherwise land as a selection. Event order is\n // pointerdown -> onMove* -> pointerup -> onMoveEnd -> click, so this ref is\n // always accurate by the time the click arrives. More reliable than a pixel\n // threshold, which has to guess.\n const isInteractiveTarget = (target: EventTarget | null) => {\n const el = target as HTMLElement | null;\n\n return !!(selectionCancel && el?.closest?.(selectionCancel));\n };\n\n /**\n * Selecting and starting a drag are the *same* gesture: you grab the thing you\n * are about to move. So the press selects immediately and the drag arms behind\n * it — move and it drags, stay still and it was only a selection. This is what\n * every canvas tool does, and it is why there is no ambiguity to resolve with a\n * modifier.\n *\n * - a press on an interactive descendant belongs to that control, so the\n * selection is dropped and the press is left alone;\n * - <kbd>Shift</kbd> or the platform modifier toggles membership;\n * - a press on an unselected widget makes it the selection, so the drag that\n * follows moves exactly what was grabbed;\n * - a press on an already-selected widget changes nothing, so the drag moves\n * the whole group.\n *\n * Runs before the drag handler (see the `mergeProps` order below), so the\n * registry resolves the group against the selection this press just made.\n */\n const handleSelectPointerDown = (e: React.PointerEvent) => {\n if (!isSelectable || !onSelect || e.button !== 0) return;\n\n if (isInteractiveTarget(e.target)) {\n onSelectionReset?.();\n\n return;\n }\n\n // A press this widget owns must never reach an ancestor widget host: in a\n // nested board the outer widget would otherwise select itself on top of the\n // inner selection. This has to cover the already-selected case too, which\n // changes nothing here but is still a press this board handled — and\n // `stopBubbleProps` below only guards draggable widgets.\n e.stopPropagation();\n\n if (e.shiftKey || e[selectModifierKey]) {\n onSelect(item.i, true);\n\n return;\n }\n\n if (!isSelected) {\n onSelect(item.i, false);\n }\n };\n\n const handleSelectKeyDown = (e: React.KeyboardEvent) => {\n // Same guard the arrow keys use: only act when the host itself is focused,\n // so Space inside a nested input or button keeps its meaning.\n if (e.target !== e.currentTarget) return;\n if (!isSelectable || !onSelect) return;\n if (e.key !== ' ' && e.key !== 'Spacebar') return;\n\n // No modifier needed here: focus already says which widget is meant, and\n // Space cannot be mistaken for the start of a drag. Only swallow the key\n // once we know we are acting on it, so a board without selection still\n // scrolls on Space.\n e.preventDefault();\n e.stopPropagation();\n // Space is an explicit selection gesture (a click is also \"interact with\n // this\"), so it toggles - that is the keyboard's way to deselect one widget.\n onSelect(item.i, true);\n };\n\n // When this widget is draggable it owns its gesture, so stop the pointer-down\n // from bubbling to an ancestor widget host (e.g. a container widget hosting a\n // nested board / Tabs). Otherwise the ancestor's `useMove` would start a\n // second drag from the same press and the whole parent widget would move too.\n // Non-draggable widgets let the event bubble so their container stays grabbable\n // through their content.\n const stopBubbleProps = isDraggable\n ? {\n onPointerDown: (e: React.PointerEvent) => e.stopPropagation(),\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\n onTouchStart: (e: React.TouchEvent) => e.stopPropagation(),\n }\n : {};\n\n // Gate a pointer drag by `dragHandle` / `dragCancel` selectors. Returns true\n // when the press must NOT start a drag (outside a `dragHandle`, or matching\n // `dragCancel`).\n const shouldGateDrag = (target: EventTarget | null) => {\n if (!(target instanceof Element)) return false;\n if (dragHandle && !target.closest(dragHandle)) return true;\n if (dragCancel && target.closest(dragCancel)) return true;\n\n // `selectionCancel` already declares which descendants are interactive, and\n // a drag must not start from them either — otherwise `useMove`'s\n // `preventDefault()` on pointer-down swallows the native focus and an input\n // inside a widget cannot be typed into. Only for selectable widgets, so a\n // board that never opted into selection keeps its exact previous behaviour\n // and `dragCancel` stays the only thing that gates a drag there.\n return !!(\n isSelectable &&\n selectionCancel &&\n target.closest(selectionCancel)\n );\n };\n\n // The gate wraps `useMove`'s own pointer-down handlers rather than a separate\n // capture-phase listener. When a press is gated we simply do not forward it to\n // `useMove`, so the drag never begins. This is deliberate: `useMove`'s\n // pointer-down handler calls both `stopPropagation()` and `preventDefault()`.\n // Calling it (or pre-empting it with a capture-phase `stopPropagation()`)\n // would break the very controls `dragCancel` is meant to protect - a\n // `preventDefault()` on pointer-down cancels a native `<input>`'s focus, and a\n // capture-phase `stopPropagation()` swallows a `<button>`'s own press events.\n // Skipping `useMove` entirely leaves the target's default behavior and its own\n // handlers fully intact.\n //\n // Keyboard moves also go through `useMove` (`onKeyDown`). Arrow keys must only\n // move the widget when the host itself is focused — not when focus is inside a\n // nested input, textarea, or other descendant (those events bubble to the host\n // and would otherwise steal caret / list navigation).\n //\n // A non-draggable widget must not carry `moveProps` at all: `useMove`'s\n // pointer-down handler calls `preventDefault()`, which cancels native text\n // selection inside the widget. Read-only boards (`isDraggable={false}`) still\n // need selectable content, so we drop the handlers entirely instead of relying\n // on the early-returns inside the `onMove*` callbacks.\n const gatedMoveProps = !isDraggable\n ? {}\n : {\n ...moveProps,\n ...(moveProps.onPointerDown && {\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n hostRef.current?.focus({ preventScroll: true });\n moveProps.onPointerDown!(e);\n },\n }),\n ...(moveProps.onMouseDown && {\n onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n hostRef.current?.focus({ preventScroll: true });\n moveProps.onMouseDown!(e);\n },\n }),\n ...(moveProps.onTouchStart && {\n onTouchStart: (e: React.TouchEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n moveProps.onTouchStart!(e);\n },\n }),\n ...(moveProps.onKeyDown && {\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.target !== e.currentTarget) return;\n handleSelectKeyDown(e);\n if (e.defaultPrevented) return;\n moveProps.onKeyDown!(e);\n },\n }),\n };\n\n // A non-draggable widget gets no `moveProps` at all, so its Space handling and\n // its focusability have to come from here instead.\n const selectionProps = isSelectable\n ? {\n onPointerDown: handleSelectPointerDown,\n // A draggable widget routes Space through the drag gate below, which\n // already enforces the host-focused rule; a non-draggable one gets no\n // `moveProps` at all and needs its own handler.\n ...(isDraggable ? {} : { onKeyDown: handleSelectKeyDown }),\n }\n : {};\n\n const handleResize = (\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => {\n if (phase === 'start') setIsResizing(true);\n else if (phase === 'end') setIsResizing(false);\n onResize(item.i, axis, phase, dx, dy);\n };\n\n const mods = {\n drag: isActiveDrag,\n draggable: isDraggable && !isActiveDrag,\n static: !!item.static,\n resizing: isResizing,\n card: isCard,\n 'no-hover-ring': !hoverRing,\n hovered: isHovered,\n 'focus-visible': isFocusVisible,\n selected: isSelected,\n // Mutually exclusive with `selected` by construction, so the two never\n // compete for precedence in a style map — and an additive lasso leaves the\n // widgets it already owns looking fully selected rather than downgrading\n // them to a preview.\n 'pre-selected': isPreSelected && !isSelected,\n };\n\n const content = (\n <BoardHostContext.Provider value={hostValue}>\n {registration?.content}\n {isResizable && !item.static ? (\n <>\n {/* A `corner` grip and its hit-zone both move to the sibling\n `GripLayerElement` below, which the widget's own `overflow: hidden`\n cannot clip. They travel together: hoisting only the visual would\n leave the half that hangs outside impossible to grab. */}\n {(resizeGripPlacement === 'corner'\n ? resizeHandles.filter((axis) => !isCornerAxis(axis))\n : resizeHandles\n ).map((axis) => (\n <ResizeHandle\n key={axis}\n axis={axis}\n placement={resizeGripPlacement}\n onResize={handleResize}\n />\n ))}\n {resizeGripPlacement === 'corner'\n ? null\n : resizeHandles\n .filter(isCornerAxis)\n .map((axis) => (\n <GripElement\n key={`grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, placement: 'inside' }}\n aria-hidden=\"true\"\n />\n ))}\n {resizeHandles.filter(isEdgeAxis).map((axis) => (\n <EdgeGripElement\n key={`edge-grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, resizing: isResizing }}\n aria-hidden=\"true\"\n >\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n </EdgeGripElement>\n ))}\n </>\n ) : null}\n </BoardHostContext.Provider>\n );\n\n const pos = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n\n // While dragging with a pointer, the widget's visual floats in the shared\n // overlay so it is never clipped by an ancestor's `overflow: hidden`. The\n // gesture-owning element (the one carrying `moveProps`) must NOT be the node\n // that moves into the overlay: React Aria's `useMove` binds its pointer\n // move/end listeners relative to the node that received `onPointerDown`, and\n // relocating that node into the portal tears it down and mounts a fresh one\n // (inside a `pointerEvents: 'none'` layer), which can drop the in-flight\n // gesture. Instead we keep a stable, always-mounted in-grid host that owns the\n // gesture for its whole lifetime, and portal a separate, non-interactive\n // visual clone into the overlay.\n const overlayNode = registry.overlayRef.current;\n // Non-grabbed group members float too, from their own drag-start rect plus the\n // one shared gesture delta. Measuring them here would be wrong (the board is\n // mid-reflow); the registry measured every member once at drag start, which is\n // the only safe window.\n const memberRect = isDragMember\n ? dragState!.memberRects.get(item.i)\n : undefined;\n const floatInOverlay =\n !!overlayNode &&\n !!dragState &&\n dragState.pointerType !== 'keyboard' &&\n (useOverlay || (isDragMember && !!memberRect));\n\n // Where the floating clone sits. The grabbed widget tracks the live drag rect\n // directly; a member tracks its own start rect offset by the same delta, so\n // the block moves as one.\n const floatRect =\n floatInOverlay && dragState\n ? isActiveDrag || !memberRect\n ? dragState.rect\n : {\n left:\n memberRect.left +\n (dragState.rect.left - dragState.startRect.left),\n top:\n memberRect.top + (dragState.rect.top - dragState.startRect.top),\n width: memberRect.width,\n height: memberRect.height,\n }\n : null;\n\n const hostStyle: CSSProperties = {\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n // Kept mounted but hidden while its clone floats, so the gesture stays live\n // on this node (the pointer listeners never get torn down).\n ...(floatInOverlay ? { opacity: 0, pointerEvents: 'none' } : null),\n };\n\n // The floating clone carries the \"drag\" affordance (raised shadow/z-index);\n // keep the hidden host flat. Keyboard drags (which never float) still\n // highlight the in-grid host, so only suppress `drag` when floating.\n // App mods go UNDER the board's own: a custom mod must never be able to\n // shadow `selected`, `drag` and friends, which the board's own style map and\n // its accessibility wiring both depend on.\n const hostMods = {\n ...customMods,\n ...mods,\n drag: isActiveDrag && !floatInOverlay,\n settled,\n };\n\n // The host is always rendered first, with a stable element shape, so React\n // reuses the same DOM node across the drag transition (never remounts it).\n const host = (\n <WidgetElement\n ref={hostRef}\n // Marks this element as a board widget host so the registry can find the\n // container widget a nested board lives in (used to keep a drag anchored to\n // a nested board while the anchor is still over its host - e.g. the Tabs\n // header above a nested board - instead of reflowing the ancestor board).\n data-board-widget-host=\"\"\n // Which widget, as opposed to \"am I inside a widget host\" - the two are\n // separate questions and the existing attribute is used as a presence\n // selector, so overloading it would make every such selector implicitly\n // value-dependent. Namespaced so it cannot collide with an app's own\n // `data-widget-id`.\n data-board-widget-id={item.i}\n {...mergeProps(\n // Before `gatedMoveProps`: the press selects, and only then does the\n // drag start and read that selection to decide what moves.\n selectionProps,\n gatedMoveProps,\n stopBubbleProps,\n hoverProps,\n focusProps,\n focusWithinProps,\n a11yProps,\n { style: hostStyle },\n )}\n qa={qa}\n mods={hostMods}\n styles={widgetStyles as Styles}\n >\n {floatInOverlay ? null : content}\n </WidgetElement>\n );\n\n const overlayClone = floatInOverlay\n ? createPortal(\n <WidgetElement\n style={{\n position: 'absolute',\n left: `${floatRect!.left}px`,\n top: `${floatRect!.top}px`,\n width: `${floatRect!.width}px`,\n height: `${floatRect!.height}px`,\n pointerEvents: 'none',\n }}\n // `hostMods` rather than `mods`, so the app's own modifiers survive the\n // gesture: the clone IS the widget while a pointer drag is in flight\n // (the in-grid host is hidden), and a custom state blinking off for the\n // duration of the drag is exactly when it would be most noticeable.\n mods={{ ...hostMods, drag: true, floating: true }}\n styles={widgetStyles as Styles}\n aria-hidden=\"true\"\n >\n {content}\n </WidgetElement>,\n overlayNode!,\n )\n : null;\n\n // Corner grips that must straddle the widget edge, hoisted out of the widget's\n // clip (see `GripLayerElement`). Positioned on the same grid rect as the host,\n // so the two stay in step through reflows and auto-height changes.\n const cornerAxes =\n isResizable && !item.static && resizeGripPlacement === 'corner'\n ? resizeHandles.filter(isCornerAxis)\n : [];\n // Suppressed while the widget floats in the drag overlay: the layer mirrors the\n // widget's *grid* rect, so leaving it behind would park a live hit-zone on a\n // cell the widget has visually left.\n // The layer is also what carries corner chrome, so it renders when either the\n // grips or the chrome need it.\n const gripLayer =\n (cornerAxes.length || cornerChrome) && !floatInOverlay ? (\n <GripLayerElement\n {...layerHoverProps}\n style={{\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n }}\n // Only the grips are decorative. Chrome is real, focusable UI, so the\n // layer can only be hidden from assistive tech when it holds no chrome.\n aria-hidden={cornerChrome ? undefined : 'true'}\n >\n {cornerAxes.map((axis) => (\n <ResizeHandle\n key={`handle-${axis}`}\n axis={axis}\n placement=\"corner\"\n onResize={handleResize}\n />\n ))}\n {cornerAxes.map((axis) => (\n <GripElement\n key={`grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, placement: 'corner' }}\n aria-hidden=\"true\"\n />\n ))}\n {cornerChrome ? (\n <CornerChromeElement mods={{ corner: cornerChromePlacement }}>\n {cornerChrome}\n </CornerChromeElement>\n ) : null}\n </GripLayerElement>\n ) : null;\n\n return (\n <>\n {host}\n {gripLayer}\n {overlayClone}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WidgetHost.js","names":["mergeProps"],"sources":["../../../../src/components/layout/Board/WidgetHost.tsx"],"sourcesContent":["import { Styles, tasty } from '@tenphi/tasty';\nimport {\n CSSProperties,\n ReactNode,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useFocusRing, useFocusWithin, useHover, useMove } from 'react-aria';\nimport { createPortal } from 'react-dom';\n\nimport { useEvent } from '../../../_internal/hooks';\nimport { useI18n } from '../../../i18n';\nimport { mergeProps } from '../../../utils/react';\n\nimport {\n BoardDragState,\n BoardHost,\n BoardHostContext,\n BoardRegistryContextValue,\n ViewportRect,\n} from './board-context';\nimport { WidgetRegistration } from './board-store';\nimport {\n calcGridColWidth,\n calcGridItemPosition,\n LayoutItem,\n PositionParams,\n ResizeHandleAxis,\n} from './grid-core';\nimport { BoardSelectModifierKey } from './use-board-select-modifier-key';\n\nimport type { BoardCornerPlacement, BoardResizeGripPlacement } from './Widget';\n\nexport type ResizePhase = 'start' | 'move' | 'end';\n\n/**\n * Slack (px) absorbed when converting an auto-height widget's content height to\n * whole rows, so sub-pixel measurement/rounding noise never bumps an extra row.\n */\nconst AUTO_HEIGHT_TOLERANCE = 4;\n\n/**\n * Corner grip size in px, and therefore how far a `corner`-placed grip hangs\n * outside the widget: exactly half of it, since it is centred on the corner. The\n * hit-zone reads the same number so what you see is what you can grab.\n */\nconst GRIP_SIZE = 10;\n\nconst WidgetElement = tasty({\n qa: 'BoardWidget',\n styles: {\n position: 'absolute',\n top: 0,\n left: 0,\n // Widgets always carry a `#surface-2` fill and rounded corners. The `card`\n // modifier (board-level `widgetProps.isCard` or per-widget `isCard`) adds a\n // border on top; a non-card widget is borderless so nested boards can align\n // their columns flush with the parent grid.\n fill: '#surface-2',\n radius: '1cr',\n // Selection reads as a focus-like state here - it is transient, it follows\n // what the user is working with, and it is dropped the moment they touch\n // something else - so it is drawn as an edge treatment rather than as a\n // fill. `outline` stays reserved for the real focus ring (the kit's\n // convention everywhere), and the two are kept legible side by side by\n // token: selection is a saturated `#primary` ring, focus a `#primary-text`\n // outline sitting one border-width further out (`outlineOffset`).\n // A widget a live marquee currently covers gets the same treatment with the\n // ring dimmed, so releasing the pointer only changes the strength of an edge\n // that is already there — no geometry shift, nothing to re-read. The border\n // is *not* dimmed with it: `#primary-border` is close to `#border` on a dark\n // schema, so fading it lands below the border a widget already has and the\n // preview would read as weaker than doing nothing.\n border: {\n '': false,\n card: true,\n 'pre-selected': '#primary-border',\n selected: '#primary-border',\n },\n shadow: {\n '': false,\n 'hovered & !card & !no-hover-ring & (draggable | resizing)':\n '0 0 0 1bw #border',\n 'pre-selected': '0 0 0 1bw #primary.40',\n selected: '0 0 0 1bw #primary',\n // `$dialog-shadow` uses Glaze `#shadow-lg`, which adapts to dark / high-contrast schemas.\n 'drag | resizing': '$dialog-shadow',\n },\n outline: {\n '': '1bw #primary-text.0',\n 'focus-visible': '1bw #primary-text',\n },\n outlineOffset: '1bw',\n zIndex: {\n '': 1,\n 'drag | resizing': 10,\n },\n // The pointer-drag ghost (the clone that floats in the overlay) is slightly\n // translucent so the user can see through it to whatever it hovers over -\n // e.g. a Tabs header underneath - and land a precise drop / tab switch. The\n // in-place host (keyboard drags, which never float) stays fully opaque.\n opacity: {\n '': 1,\n floating: 0.8,\n },\n // Reflowing widgets animate their position and size. The actively\n // dragged/resized element - and the floating overlay clone - must track the\n // pointer with no lag, so they drop geometry from the list. Geometry is also\n // dropped until the board reports `settled`: on init widgets jump to their\n // first measured positions, and without this gate they would slide/grow in\n // from their default box. The board lifts the gate after the first\n // positioned paint so subsequent reflows animate normally.\n transition: {\n '': 'theme, shadow, opacity',\n settled: 'theme, shadow, opacity, inset, width, height',\n 'drag | floating | resizing': 'theme, shadow, opacity',\n },\n boxSizing: 'border-box',\n userSelect: {\n '': 'auto',\n 'drag | resizing': 'none',\n },\n cursor: {\n '': 'auto',\n draggable: 'grab',\n drag: 'grabbing',\n },\n touchAction: 'none',\n // A widget owns its grid cell and must not paint outside it: a nested board\n // with more rows than currently fit, a mid-drag reflow (an auto-height\n // container deliberately cannot grow while a drag is in flight), or a long\n // unbreakable string would otherwise spill over its neighbours. Clipping\n // holds regardless of `isCard` — a borderless widget has no drawn edge, but\n // it still has a cell.\n //\n // The cost is that a descendant's `outline` is cropped at the edge, since an\n // outline is clipped by an *ancestor's* overflow rather than its own. A\n // widget whose content needs to paint outside — a control drawing its own\n // active ring — opts out with `overflow=\"visible\"`, or draws the ring inset\n // with a negative `outlineOffset`.\n overflow: 'hidden',\n },\n});\n\nconst HandleElement = tasty({\n qa: 'BoardResizeHandle',\n styles: {\n position: 'absolute',\n zIndex: 20,\n fill: '#clear',\n // The corner hit-zone is drawn inside the grip layer, which takes no pointer\n // events; `pointer-events` inherits, so it has to opt back in. Inside the\n // widget this is what it already got from the default.\n pointerEvents: 'auto',\n // Overhang: how far the hit-zone extends beyond the widget edge. A\n // `corner`-placed grip hangs out by half its own size, and the hit-zone\n // matches it exactly - a visible grip you cannot grab is worse than no grip.\n '--handle-size': '3x',\n '--handle-overhang': {\n '': '-8px',\n 'placement=corner': `${-GRIP_SIZE / 2}px`,\n },\n '--handle-inset': '1x',\n width: {\n '': '$handle-size',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'auto',\n },\n height: {\n '': '$handle-size',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'auto',\n },\n top: {\n '': 'auto',\n '[data-axis=\"n\"] | [data-axis=\"ne\"] | [data-axis=\"nw\"]':\n '$handle-overhang',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': '$handle-inset',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"s\"] | [data-axis=\"se\"] | [data-axis=\"sw\"]':\n '$handle-overhang',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': '$handle-inset',\n },\n left: {\n '': 'auto',\n '[data-axis=\"w\"] | [data-axis=\"nw\"] | [data-axis=\"sw\"]':\n '$handle-overhang',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '$handle-inset',\n },\n right: {\n '': 'auto',\n '[data-axis=\"e\"] | [data-axis=\"ne\"] | [data-axis=\"se\"]':\n '$handle-overhang',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '$handle-inset',\n },\n cursor: {\n '': 'default',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'ns-resize',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'ew-resize',\n '[data-axis=\"ne\"] | [data-axis=\"sw\"]': 'nesw-resize',\n '[data-axis=\"nw\"] | [data-axis=\"se\"]': 'nwse-resize',\n },\n touchAction: 'none',\n },\n});\n\nconst GripElement = tasty({\n qa: 'BoardResizeGrip',\n styles: {\n position: 'absolute',\n // Both placements derive from one number, so the grip can never drift out of\n // step with its own size: `inside` tucks it into the widget box, `corner`\n // centres it on the widget's corner - exactly half its own size back from\n // each edge. Consumers pick between them with `resizeGripPlacement` instead\n // of re-deriving these offsets from the outside.\n '--grip-size': `${GRIP_SIZE}px`,\n '--grip-inset': '4px',\n '--grip-offset': {\n '': '$grip-inset',\n 'placement=corner': '($grip-size / -2)',\n },\n width: '$grip-size',\n height: '$grip-size',\n boxSizing: 'border-box',\n pointerEvents: 'none',\n opacity: {\n '': 0,\n revealed: 1,\n },\n transition: 'opacity 120ms ease-in-out',\n borderTop: {\n '': '0',\n '[data-axis=\"ne\"] | [data-axis=\"nw\"]': '2px solid #dark.40',\n },\n borderBottom: {\n '': '0',\n '[data-axis=\"se\"] | [data-axis=\"sw\"]': '2px solid #dark.40',\n },\n borderLeft: {\n '': '0',\n '[data-axis=\"nw\"] | [data-axis=\"sw\"]': '2px solid #dark.40',\n },\n borderRight: {\n '': '0',\n '[data-axis=\"ne\"] | [data-axis=\"se\"]': '2px solid #dark.40',\n },\n radius: {\n '': '0',\n '[data-axis=\"se\"]': '4px bottom-right',\n '[data-axis=\"sw\"]': '4px bottom-left',\n '[data-axis=\"ne\"]': '4px top-right',\n '[data-axis=\"nw\"]': '4px top-left',\n },\n top: {\n '': 'auto',\n '[data-axis=\"ne\"] | [data-axis=\"nw\"]': '$grip-offset',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"se\"] | [data-axis=\"sw\"]': '$grip-offset',\n },\n left: {\n '': 'auto',\n '[data-axis=\"nw\"] | [data-axis=\"sw\"]': '$grip-offset',\n },\n right: {\n '': 'auto',\n '[data-axis=\"ne\"] | [data-axis=\"se\"]': '$grip-offset',\n },\n },\n});\n\n/**\n * Where the corner grips are drawn when `resizeGripPlacement` is `'corner'`.\n *\n * `WidgetElement` clips its children (`overflow: hidden`, and that clipping is\n * load-bearing - see its own note), so a grip centred on the widget's corner\n * would be cut in half if it stayed inside. This layer mirrors the widget's grid\n * rect as a *sibling* of it, clips nothing, and never takes pointer events: the\n * transparent `HandleElement` inside the widget still owns the gesture, so\n * escaping the clip costs no hit-testing behaviour.\n *\n * It sits above a resting widget (`zIndex: 1`) so a grip is never hidden by the\n * neighbour it overhangs, and below a dragged or resized one (`zIndex: 10`) so a\n * lifted widget still paints over its neighbours' grips. The board's own content\n * box still clips it, so a grip on a widget flush against the board edge needs\n * `containerPadding` >= half the grip size to show in full.\n */\nconst GripLayerElement = tasty({\n qa: 'BoardResizeGripLayer',\n styles: {\n position: 'absolute',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: 5,\n },\n});\n\n/**\n * A control anchored to one corner of a widget, centred on it.\n *\n * Lives in the same layer as the corner resize grips, which is the layer that\n * exists precisely because a widget clips its own content: a control an app\n * hangs off the corner itself is cropped in half by that clip, or by an\n * ancestor's scroll container when the widget sits in the first row. Here it is\n * a sibling of the widget rather than a descendant, so neither can reach it.\n *\n * Being outside the widget host also means `useMove` is not attached, so a press\n * on the chrome cannot start a drag — no `dragCancel` entry required.\n */\nconst CornerChromeElement = tasty({\n qa: 'BoardWidgetCornerChrome',\n styles: {\n position: 'absolute',\n // The layer takes no pointer events; chrome is interactive, so it opts back in.\n pointerEvents: 'auto',\n zIndex: 1,\n top: {\n '': 'auto',\n 'corner=ne | corner=nw': 0,\n },\n bottom: {\n '': 'auto',\n 'corner=se | corner=sw': 0,\n },\n left: {\n '': 'auto',\n 'corner=nw | corner=sw': 0,\n },\n right: {\n '': 'auto',\n 'corner=ne | corner=se': 0,\n },\n // Centre it on the corner: half of its own size in each direction. The\n // default matches `ne`, which is also the default placement, so chrome is\n // still centred rather than hanging off-centre if no corner mod matches.\n transform: {\n '': 'translate(50%, -50%)',\n 'corner=nw': 'translate(-50%, -50%)',\n 'corner=se': 'translate(50%, 50%)',\n 'corner=sw': 'translate(-50%, 50%)',\n },\n },\n});\n\n// Edge axes (n/s/e/w) get a dotted grip affordance, revealed on\n// hover/focus/resize. The dots line up along the edge (a vertical column for the\n// e/w handles, a horizontal row for n/s), matching the design-system pane grip\n// (see `Layout.Pane`). Purely visual - the interaction still lives on the\n// transparent `HandleElement` hit-zone above.\nconst EdgeGripElement = tasty({\n qa: 'BoardResizeEdgeGrip',\n styles: {\n position: 'absolute',\n display: 'grid',\n gap: '2bw',\n boxSizing: 'border-box',\n pointerEvents: 'none',\n opacity: {\n '': 0,\n revealed: 1,\n },\n transition: 'opacity 120ms ease-in-out',\n // A column of 5 dots for the vertical edges (e/w), a row of 5 for n/s.\n gridColumns: {\n '': '3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '3px 3px 3px 3px 3px',\n },\n gridRows: {\n '': '3px 3px 3px 3px 3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '3px',\n },\n // Anchor to the relevant edge and center along it.\n top: {\n '': '50%',\n '[data-axis=\"n\"]': '3px',\n '[data-axis=\"s\"]': 'auto',\n },\n bottom: {\n '': 'auto',\n '[data-axis=\"s\"]': '3px',\n },\n left: {\n '': 'auto',\n '[data-axis=\"w\"]': '3px',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': '50%',\n },\n right: {\n '': 'auto',\n '[data-axis=\"e\"]': '3px',\n },\n transform: {\n '': 'translate(0, 0)',\n '[data-axis=\"e\"] | [data-axis=\"w\"]': 'translate(0, -50%)',\n '[data-axis=\"n\"] | [data-axis=\"s\"]': 'translate(-50%, 0)',\n },\n\n Dot: {\n width: '3px',\n height: '3px',\n radius: 'round',\n fill: {\n '': '#dark-03',\n resizing: '#dark-02',\n },\n },\n },\n});\n\n/** Corner axes get a visible grip affordance on hover/focus/resize. */\nfunction isCornerAxis(axis: ResizeHandleAxis): boolean {\n return axis.length === 2;\n}\n\n/** Edge axes (n/s/e/w) get a dotted grip affordance. */\nfunction isEdgeAxis(axis: ResizeHandleAxis): boolean {\n return axis.length === 1;\n}\n\ninterface ResizeHandleProps {\n axis: ResizeHandleAxis;\n placement: BoardResizeGripPlacement;\n onResize: (\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => void;\n}\n\nfunction ResizeHandle({ axis, placement, onResize }: ResizeHandleProps) {\n const { moveProps } = useMove({\n onMoveStart() {\n onResize(axis, 'start', 0, 0);\n },\n onMove(e) {\n onResize(axis, 'move', e.deltaX, e.deltaY);\n },\n onMoveEnd() {\n onResize(axis, 'end', 0, 0);\n },\n });\n\n const stopProps = {\n onPointerDown: (e: React.PointerEvent) => e.stopPropagation(),\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\n onTouchStart: (e: React.TouchEvent) => e.stopPropagation(),\n };\n\n return (\n <HandleElement\n data-axis={axis}\n mods={{ placement }}\n {...mergeProps(stopProps, moveProps)}\n aria-hidden=\"true\"\n />\n );\n}\n\nexport interface WidgetHostProps {\n boardId: string;\n item: LayoutItem;\n positionParams: PositionParams;\n registration: WidgetRegistration | undefined;\n /**\n * Whether this widget renders with card chrome (fill/border/radius). Resolved\n * by the owning `Board` from the per-widget `isCard` and the board-level\n * `widgetProps.isCard` default.\n */\n isCard: boolean;\n /**\n * Whether this widget draws the resting hover ring. Resolved by the owning\n * `Board` from the per-widget `hoverRing` and the board-level\n * `widgetProps.hoverRing` default.\n */\n hoverRing: boolean;\n /** Corner-anchored chrome, drawn outside the widget's clip. */\n cornerChrome?: ReactNode;\n /** Which corner {@link cornerChrome} is centred on. */\n cornerChromePlacement?: BoardCornerPlacement;\n /** App-defined modifiers merged into the host's own, for style maps to match. */\n mods?: Record<string, boolean | string | undefined>;\n /**\n * Resolved style overrides for the rendered widget element (per-widget\n * `styles` falling back to the board-level `widgetProps.styles`).\n */\n styles?: Styles;\n isDraggable: boolean;\n isResizable: boolean;\n resizeHandles: ResizeHandleAxis[];\n /**\n * Where the corner grips sit. Resolved by the owning `Board` from the\n * per-widget `resizeGripPlacement` and the board-level\n * `widgetProps.resizeGripPlacement` default.\n */\n resizeGripPlacement: BoardResizeGripPlacement;\n /**\n * Whether this widget grows to fit its content. Resolved by the owning\n * `Board` from the per-widget `isAutoHeight` and the board-level\n * `widgetProps.isAutoHeight` default.\n */\n isAutoHeight: boolean;\n /**\n * Test id / accessible name for the rendered widget element. Resolved by the\n * owning `Board` from the per-widget `qa` and the board-level `widgetProps.qa`\n * default; falls back to the layout id.\n */\n qa?: string;\n /**\n * CSS selector for elements that must not start a pointer drag (e.g. form\n * controls inside the widget). A pointer-down whose target matches this\n * selector never begins a drag.\n */\n dragCancel?: string;\n /**\n * CSS selector for the only elements from which a pointer drag may start. A\n * pointer-down outside a matching element never begins a drag.\n */\n dragHandle?: string;\n /**\n * Whether the owning board has settled its widgets' initial positions. While\n * false, the widget does not animate `inset` (left/top) so the first\n * positioned paint isn't seen as a transition. Lifted after the board's first\n * measured render.\n */\n settled?: boolean;\n registry: BoardRegistryContextValue;\n dragState: BoardDragState | null;\n onResize: (\n id: string,\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => void;\n /**\n * Report the minimum number of rows this widget needs to fit its content\n * (typically a nested board). The owning board grows the item to this height\n * when it is taller than the current one, and treats it as the resize floor\n * so the widget cannot be dragged shorter than its content requires.\n */\n onAutoHeight: (id: string, neededRows: number) => void;\n /**\n * Notify the owning board of a drag gesture's lifecycle so it can emit the\n * public drag callbacks. Fires after the registry has updated drag state.\n */\n onDragLifecycle?: (id: string, phase: ResizePhase) => void;\n /** Whether this widget can be selected (board selection on and not opted out). */\n isSelectable?: boolean;\n isSelected?: boolean;\n /**\n * A live marquee currently covers this widget, so it *will* be selected when\n * the pointer is released. Provisional: it never reaches the selection model,\n * the callbacks or the live region.\n */\n isPreSelected?: boolean;\n /** CSS selector for descendants whose clicks must not change the selection. */\n selectionCancel?: string;\n /** Id of the board-owned node holding the shared \"Selected\" description. */\n selectedHintId?: string;\n /** Apply a selection gesture. `additive` toggles instead of replacing. */\n onSelect?: (id: string, additive: boolean) => void;\n /** Drop the whole selection. Called when the user interacts elsewhere. */\n onSelectionReset?: () => void;\n /** Pointer-event property carrying the platform additive-selection modifier. */\n selectModifierKey?: BoardSelectModifierKey;\n}\n\n/**\n * The positioned, interactive wrapper a board renders for each layout item it\n * owns. Content is pulled from the shared store (by id), so any board can host\n * any widget. Dragging uses React Aria `useMove`; during a drag the widget\n * renders into the shared overlay portal so it can float outside its board.\n */\nexport function WidgetHost(props: WidgetHostProps) {\n const {\n boardId,\n item,\n positionParams,\n registration,\n isCard,\n hoverRing,\n cornerChrome,\n cornerChromePlacement = 'ne',\n mods: customMods,\n styles: widgetStyles,\n isDraggable,\n isResizable,\n resizeHandles,\n resizeGripPlacement,\n isAutoHeight,\n qa,\n dragCancel,\n dragHandle,\n registry,\n dragState,\n settled,\n onResize,\n onAutoHeight,\n onDragLifecycle,\n isSelectable = false,\n isSelected = false,\n isPreSelected = false,\n selectionCancel,\n selectedHintId,\n onSelect,\n onSelectionReset,\n selectModifierKey = 'metaKey',\n } = props;\n\n const { t } = useI18n();\n const ariaLabel = registration?.['aria-label'];\n const hostRef = useRef<HTMLDivElement | null>(null);\n const isActiveDrag = dragState?.itemId === item.i;\n // Every member of a group drag floats, not just the grabbed one — otherwise\n // the rest sit motionless while their placeholders move, which reads as\n // broken. Only the grabbed host owns a live `useMove` gesture, so hiding the\n // others is trivially safe.\n const isDragMember = !!dragState?.itemIds.includes(item.i);\n\n // Translate a nested board's reported height deficit (signed px: positive when\n // it is squeezed, negative when it has slack) into the absolute number of rows\n // this widget needs, and report it to the owning board. The widget's chrome\n // cancels out: the needed pixel height is the widget's current pixel height\n // plus the deficit. A small tolerance keeps sub-pixel rounding from bumping an\n // extra row. Skipped during a drag (the widget is floating in the overlay).\n const requestHeightDeficit = useEvent((deficitPx: number) => {\n if (!isAutoHeight || isActiveDrag) return;\n const step = positionParams.rowHeight + positionParams.margin[1];\n if (step <= 0) return;\n const current = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n const neededPx = current.height + deficitPx;\n const neededRows = Math.max(\n 1,\n Math.ceil(\n (neededPx + positionParams.margin[1] - AUTO_HEIGHT_TOLERANCE) / step,\n ),\n );\n onAutoHeight(item.i, neededRows);\n });\n\n const hostValue = useMemo<BoardHost>(\n () => ({ isAutoHeight, requestHeightDeficit }),\n [isAutoHeight, requestHeightDeficit],\n );\n // Keyboard drags stay in place: moving the focused element into the overlay\n // portal would unmount it and stop arrow-key move events.\n const useOverlay = isActiveDrag && dragState?.pointerType !== 'keyboard';\n\n const [isResizing, setIsResizing] = useState(false);\n const [isFocusWithin, setIsFocusWithin] = useState(false);\n const { hoverProps, isHovered } = useHover({ isDisabled: isActiveDrag });\n // A `corner` grip and its hit-zone live outside the widget box, so hovering the\n // half that hangs out is not hovering the widget. Without this the grip fades\n // away exactly as the pointer arrives on it - the affordance retreats from the\n // gesture it is inviting.\n const { hoverProps: layerHoverProps, isHovered: isLayerHovered } = useHover({\n isDisabled: isActiveDrag,\n });\n const { focusProps, isFocusVisible } = useFocusRing();\n const { focusWithinProps } = useFocusWithin({\n onFocusWithinChange: setIsFocusWithin,\n });\n\n // Reveal the resize grips when the widget is interacted with (but not while it\n // is being dragged, where the widget floats in the overlay).\n const gripsRevealed =\n isResizable &&\n !item.static &&\n !isActiveDrag &&\n (isHovered || isLayerHovered || isFocusWithin || isResizing);\n\n const { moveProps } = useMove({\n onMoveStart(e) {\n if (!isDraggable) return;\n const rect = hostRef.current?.getBoundingClientRect();\n const pos = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n const vr: ViewportRect = rect\n ? {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n }\n : {\n left: pos.left,\n top: pos.top,\n width: pos.width,\n height: pos.height,\n };\n registry.onDragStart(boardId, item.i, vr, e.pointerType, hostRef.current);\n onDragLifecycle?.(item.i, 'start');\n },\n onMove(e) {\n if (!isDraggable) return;\n if (e.pointerType === 'keyboard') {\n // Amplify arrow-key steps to a full grid cell so items actually move.\n const colWidth = calcGridColWidth(positionParams);\n const stepX = colWidth + positionParams.margin[0];\n const stepY = positionParams.rowHeight + positionParams.margin[1];\n registry.onDragMove(\n Math.sign(e.deltaX) * stepX,\n Math.sign(e.deltaY) * stepY,\n e.pointerType,\n );\n onDragLifecycle?.(item.i, 'move');\n return;\n }\n registry.onDragMove(e.deltaX, e.deltaY, e.pointerType);\n onDragLifecycle?.(item.i, 'move');\n },\n onMoveEnd() {\n if (!isDraggable) return;\n registry.onDragEnd();\n onDragLifecycle?.(item.i, 'end');\n },\n });\n\n // `role=\"group\"` is what makes `aria-roledescription` legal here - it is\n // invalid on a role-less `div`, which is what this element used to be. A\n // collection role (`option`, `gridcell`, ...) would be the only way to carry a\n // real `aria-selected`, but those require presentational children and a\n // widget hosts arbitrary interactive content, so selection is conveyed by the\n // board's live region plus the shared description below instead.\n const a11yProps = {\n role: 'group',\n tabIndex: isDraggable || isSelectable ? 0 : undefined,\n 'aria-roledescription': isDraggable\n ? t('board.draggableWidget', 'Draggable widget')\n : t('board.widget', 'Widget'),\n 'aria-label': ariaLabel ?? qa ?? item.i,\n 'aria-describedby': isSelected ? selectedHintId : undefined,\n 'aria-keyshortcuts': isSelectable ? 'Space' : undefined,\n };\n\n // True from the moment a real move begins until the click that ends the\n // gesture has been swallowed. `useMove` binds only pointerdown/keydown, never\n // click, so a click handler composes with it cleanly - but the click that\n // *terminates* a drag would otherwise land as a selection. Event order is\n // pointerdown -> onMove* -> pointerup -> onMoveEnd -> click, so this ref is\n // always accurate by the time the click arrives. More reliable than a pixel\n // threshold, which has to guess.\n const isInteractiveTarget = (target: EventTarget | null) => {\n const el = target as HTMLElement | null;\n\n return !!(selectionCancel && el?.closest?.(selectionCancel));\n };\n\n /**\n * Pressing something interactive means the user has moved on from the\n * selection, so the selection is dropped — always, whatever the control is and\n * whatever it does with the event.\n *\n * That \"always\" is why this is a *capture*-phase handler and not part of\n * `handleSelectPointerDown` below. A bubble-phase handler only sees the\n * presses that reach the host, and a control is free to call\n * `stopPropagation()` before that happens — React Aria's `usePress` does it by\n * default, which is why some in-widget buttons dropped the selection and\n * others silently did not. Capture runs top-down, so it lands before any\n * descendant can speak. Portaled controls (a menu opened from a widget's\n * toolbar) are covered too: React propagates events along the React tree, so a\n * portal declared inside this widget still passes through here.\n *\n * Nothing is stopped or prevented here — the handler only reads the target, so\n * the control keeps its press, its focus and its default behaviour intact.\n */\n const handleSelectPointerDownCapture = (e: React.PointerEvent) => {\n if (!isSelectable || e.button !== 0) return;\n\n if (isInteractiveTarget(e.target)) {\n onSelectionReset?.();\n }\n };\n\n // The React capture handler above is dispatched from the React root, so a\n // descendant that stops the *native* event (charting and mapping libraries\n // attach their own listeners and do exactly that) keeps it from ever reaching\n // React — capture phase included. A native capture listener on the host node\n // itself sits below any such descendant and cannot be pre-empted. The two\n // overlap for the ordinary case and that costs nothing: clearing an already\n // empty selection is a no-op.\n useEffect(() => {\n const node = hostRef.current;\n\n if (!node || !isSelectable || !selectionCancel || !onSelectionReset) return;\n\n const handleCapture = (event: PointerEvent) => {\n if (event.button !== 0) return;\n\n const target = event.target as HTMLElement | null;\n\n if (target?.closest?.(selectionCancel)) {\n onSelectionReset();\n }\n };\n\n node.addEventListener('pointerdown', handleCapture, true);\n\n return () => node.removeEventListener('pointerdown', handleCapture, true);\n }, [isSelectable, selectionCancel, onSelectionReset]);\n\n /**\n * Selecting and starting a drag are the *same* gesture: you grab the thing you\n * are about to move. So the press selects immediately and the drag arms behind\n * it — move and it drags, stay still and it was only a selection. This is what\n * every canvas tool does, and it is why there is no ambiguity to resolve with a\n * modifier.\n *\n * - a press on an interactive descendant belongs to that control, so the\n * press is left alone (the selection was already dropped in the capture\n * phase above);\n * - <kbd>Shift</kbd> or the platform modifier toggles membership;\n * - a press on an unselected widget makes it the selection, so the drag that\n * follows moves exactly what was grabbed;\n * - a press on an already-selected widget changes nothing, so the drag moves\n * the whole group.\n *\n * Runs before the drag handler (see the `mergeProps` order below), so the\n * registry resolves the group against the selection this press just made.\n */\n const handleSelectPointerDown = (e: React.PointerEvent) => {\n if (!isSelectable || !onSelect || e.button !== 0) return;\n\n if (isInteractiveTarget(e.target)) return;\n\n // A press this widget owns must never reach an ancestor widget host: in a\n // nested board the outer widget would otherwise select itself on top of the\n // inner selection. This has to cover the already-selected case too, which\n // changes nothing here but is still a press this board handled — and\n // `stopBubbleProps` below only guards draggable widgets.\n e.stopPropagation();\n\n if (e.shiftKey || e[selectModifierKey]) {\n onSelect(item.i, true);\n\n return;\n }\n\n if (!isSelected) {\n onSelect(item.i, false);\n }\n };\n\n const handleSelectKeyDown = (e: React.KeyboardEvent) => {\n // Same guard the arrow keys use: only act when the host itself is focused,\n // so Space inside a nested input or button keeps its meaning.\n if (e.target !== e.currentTarget) return;\n if (!isSelectable || !onSelect) return;\n if (e.key !== ' ' && e.key !== 'Spacebar') return;\n\n // No modifier needed here: focus already says which widget is meant, and\n // Space cannot be mistaken for the start of a drag. Only swallow the key\n // once we know we are acting on it, so a board without selection still\n // scrolls on Space.\n e.preventDefault();\n e.stopPropagation();\n // Space is an explicit selection gesture (a click is also \"interact with\n // this\"), so it toggles - that is the keyboard's way to deselect one widget.\n onSelect(item.i, true);\n };\n\n // When this widget is draggable it owns its gesture, so stop the pointer-down\n // from bubbling to an ancestor widget host (e.g. a container widget hosting a\n // nested board / Tabs). Otherwise the ancestor's `useMove` would start a\n // second drag from the same press and the whole parent widget would move too.\n // Non-draggable widgets let the event bubble so their container stays grabbable\n // through their content.\n const stopBubbleProps = isDraggable\n ? {\n onPointerDown: (e: React.PointerEvent) => e.stopPropagation(),\n onMouseDown: (e: React.MouseEvent) => e.stopPropagation(),\n onTouchStart: (e: React.TouchEvent) => e.stopPropagation(),\n }\n : {};\n\n // Gate a pointer drag by `dragHandle` / `dragCancel` selectors. Returns true\n // when the press must NOT start a drag (outside a `dragHandle`, or matching\n // `dragCancel`).\n const shouldGateDrag = (target: EventTarget | null) => {\n if (!(target instanceof Element)) return false;\n if (dragHandle && !target.closest(dragHandle)) return true;\n if (dragCancel && target.closest(dragCancel)) return true;\n\n // `selectionCancel` already declares which descendants are interactive, and\n // a drag must not start from them either — otherwise `useMove`'s\n // `preventDefault()` on pointer-down swallows the native focus and an input\n // inside a widget cannot be typed into. Only for selectable widgets, so a\n // board that never opted into selection keeps its exact previous behaviour\n // and `dragCancel` stays the only thing that gates a drag there.\n return !!(\n isSelectable &&\n selectionCancel &&\n target.closest(selectionCancel)\n );\n };\n\n // The gate wraps `useMove`'s own pointer-down handlers rather than a separate\n // capture-phase listener. When a press is gated we simply do not forward it to\n // `useMove`, so the drag never begins. This is deliberate: `useMove`'s\n // pointer-down handler calls both `stopPropagation()` and `preventDefault()`.\n // Calling it (or pre-empting it with a capture-phase `stopPropagation()`)\n // would break the very controls `dragCancel` is meant to protect - a\n // `preventDefault()` on pointer-down cancels a native `<input>`'s focus, and a\n // capture-phase `stopPropagation()` swallows a `<button>`'s own press events.\n // Skipping `useMove` entirely leaves the target's default behavior and its own\n // handlers fully intact.\n //\n // Keyboard moves also go through `useMove` (`onKeyDown`). Arrow keys must only\n // move the widget when the host itself is focused — not when focus is inside a\n // nested input, textarea, or other descendant (those events bubble to the host\n // and would otherwise steal caret / list navigation).\n //\n // A non-draggable widget must not carry `moveProps` at all: `useMove`'s\n // pointer-down handler calls `preventDefault()`, which cancels native text\n // selection inside the widget. Read-only boards (`isDraggable={false}`) still\n // need selectable content, so we drop the handlers entirely instead of relying\n // on the early-returns inside the `onMove*` callbacks.\n const gatedMoveProps = !isDraggable\n ? {}\n : {\n ...moveProps,\n ...(moveProps.onPointerDown && {\n onPointerDown: (e: React.PointerEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n hostRef.current?.focus({ preventScroll: true });\n moveProps.onPointerDown!(e);\n },\n }),\n ...(moveProps.onMouseDown && {\n onMouseDown: (e: React.MouseEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n hostRef.current?.focus({ preventScroll: true });\n moveProps.onMouseDown!(e);\n },\n }),\n ...(moveProps.onTouchStart && {\n onTouchStart: (e: React.TouchEvent<HTMLDivElement>) => {\n if (shouldGateDrag(e.target)) return;\n moveProps.onTouchStart!(e);\n },\n }),\n ...(moveProps.onKeyDown && {\n onKeyDown: (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.target !== e.currentTarget) return;\n handleSelectKeyDown(e);\n if (e.defaultPrevented) return;\n moveProps.onKeyDown!(e);\n },\n }),\n };\n\n // A non-draggable widget gets no `moveProps` at all, so its Space handling and\n // its focusability have to come from here instead.\n const selectionProps = isSelectable\n ? {\n onPointerDownCapture: handleSelectPointerDownCapture,\n onPointerDown: handleSelectPointerDown,\n // A draggable widget routes Space through the drag gate below, which\n // already enforces the host-focused rule; a non-draggable one gets no\n // `moveProps` at all and needs its own handler.\n ...(isDraggable ? {} : { onKeyDown: handleSelectKeyDown }),\n }\n : {};\n\n const handleResize = (\n axis: ResizeHandleAxis,\n phase: ResizePhase,\n dx: number,\n dy: number,\n ) => {\n if (phase === 'start') setIsResizing(true);\n else if (phase === 'end') setIsResizing(false);\n onResize(item.i, axis, phase, dx, dy);\n };\n\n const mods = {\n drag: isActiveDrag,\n draggable: isDraggable && !isActiveDrag,\n static: !!item.static,\n resizing: isResizing,\n card: isCard,\n 'no-hover-ring': !hoverRing,\n hovered: isHovered,\n 'focus-visible': isFocusVisible,\n selected: isSelected,\n // Mutually exclusive with `selected` by construction, so the two never\n // compete for precedence in a style map — and an additive lasso leaves the\n // widgets it already owns looking fully selected rather than downgrading\n // them to a preview.\n 'pre-selected': isPreSelected && !isSelected,\n };\n\n const content = (\n <BoardHostContext.Provider value={hostValue}>\n {registration?.content}\n {isResizable && !item.static ? (\n <>\n {/* A `corner` grip and its hit-zone both move to the sibling\n `GripLayerElement` below, which the widget's own `overflow: hidden`\n cannot clip. They travel together: hoisting only the visual would\n leave the half that hangs outside impossible to grab. */}\n {(resizeGripPlacement === 'corner'\n ? resizeHandles.filter((axis) => !isCornerAxis(axis))\n : resizeHandles\n ).map((axis) => (\n <ResizeHandle\n key={axis}\n axis={axis}\n placement={resizeGripPlacement}\n onResize={handleResize}\n />\n ))}\n {resizeGripPlacement === 'corner'\n ? null\n : resizeHandles\n .filter(isCornerAxis)\n .map((axis) => (\n <GripElement\n key={`grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, placement: 'inside' }}\n aria-hidden=\"true\"\n />\n ))}\n {resizeHandles.filter(isEdgeAxis).map((axis) => (\n <EdgeGripElement\n key={`edge-grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, resizing: isResizing }}\n aria-hidden=\"true\"\n >\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n <div data-element=\"Dot\" />\n </EdgeGripElement>\n ))}\n </>\n ) : null}\n </BoardHostContext.Provider>\n );\n\n const pos = calcGridItemPosition(\n positionParams,\n item.x,\n item.y,\n item.w,\n item.h,\n );\n\n // While dragging with a pointer, the widget's visual floats in the shared\n // overlay so it is never clipped by an ancestor's `overflow: hidden`. The\n // gesture-owning element (the one carrying `moveProps`) must NOT be the node\n // that moves into the overlay: React Aria's `useMove` binds its pointer\n // move/end listeners relative to the node that received `onPointerDown`, and\n // relocating that node into the portal tears it down and mounts a fresh one\n // (inside a `pointerEvents: 'none'` layer), which can drop the in-flight\n // gesture. Instead we keep a stable, always-mounted in-grid host that owns the\n // gesture for its whole lifetime, and portal a separate, non-interactive\n // visual clone into the overlay.\n const overlayNode = registry.overlayRef.current;\n // Non-grabbed group members float too, from their own drag-start rect plus the\n // one shared gesture delta. Measuring them here would be wrong (the board is\n // mid-reflow); the registry measured every member once at drag start, which is\n // the only safe window.\n const memberRect = isDragMember\n ? dragState!.memberRects.get(item.i)\n : undefined;\n const floatInOverlay =\n !!overlayNode &&\n !!dragState &&\n dragState.pointerType !== 'keyboard' &&\n (useOverlay || (isDragMember && !!memberRect));\n\n // Where the floating clone sits. The grabbed widget tracks the live drag rect\n // directly; a member tracks its own start rect offset by the same delta, so\n // the block moves as one.\n const floatRect =\n floatInOverlay && dragState\n ? isActiveDrag || !memberRect\n ? dragState.rect\n : {\n left:\n memberRect.left +\n (dragState.rect.left - dragState.startRect.left),\n top:\n memberRect.top + (dragState.rect.top - dragState.startRect.top),\n width: memberRect.width,\n height: memberRect.height,\n }\n : null;\n\n const hostStyle: CSSProperties = {\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n // Kept mounted but hidden while its clone floats, so the gesture stays live\n // on this node (the pointer listeners never get torn down).\n ...(floatInOverlay ? { opacity: 0, pointerEvents: 'none' } : null),\n };\n\n // The floating clone carries the \"drag\" affordance (raised shadow/z-index);\n // keep the hidden host flat. Keyboard drags (which never float) still\n // highlight the in-grid host, so only suppress `drag` when floating.\n // App mods go UNDER the board's own: a custom mod must never be able to\n // shadow `selected`, `drag` and friends, which the board's own style map and\n // its accessibility wiring both depend on.\n const hostMods = {\n ...customMods,\n ...mods,\n drag: isActiveDrag && !floatInOverlay,\n settled,\n };\n\n // The host is always rendered first, with a stable element shape, so React\n // reuses the same DOM node across the drag transition (never remounts it).\n const host = (\n <WidgetElement\n ref={hostRef}\n // Marks this element as a board widget host so the registry can find the\n // container widget a nested board lives in (used to keep a drag anchored to\n // a nested board while the anchor is still over its host - e.g. the Tabs\n // header above a nested board - instead of reflowing the ancestor board).\n data-board-widget-host=\"\"\n // Which widget, as opposed to \"am I inside a widget host\" - the two are\n // separate questions and the existing attribute is used as a presence\n // selector, so overloading it would make every such selector implicitly\n // value-dependent. Namespaced so it cannot collide with an app's own\n // `data-widget-id`.\n data-board-widget-id={item.i}\n {...mergeProps(\n // Before `gatedMoveProps`: the press selects, and only then does the\n // drag start and read that selection to decide what moves.\n selectionProps,\n gatedMoveProps,\n stopBubbleProps,\n hoverProps,\n focusProps,\n focusWithinProps,\n a11yProps,\n { style: hostStyle },\n )}\n qa={qa}\n mods={hostMods}\n styles={widgetStyles as Styles}\n >\n {floatInOverlay ? null : content}\n </WidgetElement>\n );\n\n const overlayClone = floatInOverlay\n ? createPortal(\n <WidgetElement\n style={{\n position: 'absolute',\n left: `${floatRect!.left}px`,\n top: `${floatRect!.top}px`,\n width: `${floatRect!.width}px`,\n height: `${floatRect!.height}px`,\n pointerEvents: 'none',\n }}\n // `hostMods` rather than `mods`, so the app's own modifiers survive the\n // gesture: the clone IS the widget while a pointer drag is in flight\n // (the in-grid host is hidden), and a custom state blinking off for the\n // duration of the drag is exactly when it would be most noticeable.\n mods={{ ...hostMods, drag: true, floating: true }}\n styles={widgetStyles as Styles}\n aria-hidden=\"true\"\n >\n {content}\n </WidgetElement>,\n overlayNode!,\n )\n : null;\n\n // Corner grips that must straddle the widget edge, hoisted out of the widget's\n // clip (see `GripLayerElement`). Positioned on the same grid rect as the host,\n // so the two stay in step through reflows and auto-height changes.\n const cornerAxes =\n isResizable && !item.static && resizeGripPlacement === 'corner'\n ? resizeHandles.filter(isCornerAxis)\n : [];\n // Suppressed while the widget floats in the drag overlay: the layer mirrors the\n // widget's *grid* rect, so leaving it behind would park a live hit-zone on a\n // cell the widget has visually left.\n // The layer is also what carries corner chrome, so it renders when either the\n // grips or the chrome need it.\n const gripLayer =\n (cornerAxes.length || cornerChrome) && !floatInOverlay ? (\n <GripLayerElement\n {...layerHoverProps}\n style={{\n left: `${pos.left}px`,\n top: `${pos.top}px`,\n width: `${pos.width}px`,\n height: `${pos.height}px`,\n }}\n // Only the grips are decorative. Chrome is real, focusable UI, so the\n // layer can only be hidden from assistive tech when it holds no chrome.\n aria-hidden={cornerChrome ? undefined : 'true'}\n >\n {cornerAxes.map((axis) => (\n <ResizeHandle\n key={`handle-${axis}`}\n axis={axis}\n placement=\"corner\"\n onResize={handleResize}\n />\n ))}\n {cornerAxes.map((axis) => (\n <GripElement\n key={`grip-${axis}`}\n data-axis={axis}\n mods={{ revealed: gripsRevealed, placement: 'corner' }}\n aria-hidden=\"true\"\n />\n ))}\n {cornerChrome ? (\n <CornerChromeElement mods={{ corner: cornerChromePlacement }}>\n {cornerChrome}\n </CornerChromeElement>\n ) : null}\n </GripLayerElement>\n ) : null;\n\n return (\n <>\n {host}\n {gripLayer}\n {overlayClone}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
//#region src/components/layout/Board/grid-core/calculate.ts
|
|
3
3
|
/** Calculate the width of a single grid column in pixels. */
|
|
4
4
|
function calcGridColWidth(positionParams) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
//#region src/components/layout/Board/grid-core/collision-modes.ts
|
|
3
3
|
/** Whether a single grid cell is free of every item in `others`. */
|
|
4
4
|
function cellFree(others, x, y) {
|
|
@@ -56,18 +56,85 @@ function maxFreeRectAt(others, anchor, desired, limits, mins) {
|
|
|
56
56
|
return best;
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
+
* The cells beyond a pinned anchor that a drag could never ask for.
|
|
60
|
+
*
|
|
61
|
+
* `gridBounds` clamps a drag anchor to `cols - w` (and `maxRows - h`), which
|
|
62
|
+
* assumes the widget keeps the size it started with. So when the blocker is to
|
|
63
|
+
* the LEFT of the free room and that room is narrower than the widget, every
|
|
64
|
+
* anchor a pointer can produce lands inside the blocker - and the mode whose
|
|
65
|
+
* whole job is to shrink the widget into that room never gets offered it. The
|
|
66
|
+
* drop just reverts. The mirror case has no such problem, because the anchor at
|
|
67
|
+
* column 0 is always reachable: that asymmetry is why downscaling into room on
|
|
68
|
+
* the left has always worked and room on the right has not. The row axis clamps
|
|
69
|
+
* the same way, so a board with a finite `maxRows` has the same blind spot below
|
|
70
|
+
* a blocker.
|
|
71
|
+
*
|
|
72
|
+
* Nothing is offered unless the anchor is sitting ON the limit, pinned against
|
|
73
|
+
* the far edge with the pointer unable to push it further. An anchor short of the
|
|
74
|
+
* limit is the pointer's own choice - every cell between it and the limit was
|
|
75
|
+
* available to ask for - so a blocked drop there still just reverts, exactly as
|
|
76
|
+
* before. Without that gate a widget dropped on an occupied cell would skip over
|
|
77
|
+
* free cells the pointer could perfectly well have aimed at.
|
|
78
|
+
*
|
|
79
|
+
* A pinned anchor's span ends at the last row/column of the grid, so every cell
|
|
80
|
+
* returned - and every rectangle that can be measured from one - lies inside the
|
|
81
|
+
* footprint the widget is already covering.
|
|
82
|
+
*/
|
|
83
|
+
function clampedOutAnchors(item, desired, limits) {
|
|
84
|
+
const maxRows = limits.maxRows ?? Infinity;
|
|
85
|
+
const bounded = Number.isFinite(maxRows);
|
|
86
|
+
const xLimit = Math.max(0, limits.cols - desired.w);
|
|
87
|
+
const yLimit = bounded ? Math.max(0, maxRows - desired.h) : Infinity;
|
|
88
|
+
const anchors = [];
|
|
89
|
+
if (item.x === xLimit) {
|
|
90
|
+
const lastX = Math.min(item.x + desired.w - 1, limits.cols - 1);
|
|
91
|
+
for (let x = item.x + 1; x <= lastX; x++) anchors.push({
|
|
92
|
+
x,
|
|
93
|
+
y: item.y
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (bounded && item.y === yLimit) {
|
|
97
|
+
const lastY = Math.min(item.y + desired.h - 1, maxRows - 1);
|
|
98
|
+
for (let y = item.y + 1; y <= lastY; y++) anchors.push({
|
|
99
|
+
x: item.x,
|
|
100
|
+
y
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return anchors;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
59
106
|
* Shrink the placement to the room actually available at the cell it was
|
|
60
|
-
* dropped on
|
|
107
|
+
* dropped on, or - when that cell cannot take the widget at any size and the
|
|
108
|
+
* anchor is pinned against the grid edge - at a cell the clamp hid from the
|
|
109
|
+
* pointer (see `clampedOutAnchors`). The largest fit among those wins, so the
|
|
110
|
+
* widget takes as much of the room it is already hovering as there is.
|
|
61
111
|
*/
|
|
62
112
|
function downscaleInPlace(layout, item, others, desired, limits) {
|
|
63
|
-
const
|
|
113
|
+
const fitAt = (anchor) => maxFreeRectAt(others, anchor, desired, limits, item);
|
|
114
|
+
let anchor = {
|
|
64
115
|
x: item.x,
|
|
65
116
|
y: item.y
|
|
66
|
-
}
|
|
117
|
+
};
|
|
118
|
+
let fit = fitAt(anchor);
|
|
119
|
+
if (!fit) {
|
|
120
|
+
let bestArea = 0;
|
|
121
|
+
for (const candidate of clampedOutAnchors(item, desired, limits)) {
|
|
122
|
+
const candidateFit = fitAt(candidate);
|
|
123
|
+
if (!candidateFit) continue;
|
|
124
|
+
const area = candidateFit.w * candidateFit.h;
|
|
125
|
+
if (area > bestArea) {
|
|
126
|
+
bestArea = area;
|
|
127
|
+
fit = candidateFit;
|
|
128
|
+
anchor = candidate;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
67
132
|
if (!fit) return null;
|
|
68
|
-
if (fit.w === item.w && fit.h === item.h) return null;
|
|
133
|
+
if (fit.w === item.w && fit.h === item.h && anchor.x === item.x && anchor.y === item.y) return null;
|
|
69
134
|
return layout.map((l) => l.i === item.i ? {
|
|
70
135
|
...l,
|
|
136
|
+
x: anchor.x,
|
|
137
|
+
y: anchor.y,
|
|
71
138
|
w: fit.w,
|
|
72
139
|
h: fit.h,
|
|
73
140
|
moved: true
|
|
@@ -158,8 +225,9 @@ function exchangeWith(layout, item, other, from, desired, limits) {
|
|
|
158
225
|
* dense grid stays draggable that way - refusing everything that is not a clean
|
|
159
226
|
* one-to-one trade would make the mode feel broken exactly where it is needed.
|
|
160
227
|
* Cross-board callers pass `allowExchange: false`, which turns the same mode into
|
|
161
|
-
*
|
|
162
|
-
* cannot
|
|
228
|
+
* downscaling at the drop cell - there is no slot on the destination to trade
|
|
229
|
+
* back, and a transfer that cannot resolve is placed in a free cell rather than
|
|
230
|
+
* refused, since a widget dropped somewhere has to end up somewhere.
|
|
163
231
|
*/
|
|
164
232
|
function createCollisionResolver(mode, options) {
|
|
165
233
|
if (!mode || mode === "revert") return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collision-modes.js","names":[],"sources":["../../../../../src/components/layout/Board/grid-core/collision-modes.ts"],"sourcesContent":["/**\n * Collision resolution strategies for a grid that prevents collisions.\n *\n * Original UI Kit code (not vendored from react-grid-layout): the upstream\n * engine only ever reverts a blocked move.\n *\n * When `preventCollision` is on, `moveElement` refuses any placement that\n * overlaps an existing item and snaps the dragged item back. That is the right\n * default, but a free grid often wants the placement *resolved* instead of\n * refused - shrunk into whatever room is actually there, or exchanged with the\n * widget already sitting in the target slot. These strategies produce such a\n * resolution, and every resolution they return is overlap-free, so the caller's\n * own overlap guards keep working unchanged.\n */\n\nimport { collides } from './collision';\n\nimport type {\n CollisionMode,\n CollisionResolver,\n CollisionResolverOptions,\n Layout,\n LayoutItem,\n} from './types';\n\n/** Whether a single grid cell is free of every item in `others`. */\nfunction cellFree(others: Layout, x: number, y: number): boolean {\n for (let i = 0; i < others.length; i++) {\n const o = others[i];\n if (\n o !== undefined &&\n x >= o.x &&\n x < o.x + o.w &&\n y >= o.y &&\n y < o.y + o.h\n ) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The largest rectangle anchored at `anchor` that fits without overlapping\n * `others`, growing rightward and downward only.\n *\n * Never larger than `desired` (a drag must never *upscale* a widget - growing\n * things is an explicit, opt-in operation like \"distribute evenly\", not a side\n * effect of moving them), never smaller than the item's own `minW`/`minH`, and\n * never past `cols` / `maxRows`. Among the candidates the largest-area rectangle\n * wins, breaking ties on width: a grid is read left to right, so a wide-and-flat\n * result is the less surprising of two equal-area fits.\n *\n * Returns `null` when not even the minimum size fits, which the callers treat as\n * \"no resolution\" and fall back to reverting.\n */\nexport function maxFreeRectAt(\n others: Layout,\n anchor: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n mins?: { minW?: number; minH?: number },\n): { w: number; h: number } | null {\n if (anchor.x < 0 || anchor.y < 0) return null;\n\n const minW = Math.max(1, mins?.minW ?? 1);\n const minH = Math.max(1, mins?.minH ?? 1);\n const maxRows = limits.maxRows ?? Infinity;\n const maxW = Math.min(desired.w, limits.cols - anchor.x);\n const maxH = Math.min(\n desired.h,\n Number.isFinite(maxRows) ? maxRows - anchor.y : desired.h,\n );\n\n if (maxW < minW || maxH < minH) return null;\n\n // Free height available in each column of the candidate band, measured down\n // from the anchor row and capped at the tallest useful height.\n const free: number[] = [];\n for (let dx = 0; dx < maxW; dx++) {\n let h = 0;\n while (h < maxH && cellFree(others, anchor.x + dx, anchor.y + h)) h++;\n free.push(h);\n // A column with no room at all caps every wider candidate, so stop early.\n if (h === 0) break;\n }\n\n let best: { w: number; h: number } | null = null;\n let bestArea = 0;\n let limit = maxH;\n for (let w = 1; w <= free.length; w++) {\n limit = Math.min(limit, free[w - 1]!);\n if (limit < minH) break;\n if (w < minW) continue;\n const area = w * limit;\n // `>=` so the widest of several equal-area fits wins: `w` only grows here, so\n // the last match is the widest one.\n if (area >= bestArea) {\n best = { w, h: limit };\n bestArea = area;\n }\n }\n\n return best;\n}\n\n/**\n * Shrink the placement to the room actually available at the cell it was\n * dropped on.\n */\nfunction downscaleInPlace(\n layout: Layout,\n item: LayoutItem,\n others: Layout,\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n const fit = maxFreeRectAt(\n others,\n { x: item.x, y: item.y },\n desired,\n limits,\n item,\n );\n if (!fit) return null;\n // Nothing to resolve: the requested size already fits, so the collision was\n // not a sizing problem and reverting is still the honest answer.\n if (fit.w === item.w && fit.h === item.h) return null;\n\n return layout.map((l) =>\n l.i === item.i ? { ...l, w: fit.w, h: fit.h, moved: true } : l,\n );\n}\n\n/** Number of cells two items share. Zero when they do not overlap at all. */\nfunction overlapArea(a: LayoutItem, b: LayoutItem): number {\n const w = Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x);\n const h = Math.min(a.y + a.h, b.y + b.h) - Math.max(a.y, b.y);\n return w > 0 && h > 0 ? w * h : 0;\n}\n\n/**\n * Exchange the placement with one of the widgets under it.\n *\n * The dragged widget takes the other's cell and the other takes the cell the\n * dragged widget came from. Each keeps as much of its own size as fits there -\n * that cell plus any free space adjacent to it - and neither ever grows.\n *\n * `from` is whatever the caller's layout says, so it is the caller that decides\n * what \"came from\" means. A pointer drag resolves every frame against the\n * arrangement the gesture started with, making it the cell the drag began at, and\n * keeping the result a pure function of where the pointer is; chaining frames off\n * each other instead would exchange with every widget swept over.\n * The slot the dragged widget is leaving is reserved for the displaced widget\n * while the dragged one is sized, so the two can never claim the same cells: the\n * result is overlap-free by construction, not by a follow-up check.\n */\nfunction exchangeWithCollision(\n layout: Layout,\n item: LayoutItem,\n collisions: LayoutItem[],\n from: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n // Nothing to trade if the widget has not actually left a slot behind - a\n // cross-board drop, where it never had one on this board.\n if (from.x === item.x && from.y === item.y) return null;\n\n // A drop that spans a boundary covers two widgets at once, and refusing those\n // frames would leave a band mid-drag where nothing is swapped at all: the\n // placeholder snaps back to the origin, then jumps to the far swap once the drop\n // clears the first widget. Trade with the one the drop covers most instead, so\n // the swap only ever changes which partner it is - never blinks away. Ties go to\n // the widget earlier in reading order, so the choice is deterministic. Exactly\n // one widget is ever displaced, whichever is picked.\n const candidates = collisions\n .filter((c) => !c.static)\n .map((c) => ({ c, area: overlapArea(item, c) }))\n .sort((p, q) => q.area - p.area || p.c.y - q.c.y || p.c.x - q.c.x)\n .map(({ c }) => c);\n\n for (const other of candidates) {\n const exchanged = exchangeWith(layout, item, other, from, desired, limits);\n if (exchanged) return exchanged;\n }\n return null;\n}\n\n/** One concrete two-widget exchange, or `null` if either side cannot fit. */\nfunction exchangeWith(\n layout: Layout,\n item: LayoutItem,\n other: LayoutItem,\n from: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n const rest = layout.filter((l) => l.i !== item.i && l.i !== other.i);\n // The slot being vacated, held back so the dragged widget cannot grow into the\n // space the displaced one is about to need. Ids are never compared here (the\n // scan works cell by cell), so this placeholder cannot clash with a real one.\n const originSlot: LayoutItem = {\n i: 'origin-slot-reservation',\n x: from.x,\n y: from.y,\n w: desired.w,\n h: desired.h,\n };\n\n const movedFit = maxFreeRectAt(\n [...rest, originSlot],\n { x: other.x, y: other.y },\n desired,\n limits,\n item,\n );\n if (!movedFit) return null;\n const moved: LayoutItem = {\n ...item,\n x: other.x,\n y: other.y,\n w: movedFit.w,\n h: movedFit.h,\n moved: true,\n };\n\n const displacedFit = maxFreeRectAt(\n [...rest, moved],\n { x: from.x, y: from.y },\n { w: other.w, h: other.h },\n limits,\n other,\n );\n if (!displacedFit) return null;\n const displaced: LayoutItem = {\n ...other,\n x: from.x,\n y: from.y,\n w: displacedFit.w,\n h: displacedFit.h,\n moved: true,\n };\n\n return layout.map((l) =>\n l.i === item.i ? moved : l.i === other.i ? displaced : l,\n );\n}\n\n/**\n * Build the resolver `moveElement` consults instead of reverting a blocked move,\n * or `undefined` for `'revert'` (and for an unset mode), which keeps the engine\n * on its original path with no added work.\n *\n * For an in-board drag, `'swap'` is an escalation ladder: exchange with one of\n * the widgets under the drop, else downscale at the drop cell, else revert. A\n * dense grid stays draggable that way - refusing everything that is not a clean\n * one-to-one trade would make the mode feel broken exactly where it is needed.\n * Cross-board callers pass `allowExchange: false`, which turns the same mode into\n * empty-anchor downscaling; the registry cancels the transfer if that resolution\n * cannot occupy the requested cell.\n */\nexport function createCollisionResolver(\n mode: CollisionMode | undefined,\n options: CollisionResolverOptions,\n): CollisionResolver | undefined {\n if (!mode || mode === 'revert') return undefined;\n\n const limits = { cols: options.cols, maxRows: options.maxRows };\n\n return ({ layout, item, collisions, from }) => {\n const others = layout.filter((l) => l.i !== item.i);\n const desired = options.desired ?? { w: item.w, h: item.h };\n\n if (mode === 'swap' && options.allowExchange !== false) {\n const exchanged = exchangeWithCollision(\n layout,\n item,\n collisions,\n from,\n desired,\n limits,\n );\n if (exchanged) return exchanged;\n }\n\n return downscaleInPlace(layout, item, others, desired, limits);\n };\n}\n\n/**\n * Whether a layout holds no overlapping pair. A resolution is only ever accepted\n * when this holds, so the specs assert it directly.\n */\nexport function isOverlapFree(layout: Layout): boolean {\n for (let i = 0; i < layout.length; i++) {\n for (let j = i + 1; j < layout.length; j++) {\n if (collides(layout[i]!, layout[j]!)) return false;\n }\n }\n return true;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collision-modes.js","names":[],"sources":["../../../../../src/components/layout/Board/grid-core/collision-modes.ts"],"sourcesContent":["/**\n * Collision resolution strategies for a grid that prevents collisions.\n *\n * Original UI Kit code (not vendored from react-grid-layout): the upstream\n * engine only ever reverts a blocked move.\n *\n * When `preventCollision` is on, `moveElement` refuses any placement that\n * overlaps an existing item and snaps the dragged item back. That is the right\n * default, but a free grid often wants the placement *resolved* instead of\n * refused - shrunk into whatever room is actually there, or exchanged with the\n * widget already sitting in the target slot. These strategies produce such a\n * resolution, and every resolution they return is overlap-free, so the caller's\n * own overlap guards keep working unchanged.\n */\n\nimport { collides } from './collision';\n\nimport type {\n CollisionMode,\n CollisionResolver,\n CollisionResolverOptions,\n Layout,\n LayoutItem,\n} from './types';\n\n/** Whether a single grid cell is free of every item in `others`. */\nfunction cellFree(others: Layout, x: number, y: number): boolean {\n for (let i = 0; i < others.length; i++) {\n const o = others[i];\n if (\n o !== undefined &&\n x >= o.x &&\n x < o.x + o.w &&\n y >= o.y &&\n y < o.y + o.h\n ) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * The largest rectangle anchored at `anchor` that fits without overlapping\n * `others`, growing rightward and downward only.\n *\n * Never larger than `desired` (a drag must never *upscale* a widget - growing\n * things is an explicit, opt-in operation like \"distribute evenly\", not a side\n * effect of moving them), never smaller than the item's own `minW`/`minH`, and\n * never past `cols` / `maxRows`. Among the candidates the largest-area rectangle\n * wins, breaking ties on width: a grid is read left to right, so a wide-and-flat\n * result is the less surprising of two equal-area fits.\n *\n * Returns `null` when not even the minimum size fits, which the callers treat as\n * \"no resolution\" and fall back to reverting.\n */\nexport function maxFreeRectAt(\n others: Layout,\n anchor: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n mins?: { minW?: number; minH?: number },\n): { w: number; h: number } | null {\n if (anchor.x < 0 || anchor.y < 0) return null;\n\n const minW = Math.max(1, mins?.minW ?? 1);\n const minH = Math.max(1, mins?.minH ?? 1);\n const maxRows = limits.maxRows ?? Infinity;\n const maxW = Math.min(desired.w, limits.cols - anchor.x);\n const maxH = Math.min(\n desired.h,\n Number.isFinite(maxRows) ? maxRows - anchor.y : desired.h,\n );\n\n if (maxW < minW || maxH < minH) return null;\n\n // Free height available in each column of the candidate band, measured down\n // from the anchor row and capped at the tallest useful height.\n const free: number[] = [];\n for (let dx = 0; dx < maxW; dx++) {\n let h = 0;\n while (h < maxH && cellFree(others, anchor.x + dx, anchor.y + h)) h++;\n free.push(h);\n // A column with no room at all caps every wider candidate, so stop early.\n if (h === 0) break;\n }\n\n let best: { w: number; h: number } | null = null;\n let bestArea = 0;\n let limit = maxH;\n for (let w = 1; w <= free.length; w++) {\n limit = Math.min(limit, free[w - 1]!);\n if (limit < minH) break;\n if (w < minW) continue;\n const area = w * limit;\n // `>=` so the widest of several equal-area fits wins: `w` only grows here, so\n // the last match is the widest one.\n if (area >= bestArea) {\n best = { w, h: limit };\n bestArea = area;\n }\n }\n\n return best;\n}\n\n/**\n * The cells beyond a pinned anchor that a drag could never ask for.\n *\n * `gridBounds` clamps a drag anchor to `cols - w` (and `maxRows - h`), which\n * assumes the widget keeps the size it started with. So when the blocker is to\n * the LEFT of the free room and that room is narrower than the widget, every\n * anchor a pointer can produce lands inside the blocker - and the mode whose\n * whole job is to shrink the widget into that room never gets offered it. The\n * drop just reverts. The mirror case has no such problem, because the anchor at\n * column 0 is always reachable: that asymmetry is why downscaling into room on\n * the left has always worked and room on the right has not. The row axis clamps\n * the same way, so a board with a finite `maxRows` has the same blind spot below\n * a blocker.\n *\n * Nothing is offered unless the anchor is sitting ON the limit, pinned against\n * the far edge with the pointer unable to push it further. An anchor short of the\n * limit is the pointer's own choice - every cell between it and the limit was\n * available to ask for - so a blocked drop there still just reverts, exactly as\n * before. Without that gate a widget dropped on an occupied cell would skip over\n * free cells the pointer could perfectly well have aimed at.\n *\n * A pinned anchor's span ends at the last row/column of the grid, so every cell\n * returned - and every rectangle that can be measured from one - lies inside the\n * footprint the widget is already covering.\n */\nfunction clampedOutAnchors(\n item: LayoutItem,\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): { x: number; y: number }[] {\n const maxRows = limits.maxRows ?? Infinity;\n const bounded = Number.isFinite(maxRows);\n const xLimit = Math.max(0, limits.cols - desired.w);\n const yLimit = bounded ? Math.max(0, maxRows - desired.h) : Infinity;\n\n const anchors: { x: number; y: number }[] = [];\n // Each axis is clamped on its own, so each recovers on its own: slide along\n // the one the limit actually pinned, never diagonally into open grid.\n if (item.x === xLimit) {\n const lastX = Math.min(item.x + desired.w - 1, limits.cols - 1);\n for (let x = item.x + 1; x <= lastX; x++) anchors.push({ x, y: item.y });\n }\n if (bounded && item.y === yLimit) {\n const lastY = Math.min(item.y + desired.h - 1, maxRows - 1);\n for (let y = item.y + 1; y <= lastY; y++) anchors.push({ x: item.x, y });\n }\n return anchors;\n}\n\n/**\n * Shrink the placement to the room actually available at the cell it was\n * dropped on, or - when that cell cannot take the widget at any size and the\n * anchor is pinned against the grid edge - at a cell the clamp hid from the\n * pointer (see `clampedOutAnchors`). The largest fit among those wins, so the\n * widget takes as much of the room it is already hovering as there is.\n */\nfunction downscaleInPlace(\n layout: Layout,\n item: LayoutItem,\n others: Layout,\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n const fitAt = (anchor: { x: number; y: number }) =>\n maxFreeRectAt(others, anchor, desired, limits, item);\n\n let anchor = { x: item.x, y: item.y };\n let fit = fitAt(anchor);\n\n if (!fit) {\n let bestArea = 0;\n for (const candidate of clampedOutAnchors(item, desired, limits)) {\n const candidateFit = fitAt(candidate);\n if (!candidateFit) continue;\n const area = candidateFit.w * candidateFit.h;\n // `>` keeps the first of several equal-area fits, and the scan runs in\n // reading order from the drop cell, so that is the closest one to it.\n if (area > bestArea) {\n bestArea = area;\n fit = candidateFit;\n anchor = candidate;\n }\n }\n }\n\n if (!fit) return null;\n // Nothing to resolve: the requested cell takes the requested size, so the\n // collision was not a sizing problem and reverting is still the honest answer.\n if (\n fit.w === item.w &&\n fit.h === item.h &&\n anchor.x === item.x &&\n anchor.y === item.y\n ) {\n return null;\n }\n\n return layout.map((l) =>\n l.i === item.i\n ? { ...l, x: anchor.x, y: anchor.y, w: fit!.w, h: fit!.h, moved: true }\n : l,\n );\n}\n\n/** Number of cells two items share. Zero when they do not overlap at all. */\nfunction overlapArea(a: LayoutItem, b: LayoutItem): number {\n const w = Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x);\n const h = Math.min(a.y + a.h, b.y + b.h) - Math.max(a.y, b.y);\n return w > 0 && h > 0 ? w * h : 0;\n}\n\n/**\n * Exchange the placement with one of the widgets under it.\n *\n * The dragged widget takes the other's cell and the other takes the cell the\n * dragged widget came from. Each keeps as much of its own size as fits there -\n * that cell plus any free space adjacent to it - and neither ever grows.\n *\n * `from` is whatever the caller's layout says, so it is the caller that decides\n * what \"came from\" means. A pointer drag resolves every frame against the\n * arrangement the gesture started with, making it the cell the drag began at, and\n * keeping the result a pure function of where the pointer is; chaining frames off\n * each other instead would exchange with every widget swept over.\n * The slot the dragged widget is leaving is reserved for the displaced widget\n * while the dragged one is sized, so the two can never claim the same cells: the\n * result is overlap-free by construction, not by a follow-up check.\n */\nfunction exchangeWithCollision(\n layout: Layout,\n item: LayoutItem,\n collisions: LayoutItem[],\n from: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n // Nothing to trade if the widget has not actually left a slot behind - a\n // cross-board drop, where it never had one on this board.\n if (from.x === item.x && from.y === item.y) return null;\n\n // A drop that spans a boundary covers two widgets at once, and refusing those\n // frames would leave a band mid-drag where nothing is swapped at all: the\n // placeholder snaps back to the origin, then jumps to the far swap once the drop\n // clears the first widget. Trade with the one the drop covers most instead, so\n // the swap only ever changes which partner it is - never blinks away. Ties go to\n // the widget earlier in reading order, so the choice is deterministic. Exactly\n // one widget is ever displaced, whichever is picked.\n const candidates = collisions\n .filter((c) => !c.static)\n .map((c) => ({ c, area: overlapArea(item, c) }))\n .sort((p, q) => q.area - p.area || p.c.y - q.c.y || p.c.x - q.c.x)\n .map(({ c }) => c);\n\n for (const other of candidates) {\n const exchanged = exchangeWith(layout, item, other, from, desired, limits);\n if (exchanged) return exchanged;\n }\n return null;\n}\n\n/** One concrete two-widget exchange, or `null` if either side cannot fit. */\nfunction exchangeWith(\n layout: Layout,\n item: LayoutItem,\n other: LayoutItem,\n from: { x: number; y: number },\n desired: { w: number; h: number },\n limits: { cols: number; maxRows?: number },\n): LayoutItem[] | null {\n const rest = layout.filter((l) => l.i !== item.i && l.i !== other.i);\n // The slot being vacated, held back so the dragged widget cannot grow into the\n // space the displaced one is about to need. Ids are never compared here (the\n // scan works cell by cell), so this placeholder cannot clash with a real one.\n const originSlot: LayoutItem = {\n i: 'origin-slot-reservation',\n x: from.x,\n y: from.y,\n w: desired.w,\n h: desired.h,\n };\n\n const movedFit = maxFreeRectAt(\n [...rest, originSlot],\n { x: other.x, y: other.y },\n desired,\n limits,\n item,\n );\n if (!movedFit) return null;\n const moved: LayoutItem = {\n ...item,\n x: other.x,\n y: other.y,\n w: movedFit.w,\n h: movedFit.h,\n moved: true,\n };\n\n const displacedFit = maxFreeRectAt(\n [...rest, moved],\n { x: from.x, y: from.y },\n { w: other.w, h: other.h },\n limits,\n other,\n );\n if (!displacedFit) return null;\n const displaced: LayoutItem = {\n ...other,\n x: from.x,\n y: from.y,\n w: displacedFit.w,\n h: displacedFit.h,\n moved: true,\n };\n\n return layout.map((l) =>\n l.i === item.i ? moved : l.i === other.i ? displaced : l,\n );\n}\n\n/**\n * Build the resolver `moveElement` consults instead of reverting a blocked move,\n * or `undefined` for `'revert'` (and for an unset mode), which keeps the engine\n * on its original path with no added work.\n *\n * For an in-board drag, `'swap'` is an escalation ladder: exchange with one of\n * the widgets under the drop, else downscale at the drop cell, else revert. A\n * dense grid stays draggable that way - refusing everything that is not a clean\n * one-to-one trade would make the mode feel broken exactly where it is needed.\n * Cross-board callers pass `allowExchange: false`, which turns the same mode into\n * downscaling at the drop cell - there is no slot on the destination to trade\n * back, and a transfer that cannot resolve is placed in a free cell rather than\n * refused, since a widget dropped somewhere has to end up somewhere.\n */\nexport function createCollisionResolver(\n mode: CollisionMode | undefined,\n options: CollisionResolverOptions,\n): CollisionResolver | undefined {\n if (!mode || mode === 'revert') return undefined;\n\n const limits = { cols: options.cols, maxRows: options.maxRows };\n\n return ({ layout, item, collisions, from }) => {\n const others = layout.filter((l) => l.i !== item.i);\n const desired = options.desired ?? { w: item.w, h: item.h };\n\n if (mode === 'swap' && options.allowExchange !== false) {\n const exchanged = exchangeWithCollision(\n layout,\n item,\n collisions,\n from,\n desired,\n limits,\n );\n if (exchanged) return exchanged;\n }\n\n return downscaleInPlace(layout, item, others, desired, limits);\n };\n}\n\n/**\n * Whether a layout holds no overlapping pair. A resolution is only ever accepted\n * when this holds, so the specs assert it directly.\n */\nexport function isOverlapFree(layout: Layout): boolean {\n for (let i = 0; i < layout.length; i++) {\n for (let j = i + 1; j < layout.length; j++) {\n if (collides(layout[i]!, layout[j]!)) return false;\n }\n }\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
import { collides, getFirstCollision } from "./collision.js";
|
|
3
3
|
import { sortLayoutItemsByColRow, sortLayoutItemsByRowCol } from "./sort.js";
|
|
4
4
|
import { bottom, cloneLayout, cloneLayoutItem, getStatics } from "./layout.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
//#region src/components/layout/Board/grid-core/constraints.ts
|
|
3
3
|
function clamp(value, min, max) {
|
|
4
4
|
return Math.max(min, Math.min(max, value));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
import { collides, getFirstCollision } from "./collision.js";
|
|
3
3
|
import { sortLayoutItemsByColRow, sortLayoutItemsByRowCol } from "./sort.js";
|
|
4
4
|
import { bottom, cloneLayout, cloneLayoutItem, getStatics } from "./layout.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
import { distributeEvenly, placeInFreeSlot } from "./grid-core/placement.js";
|
|
3
3
|
import { getCompactor, horizontalCompactor, noCompactor, verticalCompactor } from "./grid-core/compactors.js";
|
|
4
4
|
import { aspectRatio, boundedX, boundedY, containerBounds, gridBounds, maxSize, minMaxSize, minSize, snapToGrid } from "./grid-core/constraints.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.171.0 | Cube Dev Team */
|
|
2
2
|
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
3
|
import { cloneLayout } from "./grid-core/layout.js";
|
|
4
4
|
import { useCallback, useEffect, useRef, useState } from "react";
|