@cube-dev/ui-kit 0.127.3 → 0.129.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/dist/CHANGELOG.md +40 -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 +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/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/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.d.ts +27 -0
- package/dist/components/content/Tree/Tree.js +265 -0
- package/dist/components/content/Tree/Tree.js.map +1 -0
- package/dist/components/content/Tree/TreeNode.js +107 -0
- package/dist/components/content/Tree/TreeNode.js.map +1 -0
- package/dist/components/content/Tree/index.d.ts +3 -0
- package/dist/components/content/Tree/styled.js +146 -0
- package/dist/components/content/Tree/styled.js.map +1 -0
- package/dist/components/content/Tree/tree-index.js +26 -0
- package/dist/components/content/Tree/tree-index.js.map +1 -0
- package/dist/components/content/Tree/types.d.ts +145 -0
- package/dist/components/content/Tree/use-checkbox-tree.js +231 -0
- package/dist/components/content/Tree/use-checkbox-tree.js.map +1 -0
- package/dist/components/content/Tree/use-load-data.js +75 -0
- package/dist/components/content/Tree/use-load-data.js.map +1 -0
- 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 +1 -1
- package/dist/components/fields/Checkbox/context.js +1 -1
- package/dist/components/fields/ComboBox/ComboBox.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/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.d.ts +3 -1
- package/dist/components/fields/FilterListBox/FilterListBox.js +115 -51
- package/dist/components/fields/FilterListBox/FilterListBox.js.map +1 -1
- package/dist/components/fields/FilterPicker/FilterPicker.d.ts +6 -0
- package/dist/components/fields/FilterPicker/FilterPicker.js +4 -2
- package/dist/components/fields/FilterPicker/FilterPicker.js.map +1 -1
- package/dist/components/fields/Input/Input.js +1 -1
- package/dist/components/fields/ListBox/ListBox.js +1 -1
- package/dist/components/fields/NumberInput/NumberInput.js +2 -2
- package/dist/components/fields/NumberInput/StepButton.js +1 -1
- package/dist/components/fields/PasswordInput/PasswordInput.js +2 -2
- package/dist/components/fields/Picker/Picker.js +1 -1
- package/dist/components/fields/RadioGroup/Radio.js +2 -2
- package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
- package/dist/components/fields/RadioGroup/context.js +1 -1
- package/dist/components/fields/SearchInput/SearchInput.js +2 -2
- package/dist/components/fields/Select/Select.js +1 -1
- package/dist/components/fields/Slider/Gradation.js +1 -1
- package/dist/components/fields/Slider/HueSlider.js +1 -1
- package/dist/components/fields/Slider/RangeSlider.js +1 -1
- package/dist/components/fields/Slider/Slider.js +1 -1
- package/dist/components/fields/Slider/SliderBase.js +1 -1
- package/dist/components/fields/Slider/SliderThumb.js +1 -1
- package/dist/components/fields/Slider/SliderTrack.js +1 -1
- package/dist/components/fields/Slider/elements.js +1 -1
- package/dist/components/fields/Slider/index.js +1 -1
- package/dist/components/fields/Switch/Switch.js +1 -1
- package/dist/components/fields/TextArea/TextArea.js +2 -2
- package/dist/components/fields/TextInput/TextInput.js +2 -2
- 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.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/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/EditableTitle.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/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.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.js +1 -1
- package/dist/components/overlays/Modal/OpenTransition.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 +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/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/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 +4 -1
- package/dist/index.js +5 -4
- 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/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/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.js +1 -1
- package/dist/utils/react/interactions.js +1 -1
- package/dist/utils/react/isTextOnly.js +1 -1
- package/dist/utils/react/mapProps.js +1 -1
- package/dist/utils/react/mergeProps.js +1 -1
- package/dist/utils/react/nullableValue.js +1 -1
- package/dist/utils/react/resolveIcon.js +1 -1
- package/dist/utils/react/sharedStore.js +1 -1
- package/dist/utils/react/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/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/content/Tree.md +299 -0
- package/docs/components/fields/FilterListBox.md +27 -17
- package/docs/components/fields/FilterPicker.md +58 -59
- package/docs/tasty/dsl.md +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.129.0 | Cube Dev Team */
|
|
2
|
+
import { _Item } from "../Item/Item.js";
|
|
3
|
+
import { Action } from "../../actions/Action/Action.js";
|
|
4
|
+
import { tasty } from "@tenphi/tasty";
|
|
5
|
+
|
|
6
|
+
//#region src/components/content/Tree/styled.ts
|
|
7
|
+
/**
|
|
8
|
+
* Tree root.
|
|
9
|
+
*
|
|
10
|
+
* Renders as `role="treegrid"` (set on `gridProps` from `useTree`).
|
|
11
|
+
*
|
|
12
|
+
* Tree-wide modifiers (set on `TreeElement` itself):
|
|
13
|
+
* - `has-height` — paired with `--tree-height` on inline `style`
|
|
14
|
+
* when the consumer passes a numeric `height` prop.
|
|
15
|
+
*/
|
|
16
|
+
const TreeElement = tasty({
|
|
17
|
+
qa: "Tree",
|
|
18
|
+
styles: {
|
|
19
|
+
display: "flex",
|
|
20
|
+
flow: "column",
|
|
21
|
+
width: "100%",
|
|
22
|
+
height: {
|
|
23
|
+
"": "auto",
|
|
24
|
+
"has-height": "fixed $tree-height"
|
|
25
|
+
},
|
|
26
|
+
flexGrow: {
|
|
27
|
+
"": 1,
|
|
28
|
+
"has-height": 0
|
|
29
|
+
},
|
|
30
|
+
flexShrink: {
|
|
31
|
+
"": 1,
|
|
32
|
+
"has-height": 0
|
|
33
|
+
},
|
|
34
|
+
flexBasis: {
|
|
35
|
+
"": 0,
|
|
36
|
+
"has-height": "auto"
|
|
37
|
+
},
|
|
38
|
+
minHeight: 0,
|
|
39
|
+
overflow: "auto",
|
|
40
|
+
scrollbar: "thin",
|
|
41
|
+
fill: "#clear",
|
|
42
|
+
color: "#dark",
|
|
43
|
+
transition: "theme",
|
|
44
|
+
outline: 0,
|
|
45
|
+
gap: "1bw",
|
|
46
|
+
padding: ".5x"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Per-row wrapper carrying `role="row"`, `rowProps` from
|
|
51
|
+
* `useTreeItem`, and the `--tree-level` CSS custom property used by
|
|
52
|
+
* `TreeRowItem` to compute its left padding.
|
|
53
|
+
*
|
|
54
|
+
* Has no visual styles of its own — the row's appearance lives on
|
|
55
|
+
* the inner `TreeRowItem` (which extends `Item`).
|
|
56
|
+
*/
|
|
57
|
+
const TreeNodeRow = tasty({
|
|
58
|
+
qa: "TreeRow",
|
|
59
|
+
styles: {
|
|
60
|
+
display: "block",
|
|
61
|
+
width: "100%",
|
|
62
|
+
outline: 0
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* The visible row: an `Item` extension that owns layout (full-width,
|
|
67
|
+
* tree indent) only. Color treatment is delegated to the
|
|
68
|
+
* `default.item` variant (see `DEFAULT_ITEM_STYLES` in
|
|
69
|
+
* `data/item-themes.ts`) so the Tree row matches the canonical Item
|
|
70
|
+
* look out of the box. `hovered` / `focused` / `pressed` mods are
|
|
71
|
+
* propagated from `TreeNode` because react-aria's treegrid uses a
|
|
72
|
+
* roving-tabindex "virtual focus" model and never sets those data
|
|
73
|
+
* attributes itself.
|
|
74
|
+
*/
|
|
75
|
+
const TreeRowItem = tasty(_Item, {
|
|
76
|
+
qa: "TreeItem",
|
|
77
|
+
type: "item",
|
|
78
|
+
size: "small",
|
|
79
|
+
as: "div",
|
|
80
|
+
styles: {
|
|
81
|
+
display: "grid",
|
|
82
|
+
width: "100%",
|
|
83
|
+
padding: "left ($tree-indent * 1x)",
|
|
84
|
+
"$tree-indent": "($tree-level, 0)",
|
|
85
|
+
cursor: {
|
|
86
|
+
"": "pointer",
|
|
87
|
+
disabled: "not-allowed"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Wraps the checkbox sitting in `Item`'s `prefix` slot. `Item`'s
|
|
93
|
+
* built-in Prefix padding collapses to `0` whenever there's an icon
|
|
94
|
+
* (which is always true for tree rows because the toggle/placeholder
|
|
95
|
+
* occupies the icon slot). We re-introduce a small inline gap on
|
|
96
|
+
* both sides so the checkbox isn't flush against the chevron and the
|
|
97
|
+
* title.
|
|
98
|
+
*/
|
|
99
|
+
const TreeNodeCheckboxWrapper = tasty({
|
|
100
|
+
qa: "TreeNodeCheckboxWrapper",
|
|
101
|
+
styles: {
|
|
102
|
+
display: "grid",
|
|
103
|
+
placeItems: "center",
|
|
104
|
+
placeContent: "center",
|
|
105
|
+
padding: "0 1x"
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const TOGGLE_BASE_STYLES = {
|
|
109
|
+
display: "grid",
|
|
110
|
+
placeItems: "center",
|
|
111
|
+
placeContent: "center",
|
|
112
|
+
width: "3x",
|
|
113
|
+
height: "3x",
|
|
114
|
+
radius: true,
|
|
115
|
+
transition: "theme"
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Chevron toggle button placed in `Item`'s `icon` slot. Spreads
|
|
119
|
+
* `expandButtonProps` from `useTreeItem` (an AriaButtonProps) and
|
|
120
|
+
* stops the press from bubbling to the row's selection handler via
|
|
121
|
+
* React Aria's PressResponder.
|
|
122
|
+
*/
|
|
123
|
+
const TreeNodeToggle = tasty(Action, {
|
|
124
|
+
qa: "TreeNodeToggle",
|
|
125
|
+
styles: {
|
|
126
|
+
...TOGGLE_BASE_STYLES,
|
|
127
|
+
color: {
|
|
128
|
+
"": "#dark-02",
|
|
129
|
+
":hover": "#dark"
|
|
130
|
+
},
|
|
131
|
+
fill: {
|
|
132
|
+
"": "#clear",
|
|
133
|
+
":hover": "#dark.04"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Non-interactive placeholder that occupies the same footprint as
|
|
139
|
+
* `TreeNodeToggle` so leaf rows visually align with siblings that
|
|
140
|
+
* have a chevron.
|
|
141
|
+
*/
|
|
142
|
+
const TreeNodeTogglePlaceholder = tasty({ styles: TOGGLE_BASE_STYLES });
|
|
143
|
+
|
|
144
|
+
//#endregion
|
|
145
|
+
export { TreeElement, TreeNodeCheckboxWrapper, TreeNodeRow, TreeNodeToggle, TreeNodeTogglePlaceholder, TreeRowItem };
|
|
146
|
+
//# sourceMappingURL=styled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styled.js","names":["Item"],"sources":["../../../../src/components/content/Tree/styled.ts"],"sourcesContent":["import { Styles, tasty } from '@tenphi/tasty';\n\nimport { Action } from '../../actions/Action/Action';\nimport { Item } from '../Item';\n\n/**\n * Tree root.\n *\n * Renders as `role=\"treegrid\"` (set on `gridProps` from `useTree`).\n *\n * Tree-wide modifiers (set on `TreeElement` itself):\n * - `has-height` — paired with `--tree-height` on inline `style`\n * when the consumer passes a numeric `height` prop.\n */\nexport const TreeElement = tasty({\n qa: 'Tree',\n styles: {\n display: 'flex',\n flow: 'column',\n width: '100%',\n height: { '': 'auto', 'has-height': 'fixed $tree-height' },\n flexGrow: { '': 1, 'has-height': 0 },\n flexShrink: { '': 1, 'has-height': 0 },\n flexBasis: { '': 0, 'has-height': 'auto' },\n minHeight: 0,\n overflow: 'auto',\n scrollbar: 'thin',\n fill: '#clear',\n color: '#dark',\n transition: 'theme',\n outline: 0,\n gap: '1bw',\n padding: '.5x',\n },\n});\n\n/**\n * Per-row wrapper carrying `role=\"row\"`, `rowProps` from\n * `useTreeItem`, and the `--tree-level` CSS custom property used by\n * `TreeRowItem` to compute its left padding.\n *\n * Has no visual styles of its own — the row's appearance lives on\n * the inner `TreeRowItem` (which extends `Item`).\n */\nexport const TreeNodeRow = tasty({\n qa: 'TreeRow',\n styles: {\n display: 'block',\n width: '100%',\n outline: 0,\n },\n});\n\n/**\n * The visible row: an `Item` extension that owns layout (full-width,\n * tree indent) only. Color treatment is delegated to the\n * `default.item` variant (see `DEFAULT_ITEM_STYLES` in\n * `data/item-themes.ts`) so the Tree row matches the canonical Item\n * look out of the box. `hovered` / `focused` / `pressed` mods are\n * propagated from `TreeNode` because react-aria's treegrid uses a\n * roving-tabindex \"virtual focus\" model and never sets those data\n * attributes itself.\n */\nexport const TreeRowItem = tasty(Item, {\n qa: 'TreeItem',\n type: 'item',\n size: 'small',\n as: 'div',\n styles: {\n /**\n * `Item` is `inline-grid` by default, which leaves baseline\n * descender space below the row inside the block-level\n * `TreeNodeRow` and visually inflates the gap between rows\n * past the intended `1bw`. Force block-level grid here.\n */\n display: 'grid',\n width: '100%',\n /**\n * Per-level indent. `$tree-indent` is a local token that reads\n * `--tree-level` (set inline on the parent `TreeNodeRow`) with a\n * `0` fallback. Using `padding` shorthand (instead of\n * `paddingInlineStart`) so it overrides `Item`'s default\n * `padding: 0` reliably — a longhand override on a shorthand\n * loses to it in the cascade when both are emitted from the same\n * declaration block.\n */\n padding: 'left ($tree-indent * 1x)',\n '$tree-indent': '($tree-level, 0)',\n cursor: {\n '': 'pointer',\n disabled: 'not-allowed',\n },\n },\n});\n\n/**\n * Wraps the checkbox sitting in `Item`'s `prefix` slot. `Item`'s\n * built-in Prefix padding collapses to `0` whenever there's an icon\n * (which is always true for tree rows because the toggle/placeholder\n * occupies the icon slot). We re-introduce a small inline gap on\n * both sides so the checkbox isn't flush against the chevron and the\n * title.\n */\nexport const TreeNodeCheckboxWrapper = tasty({\n qa: 'TreeNodeCheckboxWrapper',\n styles: {\n display: 'grid',\n placeItems: 'center',\n placeContent: 'center',\n padding: '0 1x',\n },\n});\n\nconst TOGGLE_BASE_STYLES: Styles = {\n display: 'grid',\n placeItems: 'center',\n placeContent: 'center',\n width: '3x',\n height: '3x',\n radius: true,\n transition: 'theme',\n};\n\n/**\n * Chevron toggle button placed in `Item`'s `icon` slot. Spreads\n * `expandButtonProps` from `useTreeItem` (an AriaButtonProps) and\n * stops the press from bubbling to the row's selection handler via\n * React Aria's PressResponder.\n */\nexport const TreeNodeToggle = tasty(Action, {\n qa: 'TreeNodeToggle',\n styles: {\n ...TOGGLE_BASE_STYLES,\n color: { '': '#dark-02', ':hover': '#dark' },\n fill: { '': '#clear', ':hover': '#dark.04' },\n },\n});\n\n/**\n * Non-interactive placeholder that occupies the same footprint as\n * `TreeNodeToggle` so leaf rows visually align with siblings that\n * have a chevron.\n */\nexport const TreeNodeTogglePlaceholder = tasty({\n styles: TOGGLE_BASE_STYLES,\n});\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,cAAc,MAAM;CAC/B,IAAI;CACJ,QAAQ;EACN,SAAS;EACT,MAAM;EACN,OAAO;EACP,QAAQ;GAAE,IAAI;GAAQ,cAAc;GAAsB;EAC1D,UAAU;GAAE,IAAI;GAAG,cAAc;GAAG;EACpC,YAAY;GAAE,IAAI;GAAG,cAAc;GAAG;EACtC,WAAW;GAAE,IAAI;GAAG,cAAc;GAAQ;EAC1C,WAAW;EACX,UAAU;EACV,WAAW;EACX,MAAM;EACN,OAAO;EACP,YAAY;EACZ,SAAS;EACT,KAAK;EACL,SAAS;EACV;CACF,CAAC;;;;;;;;;AAUF,MAAa,cAAc,MAAM;CAC/B,IAAI;CACJ,QAAQ;EACN,SAAS;EACT,OAAO;EACP,SAAS;EACV;CACF,CAAC;;;;;;;;;;;AAYF,MAAa,cAAc,MAAMA,OAAM;CACrC,IAAI;CACJ,MAAM;CACN,MAAM;CACN,IAAI;CACJ,QAAQ;EAON,SAAS;EACT,OAAO;EAUP,SAAS;EACT,gBAAgB;EAChB,QAAQ;GACN,IAAI;GACJ,UAAU;GACX;EACF;CACF,CAAC;;;;;;;;;AAUF,MAAa,0BAA0B,MAAM;CAC3C,IAAI;CACJ,QAAQ;EACN,SAAS;EACT,YAAY;EACZ,cAAc;EACd,SAAS;EACV;CACF,CAAC;AAEF,MAAM,qBAA6B;CACjC,SAAS;CACT,YAAY;CACZ,cAAc;CACd,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,YAAY;CACb;;;;;;;AAQD,MAAa,iBAAiB,MAAM,QAAQ;CAC1C,IAAI;CACJ,QAAQ;EACN,GAAG;EACH,OAAO;GAAE,IAAI;GAAY,UAAU;GAAS;EAC5C,MAAM;GAAE,IAAI;GAAU,UAAU;GAAY;EAC7C;CACF,CAAC;;;;;;AAOF,MAAa,4BAA4B,MAAM,EAC7C,QAAQ,oBACT,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.129.0 | Cube Dev Team */
|
|
2
|
+
//#region src/components/content/Tree/tree-index.ts
|
|
3
|
+
function buildTreeIndex(treeData) {
|
|
4
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
5
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
6
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
7
|
+
const visit = (nodes, parent) => {
|
|
8
|
+
for (const node of nodes) {
|
|
9
|
+
byKey.set(node.key, node);
|
|
10
|
+
parentOf.set(node.key, parent);
|
|
11
|
+
const childKeys = (node.children ?? []).map((c) => c.key);
|
|
12
|
+
childrenOf.set(node.key, childKeys);
|
|
13
|
+
if (node.children) visit(node.children, node.key);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
visit(treeData, null);
|
|
17
|
+
return {
|
|
18
|
+
byKey,
|
|
19
|
+
parentOf,
|
|
20
|
+
childrenOf
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { buildTreeIndex };
|
|
26
|
+
//# sourceMappingURL=tree-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-index.js","names":[],"sources":["../../../../src/components/content/Tree/tree-index.ts"],"sourcesContent":["import type { CubeTreeNodeData } from './types';\n\n/**\n * Map of `key -> { node, parentKey, childKeys }` for fast cascading lookups.\n *\n * Built from the public `treeData` rather than from React Stately's\n * collection, because we need the consumer's original (controlled)\n * shape to derive parent/child relationships and to call back with the\n * actual `node` objects.\n *\n * Shared between `Tree.tsx` (for `nodesByKey` / `parentOf`) and\n * `useCheckboxTree` (cascading checked state) so a single tree walk\n * powers all three maps.\n */\nexport interface TreeIndex {\n byKey: Map<string, CubeTreeNodeData>;\n parentOf: Map<string, string | null>;\n childrenOf: Map<string, string[]>;\n}\n\nexport function buildTreeIndex(treeData: CubeTreeNodeData[]): TreeIndex {\n const byKey = new Map<string, CubeTreeNodeData>();\n const parentOf = new Map<string, string | null>();\n const childrenOf = new Map<string, string[]>();\n\n const visit = (nodes: CubeTreeNodeData[], parent: string | null) => {\n for (const node of nodes) {\n byKey.set(node.key, node);\n parentOf.set(node.key, parent);\n const childKeys = (node.children ?? []).map((c) => c.key);\n childrenOf.set(node.key, childKeys);\n if (node.children) {\n visit(node.children, node.key);\n }\n }\n };\n\n visit(treeData, null);\n\n return { byKey, parentOf, childrenOf };\n}\n"],"mappings":";;AAoBA,SAAgB,eAAe,UAAyC;CACtE,MAAM,wBAAQ,IAAI,KAA+B;CACjD,MAAM,2BAAW,IAAI,KAA4B;CACjD,MAAM,6BAAa,IAAI,KAAuB;CAE9C,MAAM,SAAS,OAA2B,WAA0B;AAClE,OAAK,MAAM,QAAQ,OAAO;AACxB,SAAM,IAAI,KAAK,KAAK,KAAK;AACzB,YAAS,IAAI,KAAK,KAAK,OAAO;GAC9B,MAAM,aAAa,KAAK,YAAY,EAAE,EAAE,KAAK,MAAM,EAAE,IAAI;AACzD,cAAW,IAAI,KAAK,KAAK,UAAU;AACnC,OAAI,KAAK,SACP,OAAM,KAAK,UAAU,KAAK,IAAI;;;AAKpC,OAAM,UAAU,KAAK;AAErB,QAAO;EAAE;EAAO;EAAU;EAAY"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
|
|
2
|
+
import { BaseProps, OuterStyleProps, Styles } from "@tenphi/tasty";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { Key as Key$1 } from "@react-types/shared";
|
|
5
|
+
|
|
6
|
+
//#region src/components/content/Tree/types.d.ts
|
|
7
|
+
/** Selection cardinality, mirroring React Aria/Stately's `selectionMode`. */
|
|
8
|
+
type TreeSelectionMode = 'none' | 'single' | 'multiple';
|
|
9
|
+
/**
|
|
10
|
+
* A single node in the `treeData` array.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors AntD's `DataNode` shape but renames boolean flags to the
|
|
13
|
+
* `is*` convention used throughout `@cube-dev/ui-kit`.
|
|
14
|
+
*/
|
|
15
|
+
interface CubeTreeNodeData {
|
|
16
|
+
/** Unique identifier of the node. */
|
|
17
|
+
key: string;
|
|
18
|
+
/** Visible label (any `ReactNode`). */
|
|
19
|
+
title: ReactNode;
|
|
20
|
+
/** Children. Pass `undefined` together with `isLeaf={false}` for lazy nodes. */
|
|
21
|
+
children?: CubeTreeNodeData[];
|
|
22
|
+
/** Force leaf rendering (no expand toggle, no `loadData` call). */
|
|
23
|
+
isLeaf?: boolean;
|
|
24
|
+
/** Disable interactions on this row (focus / select / expand / check). */
|
|
25
|
+
isDisabled?: boolean;
|
|
26
|
+
/** Disable only the checkbox of this row. */
|
|
27
|
+
isCheckboxDisabled?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Per-node `isCheckable` override.
|
|
30
|
+
*
|
|
31
|
+
* - `undefined` (default): inherits the tree-level `isCheckable`.
|
|
32
|
+
* - `false`: hide the checkbox for this row even when the tree is `isCheckable`.
|
|
33
|
+
*/
|
|
34
|
+
isCheckable?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Info passed as the second argument to `onCheck`. */
|
|
37
|
+
interface TreeOnCheckInfo {
|
|
38
|
+
/** Whether the toggled node ended up checked. */
|
|
39
|
+
checked: boolean;
|
|
40
|
+
/** The toggled node. */
|
|
41
|
+
node: CubeTreeNodeData;
|
|
42
|
+
/** All currently checked nodes (flat). */
|
|
43
|
+
checkedNodes: CubeTreeNodeData[];
|
|
44
|
+
/** Keys of nodes in indeterminate state. */
|
|
45
|
+
halfCheckedKeys: Key$1[];
|
|
46
|
+
}
|
|
47
|
+
/** Info passed as the second argument to `onExpand`. */
|
|
48
|
+
interface TreeOnExpandInfo {
|
|
49
|
+
/** Whether the toggled node ended up expanded. */
|
|
50
|
+
expanded: boolean;
|
|
51
|
+
/** The toggled node. */
|
|
52
|
+
node: CubeTreeNodeData;
|
|
53
|
+
}
|
|
54
|
+
/** Info passed as the second argument to `onSelect`. */
|
|
55
|
+
interface TreeOnSelectInfo {
|
|
56
|
+
/** Whether the toggled node ended up selected. */
|
|
57
|
+
selected: boolean;
|
|
58
|
+
/** The toggled node. */
|
|
59
|
+
node: CubeTreeNodeData;
|
|
60
|
+
/** All currently selected nodes (flat). */
|
|
61
|
+
selectedNodes: CubeTreeNodeData[];
|
|
62
|
+
}
|
|
63
|
+
/** Argument shape for the `loadData` callback. */
|
|
64
|
+
interface TreeLoadDataNode {
|
|
65
|
+
key: Key$1;
|
|
66
|
+
children?: CubeTreeNodeData[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Public props for the `Tree` component.
|
|
70
|
+
*
|
|
71
|
+
* Designed to be a drop-in (modulo `is*` renames) for the AntD `Tree`
|
|
72
|
+
* `treeData` API, scoped to the v1 feature set.
|
|
73
|
+
*/
|
|
74
|
+
interface CubeTreeProps extends BaseProps, OuterStyleProps {
|
|
75
|
+
/** Hierarchical data describing the tree. */
|
|
76
|
+
treeData: CubeTreeNodeData[];
|
|
77
|
+
/** Render a checkbox in front of every (eligible) row. */
|
|
78
|
+
isCheckable?: boolean;
|
|
79
|
+
/** Allow row selection. Sugar for `selectionMode="none"` when `false`. */
|
|
80
|
+
isSelectable?: boolean;
|
|
81
|
+
/** Selection cardinality. Defaults to `'single'`. */
|
|
82
|
+
selectionMode?: TreeSelectionMode;
|
|
83
|
+
/** Disable the entire tree. */
|
|
84
|
+
isDisabled?: boolean;
|
|
85
|
+
/** Default expanded keys (uncontrolled). */
|
|
86
|
+
defaultExpandedKeys?: string[];
|
|
87
|
+
/** Controlled expanded keys. */
|
|
88
|
+
expandedKeys?: string[];
|
|
89
|
+
/**
|
|
90
|
+
* Auto-expand parents of currently expanded keys.
|
|
91
|
+
*
|
|
92
|
+
* Useful while filtering: passing matched leaf keys with this flag will
|
|
93
|
+
* keep their parents expanded as well.
|
|
94
|
+
*/
|
|
95
|
+
autoExpandParent?: boolean;
|
|
96
|
+
/** Default checked keys (uncontrolled). */
|
|
97
|
+
defaultCheckedKeys?: string[];
|
|
98
|
+
/**
|
|
99
|
+
* Controlled checked keys.
|
|
100
|
+
*
|
|
101
|
+
* Accepts either an array of keys or AntD's `{ checked, halfChecked }` shape.
|
|
102
|
+
*/
|
|
103
|
+
checkedKeys?: string[] | {
|
|
104
|
+
checked: string[];
|
|
105
|
+
halfChecked?: string[];
|
|
106
|
+
};
|
|
107
|
+
/** Default selected keys (uncontrolled). */
|
|
108
|
+
defaultSelectedKeys?: string[];
|
|
109
|
+
/** Controlled selected keys. */
|
|
110
|
+
selectedKeys?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Fixed height in pixels. When omitted, the tree fills the available
|
|
113
|
+
* vertical space and scrolls internally.
|
|
114
|
+
*/
|
|
115
|
+
height?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Async loader called the first time a non-leaf node with no `children`
|
|
118
|
+
* is expanded. The consumer is expected to merge new children into
|
|
119
|
+
* `treeData` (typical AntD pattern).
|
|
120
|
+
*/
|
|
121
|
+
loadData?: (node: TreeLoadDataNode) => Promise<void>;
|
|
122
|
+
/** Called when a node is expanded or collapsed. */
|
|
123
|
+
onExpand?: (expandedKeys: Key$1[], info: TreeOnExpandInfo) => void;
|
|
124
|
+
/**
|
|
125
|
+
* Called when a node is checked or unchecked.
|
|
126
|
+
*
|
|
127
|
+
* The first argument is `Key[]` by default; pass `checkedKeys` as
|
|
128
|
+
* `{ checked, halfChecked }` to receive the same shape back.
|
|
129
|
+
*/
|
|
130
|
+
onCheck?: (checked: Key$1[] | {
|
|
131
|
+
checked: Key$1[];
|
|
132
|
+
halfChecked: Key$1[];
|
|
133
|
+
}, info: TreeOnCheckInfo) => void;
|
|
134
|
+
/** Called when row selection changes. */
|
|
135
|
+
onSelect?: (selectedKeys: Key$1[], info: TreeOnSelectInfo) => void;
|
|
136
|
+
/** Override styles for `[data-element="Row"]` (per-row root). */
|
|
137
|
+
rowStyles?: Styles;
|
|
138
|
+
/** Accessible label for the tree. Defaults to `"Tree"`. */
|
|
139
|
+
ariaLabel?: string;
|
|
140
|
+
/** QA selector. */
|
|
141
|
+
qa?: string;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { CubeTreeNodeData, CubeTreeProps, TreeLoadDataNode, TreeOnCheckInfo, TreeOnExpandInfo, TreeOnSelectInfo, TreeSelectionMode };
|
|
145
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.129.0 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/content/Tree/use-checkbox-tree.ts
|
|
6
|
+
/**
|
|
7
|
+
* Returns whether a node should be checkable (i.e. clicking the
|
|
8
|
+
* checkbox should affect it).
|
|
9
|
+
*
|
|
10
|
+
* Skips:
|
|
11
|
+
* - explicitly disabled nodes (`isDisabled === true`)
|
|
12
|
+
* - explicitly disabled checkboxes (`isCheckboxDisabled === true`)
|
|
13
|
+
* - nodes that opted out via `isCheckable === false`
|
|
14
|
+
*/
|
|
15
|
+
function isNodeEligible(node) {
|
|
16
|
+
if (!node) return false;
|
|
17
|
+
if (node.isDisabled) return false;
|
|
18
|
+
if (node.isCheckboxDisabled) return false;
|
|
19
|
+
if (node.isCheckable === false) return false;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Recursively walk a subtree bottom-up, deriving which nodes are fully
|
|
24
|
+
* checked vs half-checked. Mutates `checked` and `half` in place.
|
|
25
|
+
*/
|
|
26
|
+
function deriveCheckedState(node, index, checked, half) {
|
|
27
|
+
const childKeys = index.childrenOf.get(node.key) ?? [];
|
|
28
|
+
if (childKeys.length === 0) {
|
|
29
|
+
const eligible = isNodeEligible(node);
|
|
30
|
+
const isChecked = checked.has(node.key);
|
|
31
|
+
return {
|
|
32
|
+
allChecked: !eligible || isChecked,
|
|
33
|
+
anyChecked: isChecked,
|
|
34
|
+
anyEligible: eligible
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
let allChecked = true;
|
|
38
|
+
let anyChecked = false;
|
|
39
|
+
let anyEligible = false;
|
|
40
|
+
for (const childKey of childKeys) {
|
|
41
|
+
const child = index.byKey.get(childKey);
|
|
42
|
+
if (!child) continue;
|
|
43
|
+
const r = deriveCheckedState(child, index, checked, half);
|
|
44
|
+
if (r.anyEligible) anyEligible = true;
|
|
45
|
+
if (!r.allChecked) allChecked = false;
|
|
46
|
+
if (r.anyChecked) anyChecked = true;
|
|
47
|
+
}
|
|
48
|
+
const eligible = isNodeEligible(node);
|
|
49
|
+
if (!anyEligible) half.delete(node.key);
|
|
50
|
+
else if (allChecked) {
|
|
51
|
+
checked.add(node.key);
|
|
52
|
+
half.delete(node.key);
|
|
53
|
+
} else if (anyChecked) {
|
|
54
|
+
checked.delete(node.key);
|
|
55
|
+
half.add(node.key);
|
|
56
|
+
} else {
|
|
57
|
+
checked.delete(node.key);
|
|
58
|
+
half.delete(node.key);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
allChecked: !eligible ? allChecked : checked.has(node.key) && allChecked,
|
|
62
|
+
anyChecked: anyChecked || checked.has(node.key),
|
|
63
|
+
anyEligible: anyEligible || eligible
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function normalizeControlledChecked(controlled) {
|
|
67
|
+
if (controlled == null) return null;
|
|
68
|
+
if (Array.isArray(controlled)) return {
|
|
69
|
+
checked: new Set(controlled),
|
|
70
|
+
halfChecked: /* @__PURE__ */ new Set()
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
checked: new Set(controlled.checked ?? []),
|
|
74
|
+
halfChecked: new Set(controlled.halfChecked ?? [])
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Local hook implementing AntD-style cascading checkbox state.
|
|
79
|
+
*
|
|
80
|
+
* - `checked` and `halfChecked` are always derived together from a single
|
|
81
|
+
* `checked` set (the source of truth) so callers don't need to track
|
|
82
|
+
* indeterminate keys themselves.
|
|
83
|
+
* - When the consumer passes `checkedKeys` as `{ checked, halfChecked }`,
|
|
84
|
+
* we keep the wire shape on the way out — same as AntD.
|
|
85
|
+
* - Toggling a node propagates *down* (skipping ineligible descendants)
|
|
86
|
+
* and recomputes ancestors *up* in a single pass.
|
|
87
|
+
*/
|
|
88
|
+
function useCheckboxTree(opts) {
|
|
89
|
+
const { treeData, index, isCheckable, defaultCheckedKeys, checkedKeys, onCheck } = opts;
|
|
90
|
+
/**
|
|
91
|
+
* Normalize the controlled `checkedKeys` prop into stable `Set` instances.
|
|
92
|
+
* Memoized on the `checkedKeys` reference so unrelated re-renders don't
|
|
93
|
+
* invalidate the derivation memo below — `normalizeControlledChecked`
|
|
94
|
+
* allocates fresh `Set`s each call, which would otherwise force
|
|
95
|
+
* `deriveCheckedState` to re-walk the entire tree on every render in
|
|
96
|
+
* controlled mode.
|
|
97
|
+
*/
|
|
98
|
+
const controlled = useMemo(() => normalizeControlledChecked(checkedKeys), [checkedKeys]);
|
|
99
|
+
const isControlled = controlled != null;
|
|
100
|
+
const wantsObjectShape = checkedKeys != null && !Array.isArray(checkedKeys);
|
|
101
|
+
const [uncontrolledChecked, setUncontrolledChecked] = useState(() => new Set(defaultCheckedKeys ?? []));
|
|
102
|
+
const sourceChecked = isControlled ? controlled.checked : uncontrolledChecked;
|
|
103
|
+
/**
|
|
104
|
+
* Derive `{ checked, halfChecked }` from the source-of-truth `checked` set
|
|
105
|
+
* by walking the tree bottom-up:
|
|
106
|
+
*
|
|
107
|
+
* - A parent is considered fully checked iff every eligible descendant
|
|
108
|
+
* leaf is checked.
|
|
109
|
+
* - A parent is half-checked iff at least one eligible descendant is
|
|
110
|
+
* checked or half-checked, but not all.
|
|
111
|
+
*
|
|
112
|
+
* Ineligible nodes (disabled / opt-out) are ignored when computing the
|
|
113
|
+
* parent's state — they neither force a parent into the unchecked nor
|
|
114
|
+
* half state.
|
|
115
|
+
*/
|
|
116
|
+
const { checkedSet, halfCheckedSet } = useMemo(() => {
|
|
117
|
+
if (!isCheckable) return {
|
|
118
|
+
checkedSet: /* @__PURE__ */ new Set(),
|
|
119
|
+
halfCheckedSet: /* @__PURE__ */ new Set()
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* If the consumer passed the object shape (`{ checked, halfChecked }`),
|
|
123
|
+
* they own the half-checked set and we use it as-is. With the array
|
|
124
|
+
* shape we still need to derive `halfChecked` ourselves — the consumer
|
|
125
|
+
* only provides `checked`, so parents should still light up
|
|
126
|
+
* indeterminate when only some descendants are checked.
|
|
127
|
+
*/
|
|
128
|
+
if (isControlled && wantsObjectShape) return {
|
|
129
|
+
checkedSet: new Set(sourceChecked),
|
|
130
|
+
halfCheckedSet: new Set(controlled.halfChecked)
|
|
131
|
+
};
|
|
132
|
+
const checked = new Set(sourceChecked);
|
|
133
|
+
const half = /* @__PURE__ */ new Set();
|
|
134
|
+
for (const root of treeData) deriveCheckedState(root, index, checked, half);
|
|
135
|
+
return {
|
|
136
|
+
checkedSet: checked,
|
|
137
|
+
halfCheckedSet: half
|
|
138
|
+
};
|
|
139
|
+
}, [
|
|
140
|
+
isCheckable,
|
|
141
|
+
isControlled,
|
|
142
|
+
wantsObjectShape,
|
|
143
|
+
sourceChecked,
|
|
144
|
+
controlled,
|
|
145
|
+
treeData,
|
|
146
|
+
index
|
|
147
|
+
]);
|
|
148
|
+
return {
|
|
149
|
+
checkedSet,
|
|
150
|
+
halfCheckedSet,
|
|
151
|
+
toggle: useEvent((key) => {
|
|
152
|
+
const node = index.byKey.get(key);
|
|
153
|
+
if (!node || !isNodeEligible(node)) return;
|
|
154
|
+
const willCheck = !checkedSet.has(key);
|
|
155
|
+
/**
|
|
156
|
+
* Seed from the derived `checkedSet`, not `sourceChecked`. The
|
|
157
|
+
* source-of-truth set may only contain leaf keys (e.g. when
|
|
158
|
+
* `defaultCheckedKeys` is leaf-only, or a consumer in controlled-array
|
|
159
|
+
* mode passes only leaves). The ancestor walk below decides whether
|
|
160
|
+
* each ancestor is fully checked by inspecting its direct children
|
|
161
|
+
* via `next.has(ck)` — those children may themselves be inner nodes
|
|
162
|
+
* whose "fully checked" status only exists in the derived set. Seeding
|
|
163
|
+
* from `sourceChecked` causes a sibling subtree's parent key to be
|
|
164
|
+
* missing from `next`, which would incorrectly drop the grandparent
|
|
165
|
+
* from the stored state (the next render's `useMemo` self-corrects,
|
|
166
|
+
* but the intermediate stored value violates the cascade invariant).
|
|
167
|
+
*/
|
|
168
|
+
const next = new Set(checkedSet);
|
|
169
|
+
const apply = (n, value) => {
|
|
170
|
+
if (!isNodeEligible(n)) return;
|
|
171
|
+
if (value) next.add(n.key);
|
|
172
|
+
else next.delete(n.key);
|
|
173
|
+
const childKeys = index.childrenOf.get(n.key) ?? [];
|
|
174
|
+
for (const ck of childKeys) {
|
|
175
|
+
const child = index.byKey.get(ck);
|
|
176
|
+
if (child) apply(child, value);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
apply(node, willCheck);
|
|
180
|
+
/**
|
|
181
|
+
* After the cascade, recompute ancestors so the public `checked` set
|
|
182
|
+
* doesn't carry parent keys that should be half-checked instead.
|
|
183
|
+
* Ancestors of `key` get visited bottom-up here.
|
|
184
|
+
*/
|
|
185
|
+
let parentKey = index.parentOf.get(key);
|
|
186
|
+
while (parentKey) {
|
|
187
|
+
const parent = index.byKey.get(parentKey);
|
|
188
|
+
if (!parent) break;
|
|
189
|
+
const childKeys = index.childrenOf.get(parentKey) ?? [];
|
|
190
|
+
let allEligibleChecked = true;
|
|
191
|
+
let anyEligible = false;
|
|
192
|
+
for (const ck of childKeys) {
|
|
193
|
+
const child = index.byKey.get(ck);
|
|
194
|
+
if (!child) continue;
|
|
195
|
+
if (!isNodeEligible(child)) continue;
|
|
196
|
+
anyEligible = true;
|
|
197
|
+
if (!next.has(ck)) {
|
|
198
|
+
allEligibleChecked = false;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (anyEligible && allEligibleChecked && isNodeEligible(parent)) next.add(parentKey);
|
|
203
|
+
else next.delete(parentKey);
|
|
204
|
+
parentKey = index.parentOf.get(parentKey);
|
|
205
|
+
}
|
|
206
|
+
if (!isControlled) setUncontrolledChecked(next);
|
|
207
|
+
if (onCheck) {
|
|
208
|
+
const finalChecked = new Set(next);
|
|
209
|
+
const finalHalf = /* @__PURE__ */ new Set();
|
|
210
|
+
for (const root of treeData) deriveCheckedState(root, index, finalChecked, finalHalf);
|
|
211
|
+
const checkedArr = Array.from(finalChecked);
|
|
212
|
+
const halfArr = Array.from(finalHalf);
|
|
213
|
+
const info = {
|
|
214
|
+
checked: willCheck,
|
|
215
|
+
node,
|
|
216
|
+
checkedNodes: checkedArr.map((k) => index.byKey.get(k)).filter((n) => !!n),
|
|
217
|
+
halfCheckedKeys: halfArr
|
|
218
|
+
};
|
|
219
|
+
if (wantsObjectShape) onCheck({
|
|
220
|
+
checked: checkedArr,
|
|
221
|
+
halfChecked: halfArr
|
|
222
|
+
}, info);
|
|
223
|
+
else onCheck(checkedArr, info);
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
export { useCheckboxTree };
|
|
231
|
+
//# sourceMappingURL=use-checkbox-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-checkbox-tree.js","names":[],"sources":["../../../../src/components/content/Tree/use-checkbox-tree.ts"],"sourcesContent":["import { useMemo, useState } from 'react';\n\nimport { useEvent } from '../../../_internal/hooks';\n\nimport type { Key } from '@react-types/shared';\nimport type { TreeIndex } from './tree-index';\nimport type { CubeTreeNodeData, TreeOnCheckInfo } from './types';\n\nexport interface UseCheckboxTreeOptions {\n treeData: CubeTreeNodeData[];\n /**\n * Pre-built tree index, shared with `Tree.tsx` so that `treeData`\n * is walked exactly once per change rather than once per consumer.\n */\n index: TreeIndex;\n isCheckable: boolean;\n defaultCheckedKeys?: string[];\n /** Either an array (AntD's default) or `{ checked, halfChecked }`. */\n checkedKeys?: string[] | { checked: string[]; halfChecked?: string[] };\n onCheck?: (\n checked: Key[] | { checked: Key[]; halfChecked: Key[] },\n info: TreeOnCheckInfo,\n ) => void;\n}\n\nexport interface CheckboxTree {\n /** Set of keys that are fully checked. */\n checkedSet: Set<string>;\n /** Set of keys that are in the indeterminate (half-checked) state. */\n halfCheckedSet: Set<string>;\n /** Toggle a key, propagating to descendants and updating ancestors. */\n toggle: (key: string) => void;\n}\n\n/**\n * Returns whether a node should be checkable (i.e. clicking the\n * checkbox should affect it).\n *\n * Skips:\n * - explicitly disabled nodes (`isDisabled === true`)\n * - explicitly disabled checkboxes (`isCheckboxDisabled === true`)\n * - nodes that opted out via `isCheckable === false`\n */\nfunction isNodeEligible(node: CubeTreeNodeData | undefined): boolean {\n if (!node) return false;\n if (node.isDisabled) return false;\n if (node.isCheckboxDisabled) return false;\n if (node.isCheckable === false) return false;\n return true;\n}\n\n/**\n * Recursively walk a subtree bottom-up, deriving which nodes are fully\n * checked vs half-checked. Mutates `checked` and `half` in place.\n */\nfunction deriveCheckedState(\n node: CubeTreeNodeData,\n index: TreeIndex,\n checked: Set<string>,\n half: Set<string>,\n): { allChecked: boolean; anyChecked: boolean; anyEligible: boolean } {\n const childKeys = index.childrenOf.get(node.key) ?? [];\n\n if (childKeys.length === 0) {\n const eligible = isNodeEligible(node);\n const isChecked = checked.has(node.key);\n return {\n allChecked: !eligible || isChecked,\n anyChecked: isChecked,\n anyEligible: eligible,\n };\n }\n\n let allChecked = true;\n let anyChecked = false;\n let anyEligible = false;\n\n for (const childKey of childKeys) {\n const child = index.byKey.get(childKey);\n if (!child) continue;\n const r = deriveCheckedState(child, index, checked, half);\n if (r.anyEligible) anyEligible = true;\n if (!r.allChecked) allChecked = false;\n if (r.anyChecked) anyChecked = true;\n }\n\n const eligible = isNodeEligible(node);\n\n if (!anyEligible) {\n // No eligible descendants — this node behaves like a leaf for\n // checking purposes: its own checked state stands as-is.\n half.delete(node.key);\n } else if (allChecked) {\n checked.add(node.key);\n half.delete(node.key);\n } else if (anyChecked) {\n checked.delete(node.key);\n half.add(node.key);\n } else {\n checked.delete(node.key);\n half.delete(node.key);\n }\n\n return {\n allChecked: !eligible ? allChecked : checked.has(node.key) && allChecked,\n anyChecked: anyChecked || checked.has(node.key),\n anyEligible: anyEligible || eligible,\n };\n}\n\nfunction normalizeControlledChecked(\n controlled: UseCheckboxTreeOptions['checkedKeys'],\n): { checked: Set<string>; halfChecked: Set<string> } | null {\n if (controlled == null) return null;\n if (Array.isArray(controlled)) {\n return {\n checked: new Set(controlled),\n halfChecked: new Set(),\n };\n }\n return {\n checked: new Set(controlled.checked ?? []),\n halfChecked: new Set(controlled.halfChecked ?? []),\n };\n}\n\n/**\n * Local hook implementing AntD-style cascading checkbox state.\n *\n * - `checked` and `halfChecked` are always derived together from a single\n * `checked` set (the source of truth) so callers don't need to track\n * indeterminate keys themselves.\n * - When the consumer passes `checkedKeys` as `{ checked, halfChecked }`,\n * we keep the wire shape on the way out — same as AntD.\n * - Toggling a node propagates *down* (skipping ineligible descendants)\n * and recomputes ancestors *up* in a single pass.\n */\nexport function useCheckboxTree(opts: UseCheckboxTreeOptions): CheckboxTree {\n const {\n treeData,\n index,\n isCheckable,\n defaultCheckedKeys,\n checkedKeys,\n onCheck,\n } = opts;\n\n /**\n * Normalize the controlled `checkedKeys` prop into stable `Set` instances.\n * Memoized on the `checkedKeys` reference so unrelated re-renders don't\n * invalidate the derivation memo below — `normalizeControlledChecked`\n * allocates fresh `Set`s each call, which would otherwise force\n * `deriveCheckedState` to re-walk the entire tree on every render in\n * controlled mode.\n */\n const controlled = useMemo(\n () => normalizeControlledChecked(checkedKeys),\n [checkedKeys],\n );\n const isControlled = controlled != null;\n const wantsObjectShape = checkedKeys != null && !Array.isArray(checkedKeys);\n\n const [uncontrolledChecked, setUncontrolledChecked] = useState<Set<string>>(\n () => new Set(defaultCheckedKeys ?? []),\n );\n\n const sourceChecked = isControlled\n ? controlled!.checked\n : uncontrolledChecked;\n\n /**\n * Derive `{ checked, halfChecked }` from the source-of-truth `checked` set\n * by walking the tree bottom-up:\n *\n * - A parent is considered fully checked iff every eligible descendant\n * leaf is checked.\n * - A parent is half-checked iff at least one eligible descendant is\n * checked or half-checked, but not all.\n *\n * Ineligible nodes (disabled / opt-out) are ignored when computing the\n * parent's state — they neither force a parent into the unchecked nor\n * half state.\n */\n const { checkedSet, halfCheckedSet } = useMemo(() => {\n if (!isCheckable) {\n return {\n checkedSet: new Set<string>(),\n halfCheckedSet: new Set<string>(),\n };\n }\n\n /**\n * If the consumer passed the object shape (`{ checked, halfChecked }`),\n * they own the half-checked set and we use it as-is. With the array\n * shape we still need to derive `halfChecked` ourselves — the consumer\n * only provides `checked`, so parents should still light up\n * indeterminate when only some descendants are checked.\n */\n if (isControlled && wantsObjectShape) {\n return {\n checkedSet: new Set(sourceChecked),\n halfCheckedSet: new Set(controlled!.halfChecked),\n };\n }\n\n const checked = new Set(sourceChecked);\n const half = new Set<string>();\n\n for (const root of treeData) {\n deriveCheckedState(root, index, checked, half);\n }\n\n return { checkedSet: checked, halfCheckedSet: half };\n }, [\n isCheckable,\n isControlled,\n wantsObjectShape,\n sourceChecked,\n controlled,\n treeData,\n index,\n ]);\n\n const toggle = useEvent((key: string) => {\n const node = index.byKey.get(key);\n if (!node || !isNodeEligible(node)) return;\n\n const isCurrentlyChecked = checkedSet.has(key);\n const willCheck = !isCurrentlyChecked;\n\n /**\n * Seed from the derived `checkedSet`, not `sourceChecked`. The\n * source-of-truth set may only contain leaf keys (e.g. when\n * `defaultCheckedKeys` is leaf-only, or a consumer in controlled-array\n * mode passes only leaves). The ancestor walk below decides whether\n * each ancestor is fully checked by inspecting its direct children\n * via `next.has(ck)` — those children may themselves be inner nodes\n * whose \"fully checked\" status only exists in the derived set. Seeding\n * from `sourceChecked` causes a sibling subtree's parent key to be\n * missing from `next`, which would incorrectly drop the grandparent\n * from the stored state (the next render's `useMemo` self-corrects,\n * but the intermediate stored value violates the cascade invariant).\n */\n const next = new Set(checkedSet);\n\n const apply = (n: CubeTreeNodeData, value: boolean) => {\n if (!isNodeEligible(n)) return;\n if (value) next.add(n.key);\n else next.delete(n.key);\n const childKeys = index.childrenOf.get(n.key) ?? [];\n for (const ck of childKeys) {\n const child = index.byKey.get(ck);\n if (child) apply(child, value);\n }\n };\n\n apply(node, willCheck);\n\n /**\n * After the cascade, recompute ancestors so the public `checked` set\n * doesn't carry parent keys that should be half-checked instead.\n * Ancestors of `key` get visited bottom-up here.\n */\n let parentKey = index.parentOf.get(key);\n while (parentKey) {\n const parent = index.byKey.get(parentKey);\n if (!parent) break;\n const childKeys = index.childrenOf.get(parentKey) ?? [];\n let allEligibleChecked = true;\n let anyEligible = false;\n for (const ck of childKeys) {\n const child = index.byKey.get(ck);\n if (!child) continue;\n if (!isNodeEligible(child)) continue;\n anyEligible = true;\n if (!next.has(ck)) {\n allEligibleChecked = false;\n break;\n }\n }\n if (anyEligible && allEligibleChecked && isNodeEligible(parent)) {\n next.add(parentKey);\n } else {\n next.delete(parentKey);\n }\n parentKey = index.parentOf.get(parentKey);\n }\n\n if (!isControlled) {\n setUncontrolledChecked(next);\n }\n\n if (onCheck) {\n const finalChecked = new Set(next);\n const finalHalf = new Set<string>();\n\n for (const root of treeData) {\n deriveCheckedState(root, index, finalChecked, finalHalf);\n }\n\n const checkedArr = Array.from(finalChecked);\n const halfArr = Array.from(finalHalf);\n const checkedNodes: CubeTreeNodeData[] = checkedArr\n .map((k) => index.byKey.get(k))\n .filter((n): n is CubeTreeNodeData => !!n);\n\n const info: TreeOnCheckInfo = {\n checked: willCheck,\n node,\n checkedNodes,\n halfCheckedKeys: halfArr,\n };\n\n if (wantsObjectShape) {\n onCheck({ checked: checkedArr, halfChecked: halfArr }, info);\n } else {\n onCheck(checkedArr, info);\n }\n }\n });\n\n return { checkedSet, halfCheckedSet, toggle };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.129.0 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/content/Tree/use-load-data.ts
|
|
6
|
+
/**
|
|
7
|
+
* Tracks which rows are currently fetching their children via `loadData`
|
|
8
|
+
* and exposes a setter for the Tree to call after every expand change.
|
|
9
|
+
*
|
|
10
|
+
* `loadData` is fired exactly once per key per "first expand" event:
|
|
11
|
+
*
|
|
12
|
+
* - Skipped if there is no `loadData` callback.
|
|
13
|
+
* - Skipped for leaf nodes (`isLeaf === true`).
|
|
14
|
+
* - Skipped if the node already has `children` (already loaded).
|
|
15
|
+
* - Skipped if a previous fetch for the same key is still in flight.
|
|
16
|
+
*
|
|
17
|
+
* The promise's resolution is awaited only to clear the `loading` mod;
|
|
18
|
+
* the consumer is expected to commit the new children to the controlled
|
|
19
|
+
* `treeData` themselves (matching AntD's pattern).
|
|
20
|
+
*/
|
|
21
|
+
function useLoadData(opts) {
|
|
22
|
+
const { nodesByKey, loadData, initialExpandedKeys } = opts;
|
|
23
|
+
const [loadingKeys, setLoadingKeys] = useState(() => /* @__PURE__ */ new Set());
|
|
24
|
+
const previousExpandedRef = useRef(new Set(initialExpandedKeys));
|
|
25
|
+
const inFlightRef = useRef(/* @__PURE__ */ new Set());
|
|
26
|
+
return {
|
|
27
|
+
loadingKeys,
|
|
28
|
+
onExpandedChanged: useEvent((expandedKeys) => {
|
|
29
|
+
const next = /* @__PURE__ */ new Set();
|
|
30
|
+
for (const k of expandedKeys) next.add(String(k));
|
|
31
|
+
const prev = previousExpandedRef.current;
|
|
32
|
+
const newlyExpanded = [];
|
|
33
|
+
for (const k of next) if (!prev.has(k)) newlyExpanded.push(k);
|
|
34
|
+
previousExpandedRef.current = next;
|
|
35
|
+
if (!loadData || newlyExpanded.length === 0) return;
|
|
36
|
+
const toLoad = [];
|
|
37
|
+
for (const key of newlyExpanded) {
|
|
38
|
+
const node = nodesByKey.get(key);
|
|
39
|
+
if (!node) continue;
|
|
40
|
+
if (node.isLeaf) continue;
|
|
41
|
+
if (node.children && node.children.length > 0) continue;
|
|
42
|
+
if (inFlightRef.current.has(key)) continue;
|
|
43
|
+
inFlightRef.current.add(key);
|
|
44
|
+
toLoad.push(key);
|
|
45
|
+
}
|
|
46
|
+
if (toLoad.length === 0) return;
|
|
47
|
+
setLoadingKeys((current) => {
|
|
48
|
+
const updated = new Set(current);
|
|
49
|
+
for (const k of toLoad) updated.add(k);
|
|
50
|
+
return updated;
|
|
51
|
+
});
|
|
52
|
+
for (const key of toLoad) {
|
|
53
|
+
const loadNode = nodesByKey.get(key);
|
|
54
|
+
Promise.resolve(loadData({
|
|
55
|
+
key,
|
|
56
|
+
children: loadNode?.children
|
|
57
|
+
})).catch((err) => {
|
|
58
|
+
console.error(`[Tree] loadData failed for key "${key}":`, err);
|
|
59
|
+
}).finally(() => {
|
|
60
|
+
inFlightRef.current.delete(key);
|
|
61
|
+
setLoadingKeys((current) => {
|
|
62
|
+
if (!current.has(key)) return current;
|
|
63
|
+
const updated = new Set(current);
|
|
64
|
+
updated.delete(key);
|
|
65
|
+
return updated;
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { useLoadData };
|
|
75
|
+
//# sourceMappingURL=use-load-data.js.map
|