@cube-dev/ui-kit 0.141.0 → 0.142.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CHANGELOG.md +103 -0
- 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 +1 -1
- package/dist/components/GridProvider.js +1 -1
- package/dist/components/HiddenInput.js +1 -1
- package/dist/components/Root.js +1 -1
- package/dist/components/actions/Action/Action.js +1 -1
- package/dist/components/actions/Banner/Banner.js +1 -1
- package/dist/components/actions/Button/Button.js +17 -3
- package/dist/components/actions/Button/Button.js.map +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 +3 -4
- package/dist/components/actions/CommandMenu/CommandMenu.js.map +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 +18 -2
- package/dist/components/actions/ItemButton/ItemButton.js.map +1 -1
- package/dist/components/actions/Link/Link.js +1 -1
- package/dist/components/actions/Menu/Menu.js +3 -4
- package/dist/components/actions/Menu/Menu.js.map +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 +8 -5
- package/dist/components/actions/Menu/MenuTrigger.js.map +1 -1
- package/dist/components/actions/Menu/SubMenuTrigger.js +10 -7
- package/dist/components/actions/Menu/SubMenuTrigger.js.map +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/index.js +1 -1
- package/dist/components/actions/use-action.js +1 -1
- package/dist/components/actions/use-anchored-menu.js +4 -3
- package/dist/components/actions/use-anchored-menu.js.map +1 -1
- package/dist/components/actions/use-context-menu.js +4 -3
- package/dist/components/actions/use-context-menu.js.map +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/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/fields/Checkbox/Checkbox.js +1 -1
- package/dist/components/fields/Checkbox/CheckboxGroup.js +3 -3
- package/dist/components/fields/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/components/fields/Checkbox/context.js +1 -1
- package/dist/components/fields/ComboBox/ComboBox.js +11 -7
- package/dist/components/fields/ComboBox/ComboBox.js.map +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/TimeInput.js +1 -1
- package/dist/components/fields/DatePicker/intl.js +1 -1
- package/dist/components/fields/DatePicker/parseDate.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 -21
- package/dist/components/fields/FilterPicker/FilterPicker.js.map +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 +2 -1
- package/dist/components/fields/ListBox/ListBox.js.map +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 -21
- package/dist/components/fields/Picker/Picker.js.map +1 -1
- package/dist/components/fields/RadioGroup/Radio.js +1 -1
- package/dist/components/fields/RadioGroup/RadioGroup.js +3 -3
- package/dist/components/fields/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/components/fields/RadioGroup/context.js +1 -1
- package/dist/components/fields/SearchInput/SearchInput.js +1 -1
- package/dist/components/fields/Select/Select.js +10 -7
- 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/TextInputMapper/TextInputMapper.js +1 -1
- package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/dist/components/form/FieldWrapper/extract-field-wrapper-props.js +1 -1
- package/dist/components/form/Form/Field.js +1 -1
- package/dist/components/form/Form/Form.d.ts +1 -2
- package/dist/components/form/Form/Form.js +3 -3
- package/dist/components/form/Form/Form.js.map +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.d.ts +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 +3 -3
- package/dist/components/form/Label.js.map +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/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/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/FileTabs/FileTabs.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/RangeCalendar.js +1 -1
- package/dist/components/other/CloudLogo/CloudLogo.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.d.ts +1 -2
- package/dist/components/overlays/Dialog/Dialog.js +3 -3
- package/dist/components/overlays/Dialog/Dialog.js.map +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 +54 -8
- package/dist/components/overlays/Dialog/DialogTrigger.js.map +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.js +3 -3
- package/dist/components/overlays/Modal/Modal.js.map +1 -1
- package/dist/components/overlays/Modal/OpenTransitionContext.js +1 -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 +3 -3
- package/dist/components/overlays/Modal/Tray.js.map +1 -1
- package/dist/components/overlays/Modal/Underlay.js +1 -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.js +1 -1
- package/dist/components/overlays/Notifications/NotificationItem.js +1 -1
- package/dist/components/overlays/Notifications/OverlayContainer.js +1 -1
- package/dist/components/overlays/Notifications/OverlayProvider.js +1 -1
- package/dist/components/overlays/Notifications/PersistentNotificationsList.js +1 -1
- package/dist/components/overlays/Notifications/dismissed-storage.js +1 -1
- package/dist/components/overlays/Notifications/format-relative-time.js +1 -1
- package/dist/components/overlays/Notifications/index.js +1 -1
- package/dist/components/overlays/Notifications/use-notification-state.js +1 -1
- package/dist/components/overlays/Notifications/use-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-overlay-timers.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-notifications.js +1 -1
- package/dist/components/overlays/Notifications/use-persistent-state.js +1 -1
- package/dist/components/overlays/Notifications/use-toast-state.js +1 -1
- package/dist/components/overlays/Toast/ToastItem.js +1 -1
- package/dist/components/overlays/Toast/index.js +1 -1
- package/dist/components/overlays/Toast/useProgressToast.js +1 -1
- package/dist/components/overlays/Toast/useToast.js +1 -1
- package/dist/components/overlays/Tooltip/Tooltip.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipProvider.js +1 -1
- package/dist/components/overlays/Tooltip/TooltipTrigger.js +1 -1
- package/dist/components/overlays/Tooltip/context.js +1 -1
- package/dist/components/portal/Portal.js +1 -1
- package/dist/components/portal/PortalProvider.js +1 -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/themes.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/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/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/provider.js +1 -1
- package/dist/providers/TrackingProvider.js +1 -1
- package/dist/providers/navigationAdapter.default.js +1 -1
- package/dist/tokens/base.js +1 -1
- package/dist/tokens/colors.js +1 -1
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/layout.js +1 -1
- package/dist/tokens/palette.js +1 -1
- package/dist/tokens/shadows.js +1 -1
- package/dist/tokens/sizes.js +1 -1
- package/dist/tokens/spacing.js +1 -1
- package/dist/tokens/typography.js +1 -1
- package/dist/utils/ResizeSensor.js +1 -1
- package/dist/utils/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/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/useCombinedRefs.js +1 -1
- package/dist/utils/react/useControlledFocusVisible.js +1 -1
- package/dist/utils/react/useEventBus.js +26 -17
- package/dist/utils/react/useEventBus.js.map +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.d.ts +116 -0
- package/dist/utils/react/usePopoverSync.js +131 -11
- package/dist/utils/react/usePopoverSync.js.map +1 -1
- package/dist/utils/react/useQaProps.js +1 -1
- package/dist/utils/react/useViewportSize.js +1 -1
- package/dist/utils/react/wrapNodeIfPlain.js +1 -1
- package/dist/utils/selection.js +1 -1
- package/dist/utils/styles.js +1 -1
- package/dist/utils/tree.js +1 -1
- package/dist/utils/warnings.js +1 -1
- package/dist/version.js +2 -2
- package/docs/components/actions/Button.md +102 -24
- package/docs/components/actions/ItemButton.md +71 -34
- package/package.json +1 -1
|
@@ -1,9 +1,56 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
2
|
-
import { useEventBus } from "./useEventBus.js";
|
|
3
|
-
import { useEffect, useRef } from "react";
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.142.1 | Cube Dev Team */
|
|
2
|
+
import { EventBusContext, useEventBus } from "./useEventBus.js";
|
|
3
|
+
import { useCallback, useContext, useEffect, useRef } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/utils/react/usePopoverSync.ts
|
|
6
6
|
/**
|
|
7
|
+
* Module-level registry of currently open popovers. Lets us resolve the
|
|
8
|
+
* LOGICAL parent of an arbitrary element across portal boundaries.
|
|
9
|
+
*
|
|
10
|
+
* Popover content is portaled to a shared root (`document.body` by default —
|
|
11
|
+
* see `Overlay.tsx`), so a grandchild popover's trigger lives inside a
|
|
12
|
+
* sibling portal rather than physically inside its grandparent's container.
|
|
13
|
+
* A naive `container.contains(triggerEl)` check therefore misses the
|
|
14
|
+
* relationship and closes the grandparent — the bug that surfaces with 3+
|
|
15
|
+
* levels of `SubMenuTrigger` nesting.
|
|
16
|
+
*
|
|
17
|
+
* The registry stores closures over the host's refs so reads always see the
|
|
18
|
+
* latest `.current` value without forcing a re-register per render.
|
|
19
|
+
*/
|
|
20
|
+
const openPopovers = /* @__PURE__ */ new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Find the open popover whose container directly contains `target`. Returns
|
|
23
|
+
* `null` for elements that live outside every registered popover (e.g. a
|
|
24
|
+
* top-level trigger button rendered next to its overlay root).
|
|
25
|
+
*/
|
|
26
|
+
function findOwningPopover(target) {
|
|
27
|
+
if (!target) return null;
|
|
28
|
+
for (const entry of openPopovers) if (entry[1].getContainerEl()?.contains(target)) return entry;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns `true` when `target` is nested inside the overlay identified by
|
|
33
|
+
* `ancestorMenuId` — either as a direct DOM descendant of `ancestorContainer`
|
|
34
|
+
* or as a descendant of a chain of popovers whose triggers eventually land
|
|
35
|
+
* inside it. Used by `popover:open` peers to avoid closing themselves when a
|
|
36
|
+
* grand-child overlay opens through a portal.
|
|
37
|
+
*/
|
|
38
|
+
function isLogicalDescendantOf(target, ancestorMenuId, ancestorContainer) {
|
|
39
|
+
if (ancestorContainer && target && ancestorContainer.contains(target)) return true;
|
|
40
|
+
let cur = target;
|
|
41
|
+
const visited = /* @__PURE__ */ new Set();
|
|
42
|
+
while (cur) {
|
|
43
|
+
const owner = findOwningPopover(cur);
|
|
44
|
+
if (!owner) return false;
|
|
45
|
+
const [id, entry] = owner;
|
|
46
|
+
if (visited.has(id)) return false;
|
|
47
|
+
visited.add(id);
|
|
48
|
+
if (id === ancestorMenuId) return true;
|
|
49
|
+
cur = entry.getTriggerEl();
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
7
54
|
* Coordinates the "only one popover open at a time" invariant via the EventBus.
|
|
8
55
|
*
|
|
9
56
|
* - When `isOpen` flips `false -> true`, emits `popover:open` once.
|
|
@@ -26,7 +73,7 @@ import { useEffect, useRef } from "react";
|
|
|
26
73
|
* flips off, `wasOpenRef` is reset so re-enabling later still emits if
|
|
27
74
|
* `isOpen` is true at that moment.
|
|
28
75
|
*/
|
|
29
|
-
function usePopoverSync({ menuId, isOpen, onClose, enabled = true }) {
|
|
76
|
+
function usePopoverSync({ menuId, isOpen, onClose, enabled = true, triggerRef, containerRef, dismissOnInnerButtonPress = true, closeOnPeerOpen = true }) {
|
|
30
77
|
const { emit, on } = useEventBus();
|
|
31
78
|
const isOpenRef = useRef(isOpen);
|
|
32
79
|
useEffect(() => {
|
|
@@ -36,34 +83,107 @@ function usePopoverSync({ menuId, isOpen, onClose, enabled = true }) {
|
|
|
36
83
|
useEffect(() => {
|
|
37
84
|
onCloseRef.current = onClose;
|
|
38
85
|
}, [onClose]);
|
|
86
|
+
const containerRefRef = useRef(containerRef);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
containerRefRef.current = containerRef;
|
|
89
|
+
}, [containerRef]);
|
|
90
|
+
const triggerRefRef = useRef(triggerRef);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
triggerRefRef.current = triggerRef;
|
|
93
|
+
}, [triggerRef]);
|
|
39
94
|
useEffect(() => {
|
|
40
95
|
if (!enabled) return;
|
|
41
|
-
|
|
42
|
-
if (data.menuId
|
|
43
|
-
|
|
96
|
+
const offOpen = closeOnPeerOpen ? on("popover:open", (data) => {
|
|
97
|
+
if (data.menuId === menuId || !isOpenRef.current) return;
|
|
98
|
+
const container = containerRefRef.current?.current ?? null;
|
|
99
|
+
if (isLogicalDescendantOf(data.triggerEl, menuId, container)) return;
|
|
100
|
+
onCloseRef.current();
|
|
101
|
+
}) : null;
|
|
102
|
+
const offDismiss = dismissOnInnerButtonPress ? on("popover:dismiss-ancestor", (data) => {
|
|
103
|
+
if (!isOpenRef.current) return;
|
|
104
|
+
const container = containerRefRef.current?.current;
|
|
105
|
+
const from = data?.from;
|
|
106
|
+
if (!container || !from) return;
|
|
107
|
+
if (container.contains(from)) onCloseRef.current();
|
|
108
|
+
}) : null;
|
|
109
|
+
return () => {
|
|
110
|
+
offOpen?.();
|
|
111
|
+
offDismiss?.();
|
|
112
|
+
};
|
|
44
113
|
}, [
|
|
45
114
|
on,
|
|
46
115
|
menuId,
|
|
47
|
-
enabled
|
|
116
|
+
enabled,
|
|
117
|
+
dismissOnInnerButtonPress,
|
|
118
|
+
closeOnPeerOpen
|
|
48
119
|
]);
|
|
49
120
|
const wasOpenRef = useRef(false);
|
|
50
121
|
useEffect(() => {
|
|
51
122
|
if (!enabled) {
|
|
123
|
+
if (wasOpenRef.current) openPopovers.delete(menuId);
|
|
52
124
|
wasOpenRef.current = false;
|
|
53
125
|
return;
|
|
54
126
|
}
|
|
55
127
|
if (isOpen && !wasOpenRef.current) {
|
|
56
128
|
wasOpenRef.current = true;
|
|
57
|
-
|
|
58
|
-
|
|
129
|
+
openPopovers.set(menuId, {
|
|
130
|
+
getContainerEl: () => containerRefRef.current?.current ?? null,
|
|
131
|
+
getTriggerEl: () => triggerRefRef.current?.current ?? null
|
|
132
|
+
});
|
|
133
|
+
emit("popover:open", {
|
|
134
|
+
menuId,
|
|
135
|
+
triggerEl: triggerRefRef.current?.current ?? null
|
|
136
|
+
});
|
|
137
|
+
} else if (!isOpen && wasOpenRef.current) {
|
|
138
|
+
wasOpenRef.current = false;
|
|
139
|
+
openPopovers.delete(menuId);
|
|
140
|
+
}
|
|
59
141
|
}, [
|
|
60
142
|
isOpen,
|
|
61
143
|
emit,
|
|
62
144
|
menuId,
|
|
63
145
|
enabled
|
|
64
146
|
]);
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
return () => {
|
|
149
|
+
openPopovers.delete(menuId);
|
|
150
|
+
};
|
|
151
|
+
}, [menuId]);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Hook that returns a dispatcher to close the popover that contains a given
|
|
155
|
+
* DOM element. Used by `Button` / `ItemButton` to implement the default
|
|
156
|
+
* "press inside a popover closes the popover" behaviour. Custom (non-Cube)
|
|
157
|
+
* interactive controls can call this directly:
|
|
158
|
+
*
|
|
159
|
+
* ```tsx
|
|
160
|
+
* const dismiss = useDismissParentPopover();
|
|
161
|
+
* <MyCustomPressable onPress={(e) => { doThing(); dismiss(e.currentTarget); }} />
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* The actual dismiss is dispatched through the EventBus, which defers via
|
|
165
|
+
* `setTimeout(0)` — so the user's synchronous handler (and any React state
|
|
166
|
+
* updates it triggers) flushes BEFORE the popover closes. This is critical
|
|
167
|
+
* for the "open a hoisted modal from a popover footer" case: the modal
|
|
168
|
+
* mounts first, then the popover closes.
|
|
169
|
+
*
|
|
170
|
+
* Only popover-type containers (those that pass `dismissOnInnerButtonPress`
|
|
171
|
+
* as `true`, the default) react to the event. Modal/tray/fullscreen Dialog
|
|
172
|
+
* containers explicitly opt out so a Button inside their content does not
|
|
173
|
+
* auto-close them.
|
|
174
|
+
*
|
|
175
|
+
* When called outside an `EventBusProvider` (e.g. in unit tests that render
|
|
176
|
+
* a Button without wrapping in `<Root>`), the returned function is a no-op —
|
|
177
|
+
* the dismiss flow gracefully degrades rather than throwing.
|
|
178
|
+
*/
|
|
179
|
+
function useDismissParentPopover() {
|
|
180
|
+
const emit = useContext(EventBusContext)?.emit;
|
|
181
|
+
return useCallback((from) => {
|
|
182
|
+
if (!from || !emit) return;
|
|
183
|
+
emit("popover:dismiss-ancestor", { from });
|
|
184
|
+
}, [emit]);
|
|
65
185
|
}
|
|
66
186
|
|
|
67
187
|
//#endregion
|
|
68
|
-
export { usePopoverSync };
|
|
188
|
+
export { useDismissParentPopover, usePopoverSync };
|
|
69
189
|
//# sourceMappingURL=usePopoverSync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopoverSync.js","names":[],"sources":["../../../src/utils/react/usePopoverSync.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { useEventBus } from './useEventBus';\n\nexport interface UsePopoverSyncOptions {\n /** Stable identifier for this popover instance (typically a generateRandomId() memo). */\n menuId: string;\n /** Current open state of this popover. */\n isOpen: boolean;\n /** Called when another popover opens while this one is open. */\n onClose: () => void;\n /**\n * When `false`, this popover does not participate in the sync (no listening,\n * no emitting). Useful for \"dummy\" triggers that proxy a real one (see\n * `MenuTrigger`'s `isDummy`). Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/**\n * Coordinates the \"only one popover open at a time\" invariant via the EventBus.\n *\n * - When `isOpen` flips `false -> true`, emits `popover:open` once.\n * - While open, listens for peers' `popover:open` events and calls `onClose`.\n *\n * Implementation notes (ALL of these matter — losing any one re-introduces a\n * race that surfaces only under rapid trigger switching, which is hard to\n * reproduce in tests):\n *\n * 1. `isOpen` and `onClose` are read through refs inside the listener, so the\n * subscription effect's dep array does NOT include `isOpen`/`onClose`. This\n * keeps the listener identity stable across open/close transitions and\n * avoids the unsubscribe-emit-resubscribe window where an emit can be\n * delivered to a stale listener (or no listener).\n * 2. The emit fires only on the `false -> true` transition, gated by\n * `wasOpenRef`. A re-render where `isOpen` is still `true` must NOT\n * re-emit, otherwise it could re-trigger listeners on peers that just\n * opened in the same render flush.\n * 3. The `enabled` flag short-circuits both effects symmetrically. When it\n * flips off, `wasOpenRef` is reset so re-enabling later still emits if\n * `isOpen` is true at that moment.\n */\nexport function usePopoverSync({\n menuId,\n isOpen,\n onClose,\n enabled = true,\n}: UsePopoverSyncOptions): void {\n const { emit, on } = useEventBus();\n\n const isOpenRef = useRef(isOpen);\n useEffect(() => {\n isOpenRef.current = isOpen;\n }, [isOpen]);\n\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n useEffect(() => {\n if (!enabled) return;\n return on('popover:open', (data: { menuId: string }) => {\n if (data.menuId !== menuId && isOpenRef.current) {\n onCloseRef.current();\n }\n });\n }, [on, menuId, enabled]);\n\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (!enabled) {\n wasOpenRef.current = false;\n return;\n }\n if (isOpen && !wasOpenRef.current) {\n wasOpenRef.current = true;\n emit('popover:open', { menuId });\n } else if (!isOpen) {\n wasOpenRef.current = false;\n }\n }, [isOpen, emit, menuId, enabled]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,eAAe,EAC7B,QACA,QACA,SACA,UAAU,QACoB;CAC9B,MAAM,EAAE,MAAM,OAAO,aAAa;CAElC,MAAM,YAAY,OAAO,OAAO;AAChC,iBAAgB;AACd,YAAU,UAAU;IACnB,CAAC,OAAO,CAAC;CAEZ,MAAM,aAAa,OAAO,QAAQ;AAClC,iBAAgB;AACd,aAAW,UAAU;IACpB,CAAC,QAAQ,CAAC;AAEb,iBAAgB;AACd,MAAI,CAAC,QAAS;AACd,SAAO,GAAG,iBAAiB,SAA6B;AACtD,OAAI,KAAK,WAAW,UAAU,UAAU,QACtC,YAAW,SAAS;IAEtB;IACD;EAAC;EAAI;EAAQ;EAAQ,CAAC;CAEzB,MAAM,aAAa,OAAO,MAAM;AAChC,iBAAgB;AACd,MAAI,CAAC,SAAS;AACZ,cAAW,UAAU;AACrB;;AAEF,MAAI,UAAU,CAAC,WAAW,SAAS;AACjC,cAAW,UAAU;AACrB,QAAK,gBAAgB,EAAE,QAAQ,CAAC;aACvB,CAAC,OACV,YAAW,UAAU;IAEtB;EAAC;EAAQ;EAAM;EAAQ;EAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"usePopoverSync.js","names":[],"sources":["../../../src/utils/react/usePopoverSync.ts"],"sourcesContent":["import { RefObject, useCallback, useContext, useEffect, useRef } from 'react';\n\nimport { EventBusContext, useEventBus } from './useEventBus';\n\nexport interface UsePopoverSyncOptions {\n /** Stable identifier for this popover instance (typically a generateRandomId() memo). */\n menuId: string;\n /** Current open state of this popover. */\n isOpen: boolean;\n /** Called when another popover opens while this one is open. */\n onClose: () => void;\n /**\n * When `false`, this popover does not participate in the sync (no listening,\n * no emitting). Useful for \"dummy\" triggers that proxy a real one (see\n * `MenuTrigger`'s `isDummy`). Defaults to `true`.\n */\n enabled?: boolean;\n /**\n * Ref to the popover's trigger element. When provided, the element is\n * included in the `popover:open` emit payload so peers can detect whether\n * the new opener is nested inside their own overlay (and skip closing in\n * that case). Optional — omitting it preserves the legacy \"always close on\n * peer open\" behaviour.\n */\n triggerRef?: RefObject<HTMLElement | null>;\n /**\n * Ref to the overlay/container element that hosts this popover's content.\n * When provided, the listener performs a DOM `contains()` check on incoming\n * peer triggers: peers whose trigger lives inside this container are\n * considered nested children and do NOT close us.\n */\n containerRef?: RefObject<HTMLElement | null>;\n /**\n * Whether this overlay closes when a Button/ItemButton inside its container\n * is pressed. Defaults to `true` (popover semantics — popovers are transient\n * surfaces and any action inside them should dismiss them). Set to `false`\n * for modals/trays/fullscreen dialogs — buttons inside a Dialog should not\n * auto-close it. Requires `containerRef` to be set; without it the listener\n * has no way to determine whether the dispatching button is \"inside\" this\n * overlay and is effectively a no-op.\n */\n dismissOnInnerButtonPress?: boolean;\n /**\n * Whether this overlay closes when a peer popover opens. Defaults to `true`\n * (popover semantics — only one popover open at a time). Set to `false` for\n * modals/trays/fullscreen dialogs so a peer popover opening cannot bypass\n * the dialog's own `isDismissable` / `onClose` handling and yank it shut.\n *\n * The host still EMITS `popover:open` regardless of this flag, so opening a\n * modal/tray correctly dismisses any peer popover that was open before.\n */\n closeOnPeerOpen?: boolean;\n}\n\ninterface PopoverOpenPayload {\n menuId: string;\n triggerEl: Element | null;\n}\n\ninterface PopoverDismissAncestorPayload {\n /** The DOM node of the button that requested the dismiss. */\n from: Element | null;\n}\n\ninterface PopoverRegistryEntry {\n getContainerEl: () => Element | null;\n getTriggerEl: () => Element | null;\n}\n\n/**\n * Module-level registry of currently open popovers. Lets us resolve the\n * LOGICAL parent of an arbitrary element across portal boundaries.\n *\n * Popover content is portaled to a shared root (`document.body` by default —\n * see `Overlay.tsx`), so a grandchild popover's trigger lives inside a\n * sibling portal rather than physically inside its grandparent's container.\n * A naive `container.contains(triggerEl)` check therefore misses the\n * relationship and closes the grandparent — the bug that surfaces with 3+\n * levels of `SubMenuTrigger` nesting.\n *\n * The registry stores closures over the host's refs so reads always see the\n * latest `.current` value without forcing a re-register per render.\n */\nconst openPopovers = new Map<string, PopoverRegistryEntry>();\n\n/**\n * Find the open popover whose container directly contains `target`. Returns\n * `null` for elements that live outside every registered popover (e.g. a\n * top-level trigger button rendered next to its overlay root).\n */\nfunction findOwningPopover(\n target: Element | null,\n): [string, PopoverRegistryEntry] | null {\n if (!target) return null;\n for (const entry of openPopovers) {\n if (entry[1].getContainerEl()?.contains(target)) {\n return entry;\n }\n }\n return null;\n}\n\n/**\n * Returns `true` when `target` is nested inside the overlay identified by\n * `ancestorMenuId` — either as a direct DOM descendant of `ancestorContainer`\n * or as a descendant of a chain of popovers whose triggers eventually land\n * inside it. Used by `popover:open` peers to avoid closing themselves when a\n * grand-child overlay opens through a portal.\n */\nfunction isLogicalDescendantOf(\n target: Element | null,\n ancestorMenuId: string,\n ancestorContainer: Element | null,\n): boolean {\n if (ancestorContainer && target && ancestorContainer.contains(target)) {\n return true;\n }\n let cur: Element | null = target;\n const visited = new Set<string>();\n while (cur) {\n const owner = findOwningPopover(cur);\n if (!owner) return false;\n const [id, entry] = owner;\n if (visited.has(id)) return false;\n visited.add(id);\n if (id === ancestorMenuId) return true;\n cur = entry.getTriggerEl();\n }\n return false;\n}\n\n/**\n * Coordinates the \"only one popover open at a time\" invariant via the EventBus.\n *\n * - When `isOpen` flips `false -> true`, emits `popover:open` once.\n * - While open, listens for peers' `popover:open` events and calls `onClose`.\n *\n * Implementation notes (ALL of these matter — losing any one re-introduces a\n * race that surfaces only under rapid trigger switching, which is hard to\n * reproduce in tests):\n *\n * 1. `isOpen` and `onClose` are read through refs inside the listener, so the\n * subscription effect's dep array does NOT include `isOpen`/`onClose`. This\n * keeps the listener identity stable across open/close transitions and\n * avoids the unsubscribe-emit-resubscribe window where an emit can be\n * delivered to a stale listener (or no listener).\n * 2. The emit fires only on the `false -> true` transition, gated by\n * `wasOpenRef`. A re-render where `isOpen` is still `true` must NOT\n * re-emit, otherwise it could re-trigger listeners on peers that just\n * opened in the same render flush.\n * 3. The `enabled` flag short-circuits both effects symmetrically. When it\n * flips off, `wasOpenRef` is reset so re-enabling later still emits if\n * `isOpen` is true at that moment.\n */\nexport function usePopoverSync({\n menuId,\n isOpen,\n onClose,\n enabled = true,\n triggerRef,\n containerRef,\n dismissOnInnerButtonPress = true,\n closeOnPeerOpen = true,\n}: UsePopoverSyncOptions): void {\n const { emit, on } = useEventBus();\n\n const isOpenRef = useRef(isOpen);\n useEffect(() => {\n isOpenRef.current = isOpen;\n }, [isOpen]);\n\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n onCloseRef.current = onClose;\n }, [onClose]);\n\n // Track the latest containerRef via a stable ref-of-refs so the listener\n // never resubscribes when callers pass freshly-created ref wrappers across\n // renders. Same pattern as `onCloseRef` above — without this the listener's\n // effect would churn for any caller that doesn't memoize its refs.\n const containerRefRef = useRef(containerRef);\n useEffect(() => {\n containerRefRef.current = containerRef;\n }, [containerRef]);\n\n const triggerRefRef = useRef(triggerRef);\n useEffect(() => {\n triggerRefRef.current = triggerRef;\n }, [triggerRef]);\n\n useEffect(() => {\n if (!enabled) return;\n\n // `popover:open` listener — gated on `closeOnPeerOpen`. Modals/trays opt\n // out so a peer popover opening cannot bypass the dialog's\n // `isDismissable` / `onClose` handling and call `state.close()` directly.\n // Note: the EMIT side (lower in this hook) still fires regardless, so\n // opening a modal still correctly dismisses peer popovers.\n const offOpen = closeOnPeerOpen\n ? on('popover:open', (data: PopoverOpenPayload) => {\n if (data.menuId === menuId || !isOpenRef.current) return;\n const container = containerRefRef.current?.current ?? null;\n // Nested-popover guard: stay open when the opening peer's trigger is\n // a LOGICAL descendant of our overlay. Direct DOM containment only\n // covers the first level — for grand-child popovers the trigger lives\n // in a sibling portal, so we walk the registered popover chain back\n // up via each parent's trigger element. Without this, opening a\n // third-level `SubMenuTrigger` would close every ancestor menu.\n if (isLogicalDescendantOf(data.triggerEl, menuId, container)) return;\n onCloseRef.current();\n })\n : null;\n\n // `popover:dismiss-ancestor` is emitted by `Button` / `ItemButton` (and any\n // consumer using `useDismissParentPopover`) after their `onPress` runs.\n // Only popover-type overlays subscribe; modals/trays opt out via\n // `dismissOnInnerButtonPress: false` so a Button inside a Dialog content\n // does NOT auto-close the Dialog.\n const offDismiss = dismissOnInnerButtonPress\n ? on(\n 'popover:dismiss-ancestor',\n (data: PopoverDismissAncestorPayload) => {\n if (!isOpenRef.current) return;\n const container = containerRefRef.current?.current;\n const from = data?.from;\n // Require both a container and an originating element so we can do\n // the contains-check. Hosts without `containerRef` (e.g.\n // `use-anchored-menu`, `use-context-menu`) are silently no-op.\n if (!container || !from) return;\n if (container.contains(from)) onCloseRef.current();\n },\n )\n : null;\n\n return () => {\n offOpen?.();\n offDismiss?.();\n };\n }, [on, menuId, enabled, dismissOnInnerButtonPress, closeOnPeerOpen]);\n\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (!enabled) {\n if (wasOpenRef.current) {\n openPopovers.delete(menuId);\n }\n wasOpenRef.current = false;\n return;\n }\n if (isOpen && !wasOpenRef.current) {\n wasOpenRef.current = true;\n // Register BEFORE emitting so peers' listeners (deferred via the\n // bus's `setTimeout(0)`) can already see us in the registry when\n // they walk the logical chain.\n openPopovers.set(menuId, {\n getContainerEl: () => containerRefRef.current?.current ?? null,\n getTriggerEl: () => triggerRefRef.current?.current ?? null,\n });\n emit<PopoverOpenPayload>('popover:open', {\n menuId,\n triggerEl: triggerRefRef.current?.current ?? null,\n });\n } else if (!isOpen && wasOpenRef.current) {\n wasOpenRef.current = false;\n openPopovers.delete(menuId);\n }\n }, [isOpen, emit, menuId, enabled]);\n\n // Final cleanup on unmount: covers the case where a host unmounts while\n // still flagged open (e.g. a parent unmount tears down a child popover\n // before its close transition runs).\n useEffect(() => {\n return () => {\n openPopovers.delete(menuId);\n };\n }, [menuId]);\n}\n\n/**\n * Hook that returns a dispatcher to close the popover that contains a given\n * DOM element. Used by `Button` / `ItemButton` to implement the default\n * \"press inside a popover closes the popover\" behaviour. Custom (non-Cube)\n * interactive controls can call this directly:\n *\n * ```tsx\n * const dismiss = useDismissParentPopover();\n * <MyCustomPressable onPress={(e) => { doThing(); dismiss(e.currentTarget); }} />\n * ```\n *\n * The actual dismiss is dispatched through the EventBus, which defers via\n * `setTimeout(0)` — so the user's synchronous handler (and any React state\n * updates it triggers) flushes BEFORE the popover closes. This is critical\n * for the \"open a hoisted modal from a popover footer\" case: the modal\n * mounts first, then the popover closes.\n *\n * Only popover-type containers (those that pass `dismissOnInnerButtonPress`\n * as `true`, the default) react to the event. Modal/tray/fullscreen Dialog\n * containers explicitly opt out so a Button inside their content does not\n * auto-close them.\n *\n * When called outside an `EventBusProvider` (e.g. in unit tests that render\n * a Button without wrapping in `<Root>`), the returned function is a no-op —\n * the dismiss flow gracefully degrades rather than throwing.\n */\nexport function useDismissParentPopover() {\n // Read context defensively: `Button` / `ItemButton` use this hook\n // unconditionally, but tests (and standalone usages outside `<Root>`) may\n // mount them without an `EventBusProvider`. A throw would crash every\n // Button render in those cases.\n const bus = useContext(EventBusContext);\n const emit = bus?.emit;\n return useCallback(\n (from: Element | null) => {\n if (!from || !emit) return;\n emit<PopoverDismissAncestorPayload>('popover:dismiss-ancestor', { from });\n },\n [emit],\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmFA,MAAM,+BAAe,IAAI,KAAmC;;;;;;AAO5D,SAAS,kBACP,QACuC;AACvC,KAAI,CAAC,OAAQ,QAAO;AACpB,MAAK,MAAM,SAAS,aAClB,KAAI,MAAM,GAAG,gBAAgB,EAAE,SAAS,OAAO,CAC7C,QAAO;AAGX,QAAO;;;;;;;;;AAUT,SAAS,sBACP,QACA,gBACA,mBACS;AACT,KAAI,qBAAqB,UAAU,kBAAkB,SAAS,OAAO,CACnE,QAAO;CAET,IAAI,MAAsB;CAC1B,MAAM,0BAAU,IAAI,KAAa;AACjC,QAAO,KAAK;EACV,MAAM,QAAQ,kBAAkB,IAAI;AACpC,MAAI,CAAC,MAAO,QAAO;EACnB,MAAM,CAAC,IAAI,SAAS;AACpB,MAAI,QAAQ,IAAI,GAAG,CAAE,QAAO;AAC5B,UAAQ,IAAI,GAAG;AACf,MAAI,OAAO,eAAgB,QAAO;AAClC,QAAM,MAAM,cAAc;;AAE5B,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA0BT,SAAgB,eAAe,EAC7B,QACA,QACA,SACA,UAAU,MACV,YACA,cACA,4BAA4B,MAC5B,kBAAkB,QACY;CAC9B,MAAM,EAAE,MAAM,OAAO,aAAa;CAElC,MAAM,YAAY,OAAO,OAAO;AAChC,iBAAgB;AACd,YAAU,UAAU;IACnB,CAAC,OAAO,CAAC;CAEZ,MAAM,aAAa,OAAO,QAAQ;AAClC,iBAAgB;AACd,aAAW,UAAU;IACpB,CAAC,QAAQ,CAAC;CAMb,MAAM,kBAAkB,OAAO,aAAa;AAC5C,iBAAgB;AACd,kBAAgB,UAAU;IACzB,CAAC,aAAa,CAAC;CAElB,MAAM,gBAAgB,OAAO,WAAW;AACxC,iBAAgB;AACd,gBAAc,UAAU;IACvB,CAAC,WAAW,CAAC;AAEhB,iBAAgB;AACd,MAAI,CAAC,QAAS;EAOd,MAAM,UAAU,kBACZ,GAAG,iBAAiB,SAA6B;AAC/C,OAAI,KAAK,WAAW,UAAU,CAAC,UAAU,QAAS;GAClD,MAAM,YAAY,gBAAgB,SAAS,WAAW;AAOtD,OAAI,sBAAsB,KAAK,WAAW,QAAQ,UAAU,CAAE;AAC9D,cAAW,SAAS;IACpB,GACF;EAOJ,MAAM,aAAa,4BACf,GACE,6BACC,SAAwC;AACvC,OAAI,CAAC,UAAU,QAAS;GACxB,MAAM,YAAY,gBAAgB,SAAS;GAC3C,MAAM,OAAO,MAAM;AAInB,OAAI,CAAC,aAAa,CAAC,KAAM;AACzB,OAAI,UAAU,SAAS,KAAK,CAAE,YAAW,SAAS;IAErD,GACD;AAEJ,eAAa;AACX,cAAW;AACX,iBAAc;;IAEf;EAAC;EAAI;EAAQ;EAAS;EAA2B;EAAgB,CAAC;CAErE,MAAM,aAAa,OAAO,MAAM;AAChC,iBAAgB;AACd,MAAI,CAAC,SAAS;AACZ,OAAI,WAAW,QACb,cAAa,OAAO,OAAO;AAE7B,cAAW,UAAU;AACrB;;AAEF,MAAI,UAAU,CAAC,WAAW,SAAS;AACjC,cAAW,UAAU;AAIrB,gBAAa,IAAI,QAAQ;IACvB,sBAAsB,gBAAgB,SAAS,WAAW;IAC1D,oBAAoB,cAAc,SAAS,WAAW;IACvD,CAAC;AACF,QAAyB,gBAAgB;IACvC;IACA,WAAW,cAAc,SAAS,WAAW;IAC9C,CAAC;aACO,CAAC,UAAU,WAAW,SAAS;AACxC,cAAW,UAAU;AACrB,gBAAa,OAAO,OAAO;;IAE5B;EAAC;EAAQ;EAAM;EAAQ;EAAQ,CAAC;AAKnC,iBAAgB;AACd,eAAa;AACX,gBAAa,OAAO,OAAO;;IAE5B,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6Bd,SAAgB,0BAA0B;CAMxC,MAAM,OADM,WAAW,gBAAgB,EACrB;AAClB,QAAO,aACJ,SAAyB;AACxB,MAAI,CAAC,QAAQ,CAAC,KAAM;AACpB,OAAoC,4BAA4B,EAAE,MAAM,CAAC;IAE3E,CAAC,KAAK,CACP"}
|
package/dist/utils/selection.js
CHANGED
package/dist/utils/styles.js
CHANGED
package/dist/utils/tree.js
CHANGED
package/dist/utils/warnings.js
CHANGED
package/dist/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/** @license MIT | @cube-dev/ui-kit v0.
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.142.1 | Cube Dev Team */
|
|
2
2
|
//#region src/version.ts
|
|
3
|
-
const VERSION = "0.
|
|
3
|
+
const VERSION = "0.142.1";
|
|
4
4
|
const TASTY_VERSION = "2.6.2";
|
|
5
5
|
if (typeof window !== "undefined") {
|
|
6
6
|
const version = VERSION;
|
|
@@ -41,6 +41,7 @@ Supports [Base properties](../../BaseProperties.md)
|
|
|
41
41
|
Customises the root element of the component.
|
|
42
42
|
|
|
43
43
|
**Sub-elements:**
|
|
44
|
+
|
|
44
45
|
- `Icon` – wrapper around the leading icon
|
|
45
46
|
- `RightIcon` – wrapper around the trailing icon
|
|
46
47
|
- `Label` – the button text content
|
|
@@ -114,27 +115,35 @@ The `mods` prop accepts the following modifiers you can override:
|
|
|
114
115
|
```jsx
|
|
115
116
|
import { IconPlus } from '@tabler/icons-react';
|
|
116
117
|
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
{
|
|
119
|
+
/* Standard icon */
|
|
120
|
+
}
|
|
121
|
+
<Button icon={<IconPlus />} aria-label="Add item" />;
|
|
122
|
+
|
|
123
|
+
{
|
|
124
|
+
/* Empty slot (reserves space but shows nothing) */
|
|
125
|
+
}
|
|
126
|
+
<Button icon={true} aria-label="Empty slot" />;
|
|
127
|
+
|
|
128
|
+
{
|
|
129
|
+
/* Dynamic icon based on mods */
|
|
130
|
+
}
|
|
131
|
+
<Button
|
|
132
|
+
icon={({ loading }) => (loading ? <SpinnerIcon /> : <IconPlus />)}
|
|
126
133
|
aria-label="Dynamic icon"
|
|
127
134
|
>
|
|
128
135
|
Save
|
|
129
|
-
</Button
|
|
136
|
+
</Button>;
|
|
130
137
|
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
{
|
|
139
|
+
/* Return true from function for empty slot */
|
|
140
|
+
}
|
|
141
|
+
<Button
|
|
142
|
+
icon={({ selected }) => (selected ? <CheckIcon /> : true)}
|
|
134
143
|
aria-label="Conditional icon"
|
|
135
144
|
>
|
|
136
145
|
Option
|
|
137
|
-
</Button
|
|
146
|
+
</Button>;
|
|
138
147
|
```
|
|
139
148
|
|
|
140
149
|
### Link Button
|
|
@@ -159,21 +168,31 @@ import { IconPlus } from '@tabler/icons-react';
|
|
|
159
168
|
### With Tooltip
|
|
160
169
|
|
|
161
170
|
```jsx
|
|
162
|
-
{
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{
|
|
166
|
-
|
|
171
|
+
{
|
|
172
|
+
/* Simple tooltip text */
|
|
173
|
+
}
|
|
174
|
+
<Button icon={<IconPlus />} tooltip="Add new item" aria-label="Add" />;
|
|
175
|
+
|
|
176
|
+
{
|
|
177
|
+
/* Auto tooltip on overflow */
|
|
178
|
+
}
|
|
179
|
+
<Button tooltip={true} width="100px">
|
|
180
|
+
This text will be truncated
|
|
181
|
+
</Button>;
|
|
167
182
|
```
|
|
168
183
|
|
|
169
184
|
### Custom Size
|
|
170
185
|
|
|
171
186
|
```jsx
|
|
172
|
-
{
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{
|
|
176
|
-
|
|
187
|
+
{
|
|
188
|
+
/* Using a number (pixels) */
|
|
189
|
+
}
|
|
190
|
+
<Button size={64}>Large Custom</Button>;
|
|
191
|
+
|
|
192
|
+
{
|
|
193
|
+
/* Using a string multiplier */
|
|
194
|
+
}
|
|
195
|
+
<Button size="8x">8x Size</Button>;
|
|
177
196
|
```
|
|
178
197
|
|
|
179
198
|
## Accessibility
|
|
@@ -195,6 +214,65 @@ import { IconPlus } from '@tabler/icons-react';
|
|
|
195
214
|
- `aria-pressed` – Managed automatically when `isSelected` is used.
|
|
196
215
|
- Additional ARIA attributes supported by React Aria's `useButton`.
|
|
197
216
|
|
|
217
|
+
## Behaviour Inside Popovers
|
|
218
|
+
|
|
219
|
+
By default, pressing a `Button` inside an open popover (any overlay that
|
|
220
|
+
uses `usePopoverSync` — including the popovers rendered by `FilterPicker`,
|
|
221
|
+
`Picker`, `ComboBox`, `Select`, `MenuTrigger`, and
|
|
222
|
+
`DialogTrigger type="popover"`) **dismisses that popover** after the user's
|
|
223
|
+
`onPress` runs. This matches the common UX where a popover is a transient
|
|
224
|
+
surface: any action inside it should close it.
|
|
225
|
+
|
|
226
|
+
Modal / tray / fullscreen Dialogs are **not** affected — a Button inside a
|
|
227
|
+
modal Dialog does not auto-close it.
|
|
228
|
+
|
|
229
|
+
### Opt-outs
|
|
230
|
+
|
|
231
|
+
There are three ways to keep the popover open when a Button is pressed:
|
|
232
|
+
|
|
233
|
+
1. **Automatic for popover triggers.** Buttons that act as popover triggers
|
|
234
|
+
already carry `data-popover-trigger` (applied by `MenuTrigger`,
|
|
235
|
+
`DialogTrigger type="popover"`, `FilterPicker`, `Picker`, `ComboBox`,
|
|
236
|
+
`Select`). Modal-type `DialogTrigger` children are **not** marked, so they
|
|
237
|
+
correctly dismiss the parent popover and let the modal take over.
|
|
238
|
+
2. **Manual via `data-popover-keep`.** Add the attribute to the button
|
|
239
|
+
(toggle case) or to any ancestor element (subtree case — useful when a
|
|
240
|
+
custom inline editor inside a popover footer should not collapse on
|
|
241
|
+
every interaction):
|
|
242
|
+
|
|
243
|
+
```jsx
|
|
244
|
+
<Button data-popover-keep onPress={() => setMode((m) => !m)}>
|
|
245
|
+
Toggle
|
|
246
|
+
</Button>
|
|
247
|
+
|
|
248
|
+
<div data-popover-keep>
|
|
249
|
+
{/* All Buttons inside this wrapper opt out. */}
|
|
250
|
+
</div>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
3. **Custom non-Cube triggers.** Call `useDismissParentPopover()` yourself if
|
|
254
|
+
your control should dismiss the popover but does not extend `Button` /
|
|
255
|
+
`ItemButton`:
|
|
256
|
+
```jsx
|
|
257
|
+
const dismiss = useDismissParentPopover();
|
|
258
|
+
<MyCustomPressable
|
|
259
|
+
onPress={(e) => {
|
|
260
|
+
doThing();
|
|
261
|
+
dismiss(e.currentTarget);
|
|
262
|
+
}}
|
|
263
|
+
/>;
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Async `onPress`
|
|
267
|
+
|
|
268
|
+
The dismiss is dispatched via the EventBus, which defers with `setTimeout(0)`.
|
|
269
|
+
This means synchronous `onPress` handlers (and any React state updates they
|
|
270
|
+
trigger) flush **before** the popover closes — including the common case of
|
|
271
|
+
opening a hoisted modal via `useDialogContainer` from a popover footer (the
|
|
272
|
+
modal mounts first, then the popover closes behind it). If your `onPress` is
|
|
273
|
+
async and `await`s before opening another overlay, the popover will close
|
|
274
|
+
first and the new overlay will appear after — usually fine, but worth noting.
|
|
275
|
+
|
|
198
276
|
## Best Practices
|
|
199
277
|
|
|
200
278
|
1. **Do**: Provide a label for icon-only buttons
|
|
@@ -74,7 +74,7 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
74
74
|
### Sizes
|
|
75
75
|
|
|
76
76
|
- `xsmall` - Extra small size for compact interfaces
|
|
77
|
-
- `small` - Small size for dense layouts
|
|
77
|
+
- `small` - Small size for dense layouts
|
|
78
78
|
- `medium` - Default size for most use cases
|
|
79
79
|
- `large` - Large size for prominent actions
|
|
80
80
|
- `xlarge` - Extra large size for hero actions
|
|
@@ -84,15 +84,13 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
84
84
|
### Basic Button
|
|
85
85
|
|
|
86
86
|
```jsx
|
|
87
|
-
<ItemButton onPress={() => console.log('Clicked')}>
|
|
88
|
-
Click me
|
|
89
|
-
</ItemButton>
|
|
87
|
+
<ItemButton onPress={() => console.log('Clicked')}>Click me</ItemButton>
|
|
90
88
|
```
|
|
91
89
|
|
|
92
90
|
### Button with Icons
|
|
93
91
|
|
|
94
92
|
```jsx
|
|
95
|
-
<ItemButton
|
|
93
|
+
<ItemButton
|
|
96
94
|
icon={<IconFile />}
|
|
97
95
|
rightIcon={<IconExternalLink />}
|
|
98
96
|
onPress={handleOpen}
|
|
@@ -104,19 +102,13 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
104
102
|
### Link Button
|
|
105
103
|
|
|
106
104
|
```jsx
|
|
107
|
-
<ItemButton to="/docs">
|
|
108
|
-
Go to Documentation
|
|
109
|
-
</ItemButton>
|
|
105
|
+
<ItemButton to="/docs">Go to Documentation</ItemButton>
|
|
110
106
|
```
|
|
111
107
|
|
|
112
108
|
### Button with Hotkey
|
|
113
109
|
|
|
114
110
|
```jsx
|
|
115
|
-
<ItemButton
|
|
116
|
-
hotkeys="cmd+s"
|
|
117
|
-
onPress={handleSave}
|
|
118
|
-
type="primary"
|
|
119
|
-
>
|
|
111
|
+
<ItemButton hotkeys="cmd+s" onPress={handleSave} type="primary">
|
|
120
112
|
Save Document
|
|
121
113
|
</ItemButton>
|
|
122
114
|
```
|
|
@@ -124,11 +116,7 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
124
116
|
### Form Submit Button
|
|
125
117
|
|
|
126
118
|
```jsx
|
|
127
|
-
<ItemButton
|
|
128
|
-
htmlType="submit"
|
|
129
|
-
type="primary"
|
|
130
|
-
icon={<IconCheck />}
|
|
131
|
-
>
|
|
119
|
+
<ItemButton htmlType="submit" type="primary" icon={<IconCheck />}>
|
|
132
120
|
Submit Form
|
|
133
121
|
</ItemButton>
|
|
134
122
|
```
|
|
@@ -136,10 +124,7 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
136
124
|
### Button with Selection State
|
|
137
125
|
|
|
138
126
|
```jsx
|
|
139
|
-
<ItemButton
|
|
140
|
-
isSelected={isSelected}
|
|
141
|
-
onPress={() => setIsSelected(!isSelected)}
|
|
142
|
-
>
|
|
127
|
+
<ItemButton isSelected={isSelected} onPress={() => setIsSelected(!isSelected)}>
|
|
143
128
|
Toggle Selection
|
|
144
129
|
</ItemButton>
|
|
145
130
|
```
|
|
@@ -149,12 +134,20 @@ Inherits all modifiers from [Item](../content/Item.md) plus:
|
|
|
149
134
|
ItemButton supports inline actions that appear on the right side. Use the `ItemButton.Action` compound component for consistent styling:
|
|
150
135
|
|
|
151
136
|
```jsx
|
|
152
|
-
<ItemButton
|
|
137
|
+
<ItemButton
|
|
153
138
|
icon={<IconFile />}
|
|
154
139
|
actions={
|
|
155
140
|
<>
|
|
156
|
-
<ItemButton.Action
|
|
157
|
-
|
|
141
|
+
<ItemButton.Action
|
|
142
|
+
icon={<IconEdit />}
|
|
143
|
+
aria-label="Edit"
|
|
144
|
+
onPress={handleEdit}
|
|
145
|
+
/>
|
|
146
|
+
<ItemButton.Action
|
|
147
|
+
icon={<IconTrash />}
|
|
148
|
+
aria-label="Delete"
|
|
149
|
+
onPress={handleDelete}
|
|
150
|
+
/>
|
|
158
151
|
</>
|
|
159
152
|
}
|
|
160
153
|
onPress={handleOpen}
|
|
@@ -188,9 +181,41 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
188
181
|
- `aria-pressed` - Indicates toggle state for toggle buttons
|
|
189
182
|
- `role` - Automatically set to "button" or "link" based on props
|
|
190
183
|
|
|
184
|
+
## Behaviour Inside Popovers
|
|
185
|
+
|
|
186
|
+
Like `Button`, an `ItemButton` press inside an open popover **dismisses
|
|
187
|
+
that popover** by default — popovers are transient surfaces and any action
|
|
188
|
+
inside them should close them. Modals/trays/fullscreen Dialogs are not
|
|
189
|
+
affected.
|
|
190
|
+
|
|
191
|
+
### Opt-outs
|
|
192
|
+
|
|
193
|
+
- **Automatic for popover triggers** — `MenuTrigger`, `DialogTrigger
|
|
194
|
+
type="popover"`, and the picker components (`FilterPicker`, `Picker`,
|
|
195
|
+
`ComboBox`, `Select`) mark their trigger ItemButtons with
|
|
196
|
+
`data-popover-trigger` so they don't dismiss the popover they themselves
|
|
197
|
+
live in.
|
|
198
|
+
- **Manual via `data-popover-keep`** — add to the ItemButton (toggle) or
|
|
199
|
+
any ancestor (whole subtree):
|
|
200
|
+
```jsx
|
|
201
|
+
<ItemButton data-popover-keep onPress={() => setMode((m) => !m)}>
|
|
202
|
+
Toggle Mode
|
|
203
|
+
</ItemButton>
|
|
204
|
+
```
|
|
205
|
+
- **Custom non-Cube triggers** — call `useDismissParentPopover()` directly
|
|
206
|
+
if you build a control on top of something other than `Button` /
|
|
207
|
+
`ItemButton`.
|
|
208
|
+
|
|
209
|
+
The dismiss is dispatched via the EventBus, which defers with `setTimeout(0)`
|
|
210
|
+
— so synchronous `onPress` handlers (and the React state updates they
|
|
211
|
+
trigger) flush BEFORE the popover closes. This makes the "open a hoisted
|
|
212
|
+
modal from a popover footer" pattern work without flicker: the modal mounts
|
|
213
|
+
first, then the popover closes behind it.
|
|
214
|
+
|
|
191
215
|
## Best Practices
|
|
192
216
|
|
|
193
217
|
1. **Do**: Use clear, action-oriented text
|
|
218
|
+
|
|
194
219
|
```jsx
|
|
195
220
|
<ItemButton onPress={handleSave} type="primary">
|
|
196
221
|
Save Changes
|
|
@@ -198,6 +223,7 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
198
223
|
```
|
|
199
224
|
|
|
200
225
|
2. **Do**: Add hotkeys for frequently used actions
|
|
226
|
+
|
|
201
227
|
```jsx
|
|
202
228
|
<ItemButton hotkeys="cmd+s" onPress={handleSave}>
|
|
203
229
|
Save Document
|
|
@@ -205,6 +231,7 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
205
231
|
```
|
|
206
232
|
|
|
207
233
|
3. **Do**: Use appropriate button types for forms
|
|
234
|
+
|
|
208
235
|
```jsx
|
|
209
236
|
<ItemButton htmlType="submit" type="primary">
|
|
210
237
|
Submit Form
|
|
@@ -212,8 +239,9 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
212
239
|
```
|
|
213
240
|
|
|
214
241
|
4. **Do**: Use `ItemButton.Action` for inline actions
|
|
242
|
+
|
|
215
243
|
```jsx
|
|
216
|
-
<ItemButton
|
|
244
|
+
<ItemButton
|
|
217
245
|
icon={<IconFile />}
|
|
218
246
|
actions={
|
|
219
247
|
<>
|
|
@@ -228,15 +256,21 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
228
256
|
```
|
|
229
257
|
|
|
230
258
|
5. **Don't**: Use vague or unclear button text
|
|
259
|
+
|
|
231
260
|
```jsx
|
|
232
|
-
{
|
|
233
|
-
|
|
261
|
+
{
|
|
262
|
+
/* Avoid this - unclear what "OK" does */
|
|
263
|
+
}
|
|
264
|
+
<ItemButton onPress={handleAction}>OK</ItemButton>;
|
|
234
265
|
```
|
|
235
266
|
|
|
236
267
|
6. **Don't**: Add too many actions (limit to 2-3 for clarity)
|
|
268
|
+
|
|
237
269
|
```jsx
|
|
238
|
-
{
|
|
239
|
-
|
|
270
|
+
{
|
|
271
|
+
/* Avoid this - too many action buttons */
|
|
272
|
+
}
|
|
273
|
+
<ItemButton
|
|
240
274
|
actions={
|
|
241
275
|
<>
|
|
242
276
|
<ItemButton.Action icon={<IconEdit />} aria-label="Edit" />
|
|
@@ -247,13 +281,16 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
247
281
|
}
|
|
248
282
|
>
|
|
249
283
|
Button with too many actions
|
|
250
|
-
</ItemButton
|
|
284
|
+
</ItemButton>;
|
|
251
285
|
```
|
|
252
286
|
|
|
253
287
|
7. **Don't**: Overcrowd buttons with too many visual elements
|
|
288
|
+
|
|
254
289
|
```jsx
|
|
255
|
-
{
|
|
256
|
-
|
|
290
|
+
{
|
|
291
|
+
/* Avoid this - too many competing elements */
|
|
292
|
+
}
|
|
293
|
+
<ItemButton
|
|
257
294
|
icon={<IconA />}
|
|
258
295
|
rightIcon={<IconB />}
|
|
259
296
|
prefix="Pre"
|
|
@@ -261,7 +298,7 @@ Actions automatically inherit the parent button's `type` prop and adjust their s
|
|
|
261
298
|
description="Long description"
|
|
262
299
|
>
|
|
263
300
|
Overcrowded Button
|
|
264
|
-
</ItemButton
|
|
301
|
+
</ItemButton>;
|
|
265
302
|
```
|
|
266
303
|
|
|
267
304
|
8. **Accessibility**: Always ensure buttons have clear, descriptive labels, proper keyboard support, and provide `aria-label` for action buttons
|