@cube-dev/ui-kit 0.156.0 → 0.157.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 +237 -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 +42 -44
- 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/InfoBadge/InfoBadge.js +1 -1
- package/dist/components/content/InlineInput/InlineInput.js +1 -1
- package/dist/components/content/Item/Item.js +1 -1
- package/dist/components/content/ItemBadge/ItemBadge.js +1 -1
- package/dist/components/content/ItemCard/ItemCard.js +1 -1
- package/dist/components/content/Layout/GridLayout.js +1 -1
- package/dist/components/content/Layout/Layout.js +1 -1
- package/dist/components/content/Layout/LayoutBlock.js +1 -1
- package/dist/components/content/Layout/LayoutCenter.js +1 -1
- package/dist/components/content/Layout/LayoutContainer.js +1 -1
- package/dist/components/content/Layout/LayoutContent.js +1 -1
- package/dist/components/content/Layout/LayoutContext.js +1 -1
- package/dist/components/content/Layout/LayoutFlex.js +1 -1
- package/dist/components/content/Layout/LayoutFooter.js +1 -1
- package/dist/components/content/Layout/LayoutGrid.js +1 -1
- package/dist/components/content/Layout/LayoutHeader.js +1 -1
- package/dist/components/content/Layout/LayoutPane.js +1 -1
- package/dist/components/content/Layout/LayoutPanel.js +1 -1
- package/dist/components/content/Layout/LayoutPanelHeader.js +1 -1
- package/dist/components/content/Layout/LayoutToolbar.js +1 -1
- package/dist/components/content/Layout/hooks/useTinyScrollbar.js +1 -1
- package/dist/components/content/Layout/index.js +1 -1
- package/dist/components/content/Layout/utils.js +1 -1
- package/dist/components/content/Paragraph.js +1 -1
- package/dist/components/content/Placeholder/Placeholder.js +1 -1
- package/dist/components/content/PrismCode/PrismCode.js +1 -1
- package/dist/components/content/PrismCode/prismSetup.js +1 -1
- package/dist/components/content/PrismDiffCode/PrismDiffCode.js +1 -1
- package/dist/components/content/Result/Result.js +1 -1
- package/dist/components/content/Skeleton/Skeleton.js +1 -1
- package/dist/components/content/Tag/Tag.js +2 -2
- package/dist/components/content/Tag/Tag.js.map +1 -1
- package/dist/components/content/Text.js +1 -1
- package/dist/components/content/TextItem/TextItem.js +1 -1
- package/dist/components/content/Title.js +1 -1
- package/dist/components/content/Tree/Tree.js +1 -1
- package/dist/components/content/Tree/TreeNode.js +1 -1
- package/dist/components/content/Tree/styled.js +1 -1
- package/dist/components/content/Tree/tree-index.js +1 -1
- package/dist/components/content/Tree/use-checkbox-tree.js +1 -1
- package/dist/components/content/Tree/use-load-data.js +1 -1
- package/dist/components/content/highlightText.js +1 -1
- package/dist/components/content/use-auto-tooltip.js +1 -1
- package/dist/components/data/DataTable/DataTable.d.ts +13 -0
- package/dist/components/data/DataTable/DataTable.js +246 -0
- package/dist/components/data/DataTable/DataTable.js.map +1 -0
- package/dist/components/data/DataTable/index.d.ts +3 -0
- package/dist/components/data/DataTable/types.d.ts +145 -0
- package/dist/components/data/ItemTable/ItemTable.d.ts +19 -0
- package/dist/components/data/ItemTable/ItemTable.js +350 -0
- package/dist/components/data/ItemTable/ItemTable.js.map +1 -0
- package/dist/components/data/ItemTable/ItemTableBulkBar.d.ts +23 -0
- package/dist/components/data/ItemTable/ItemTableBulkBar.js +131 -0
- package/dist/components/data/ItemTable/ItemTableBulkBar.js.map +1 -0
- package/dist/components/data/ItemTable/ItemTableDragPreview.js +46 -0
- package/dist/components/data/ItemTable/ItemTableDragPreview.js.map +1 -0
- package/dist/components/data/ItemTable/ItemTableFooter.js +79 -0
- package/dist/components/data/ItemTable/ItemTableFooter.js.map +1 -0
- package/dist/components/data/ItemTable/ItemTableToolbar.d.ts +34 -0
- package/dist/components/data/ItemTable/ItemTableToolbar.js +91 -0
- package/dist/components/data/ItemTable/ItemTableToolbar.js.map +1 -0
- package/dist/components/data/ItemTable/index.d.ts +4 -0
- package/dist/components/data/ItemTable/types.d.ts +327 -0
- package/dist/components/data/TableBase/ColumnResizer.js +70 -0
- package/dist/components/data/TableBase/ColumnResizer.js.map +1 -0
- package/dist/components/data/TableBase/RowCollection.js +99 -0
- package/dist/components/data/TableBase/RowCollection.js.map +1 -0
- package/dist/components/data/TableBase/TableRow.js +89 -0
- package/dist/components/data/TableBase/TableRow.js.map +1 -0
- package/dist/components/data/TableBase/TableView.d.ts +22 -0
- package/dist/components/data/TableBase/TableView.js +921 -0
- package/dist/components/data/TableBase/TableView.js.map +1 -0
- package/dist/components/data/TableBase/index.d.ts +5 -0
- package/dist/components/data/TableBase/row-menu.js +40 -0
- package/dist/components/data/TableBase/row-menu.js.map +1 -0
- package/dist/components/data/TableBase/styled.d.ts +5 -0
- package/dist/components/data/TableBase/styled.js +532 -0
- package/dist/components/data/TableBase/styled.js.map +1 -0
- package/dist/components/data/TableBase/types.d.ts +160 -0
- package/dist/components/data/TableBase/types.js +31 -0
- package/dist/components/data/TableBase/types.js.map +1 -0
- package/dist/components/data/TableBase/use-cell-selection.d.ts +3 -0
- package/dist/components/data/TableBase/use-cell-selection.js +0 -0
- package/dist/components/data/TableBase/use-cell-selection.js.map +1 -0
- package/dist/components/data/TableBase/use-container-width.js +35 -0
- package/dist/components/data/TableBase/use-container-width.js.map +1 -0
- package/dist/components/data/TableBase/use-row-move-animation.js +90 -0
- package/dist/components/data/TableBase/use-row-move-animation.js.map +1 -0
- package/dist/components/data/TableBase/use-scrollability.js +49 -0
- package/dist/components/data/TableBase/use-scrollability.js.map +1 -0
- package/dist/components/data/TableBase/use-table-columns.d.ts +2 -0
- package/dist/components/data/TableBase/use-table-columns.js +166 -0
- package/dist/components/data/TableBase/use-table-columns.js.map +1 -0
- package/dist/components/data/TableBase/use-table-search.js +64 -0
- package/dist/components/data/TableBase/use-table-search.js.map +1 -0
- package/dist/components/data/TableBase/use-table-selection.d.ts +4 -0
- package/dist/components/data/TableBase/use-table-selection.js +233 -0
- package/dist/components/data/TableBase/use-table-selection.js.map +1 -0
- package/dist/components/data/TableBase/use-table-sort.js +91 -0
- package/dist/components/data/TableBase/use-table-sort.js.map +1 -0
- package/dist/components/data/TableBase/use-table-sorts.js +97 -0
- package/dist/components/data/TableBase/use-table-sorts.js.map +1 -0
- package/dist/components/data/TableBase/use-table-storage.d.ts +8 -0
- package/dist/components/data/TableBase/use-table-storage.js +58 -0
- package/dist/components/data/TableBase/use-table-storage.js.map +1 -0
- package/dist/components/data/index.d.ts +10 -0
- package/dist/components/fields/Checkbox/Checkbox.js +1 -1
- package/dist/components/fields/Checkbox/CheckboxGroup.js +1 -1
- package/dist/components/fields/Checkbox/context.js +1 -1
- package/dist/components/fields/ColorInput/ColorInput.d.ts +67 -0
- package/dist/components/fields/ColorInput/ColorInput.js +230 -0
- package/dist/components/fields/ColorInput/ColorInput.js.map +1 -0
- package/dist/components/fields/ColorInput/index.d.ts +2 -0
- package/dist/components/fields/ColorPicker/ColorPicker.d.ts +34 -37
- package/dist/components/fields/ColorPicker/ColorPicker.js +131 -182
- package/dist/components/fields/ColorPicker/ColorPicker.js.map +1 -1
- package/dist/components/fields/ColorPicker/index.d.ts +1 -3
- package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.d.ts +50 -0
- package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js +269 -0
- package/dist/components/fields/ColorSwatchGroup/ColorSwatchGroup.js.map +1 -0
- package/dist/components/fields/ColorSwatchGroup/index.d.ts +2 -0
- package/dist/components/fields/ComboBox/ComboBox.js +1 -1
- package/dist/components/fields/CommandTextArea/CommandTextArea.js +1 -1
- package/dist/components/fields/CommandTextArea/caretPosition.js +1 -1
- package/dist/components/fields/CommandTextArea/useCaretAnchor.js +1 -1
- package/dist/components/fields/DatePicker/DateInput.js +1 -1
- package/dist/components/fields/DatePicker/DateInputBase.js +1 -1
- package/dist/components/fields/DatePicker/DatePicker.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerButton.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerElement.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerInput.js +1 -1
- package/dist/components/fields/DatePicker/DatePickerSegment.js +1 -1
- package/dist/components/fields/DatePicker/DateRangePicker.js +1 -1
- package/dist/components/fields/DatePicker/DateRangeSeparatedPicker.js +1 -1
- package/dist/components/fields/DatePicker/MonthPicker.js +1 -1
- package/dist/components/fields/DatePicker/PeriodPicker.js +1 -1
- package/dist/components/fields/DatePicker/QuarterPicker.js +1 -1
- package/dist/components/fields/DatePicker/TimeInput.js +1 -1
- package/dist/components/fields/DatePicker/WeekPicker.js +1 -1
- package/dist/components/fields/DatePicker/YearPicker.js +1 -1
- package/dist/components/fields/DatePicker/parseDate.js +1 -1
- package/dist/components/fields/DatePicker/period.js +1 -1
- package/dist/components/fields/DatePicker/props.js +1 -1
- package/dist/components/fields/DatePicker/utils.js +1 -1
- package/dist/components/fields/FileInput/FileInput.js +1 -1
- package/dist/components/fields/FilterListBox/FilterListBox.js +2 -1
- package/dist/components/fields/FilterListBox/FilterListBox.js.map +1 -1
- package/dist/components/fields/FilterPicker/FilterPicker.js +6 -1
- package/dist/components/fields/FilterPicker/FilterPicker.js.map +1 -1
- package/dist/components/fields/Input/Input.js +2 -2
- package/dist/components/fields/ListBox/DraggableListBox.js +1 -1
- package/dist/components/fields/ListBox/ListBox.d.ts +7 -0
- package/dist/components/fields/ListBox/ListBox.js +4 -3
- package/dist/components/fields/ListBox/ListBox.js.map +1 -1
- package/dist/components/fields/ListBoxPopover/ListBoxPopover.js +1 -1
- package/dist/components/fields/ListBoxPopover/listNavigation.js +1 -1
- package/dist/components/fields/ListBoxPopover/useCompositeFocus.js +1 -1
- package/dist/components/fields/NumberInput/NumberInput.js +1 -1
- package/dist/components/fields/NumberInput/StepButton.js +1 -1
- package/dist/components/fields/PasswordInput/PasswordInput.d.ts +2 -2
- package/dist/components/fields/PasswordInput/PasswordInput.js +12 -2
- package/dist/components/fields/PasswordInput/PasswordInput.js.map +1 -1
- package/dist/components/fields/Picker/Picker.js +6 -1
- package/dist/components/fields/Picker/Picker.js.map +1 -1
- package/dist/components/fields/RadioGroup/Radio.d.ts +2 -2
- package/dist/components/fields/RadioGroup/Radio.js +4 -4
- package/dist/components/fields/RadioGroup/Radio.js.map +1 -1
- package/dist/components/fields/RadioGroup/RadioGroup.js +1 -1
- package/dist/components/fields/RadioGroup/context.js +1 -1
- package/dist/components/fields/SearchComboBox/SearchComboBox.js +1 -1
- package/dist/components/fields/SearchInput/SearchInput.d.ts +2 -2
- package/dist/components/fields/SearchInput/SearchInput.js +17 -4
- package/dist/components/fields/SearchInput/SearchInput.js.map +1 -1
- package/dist/components/fields/Select/Select.js +1 -1
- package/dist/components/fields/Slider/Gradation.js +1 -1
- package/dist/components/fields/Slider/HueSlider.js +1 -1
- package/dist/components/fields/Slider/RangeSlider.js +1 -1
- package/dist/components/fields/Slider/Slider.js +1 -1
- package/dist/components/fields/Slider/SliderBase.js +1 -1
- package/dist/components/fields/Slider/SliderThumb.js +1 -1
- package/dist/components/fields/Slider/SliderTrack.js +1 -1
- package/dist/components/fields/Slider/elements.js +1 -1
- package/dist/components/fields/Slider/index.js +1 -1
- package/dist/components/fields/Switch/Switch.js +1 -1
- package/dist/components/fields/TextArea/TextArea.d.ts +2 -2
- package/dist/components/fields/TextArea/TextArea.js +12 -5
- package/dist/components/fields/TextArea/TextArea.js.map +1 -1
- package/dist/components/fields/TextInput/TextInput.d.ts +2 -2
- package/dist/components/fields/TextInput/TextInput.js +15 -3
- package/dist/components/fields/TextInput/TextInput.js.map +1 -1
- package/dist/components/fields/TextInput/TextInputBase.d.ts +17 -1
- package/dist/components/fields/TextInput/TextInputBase.js +1 -1
- package/dist/components/fields/TextInput/TextInputBase.js.map +1 -1
- package/dist/components/fields/TextInput/index.d.ts +1 -1
- package/dist/components/fields/TextInputMapper/TextInputMapper.js +1 -1
- package/dist/components/fields/{ColorPicker/ColorPickerPanel.js → color/ColorPanel.js} +14 -11
- package/dist/components/fields/color/ColorPanel.js.map +1 -0
- package/dist/components/fields/color/ColorSwatch.d.ts +22 -0
- package/dist/components/fields/color/ColorSwatch.js +58 -0
- package/dist/components/fields/color/ColorSwatch.js.map +1 -0
- package/dist/components/fields/{ColorPicker → color}/channels.d.ts +1 -1
- package/dist/components/fields/{ColorPicker → color}/channels.js +2 -2
- package/dist/components/fields/color/channels.js.map +1 -0
- package/dist/components/fields/color/color.d.ts +21 -0
- package/dist/components/fields/{ColorPicker → color}/color.js +2 -2
- package/dist/components/fields/color/color.js.map +1 -0
- package/dist/components/fields/color/context.js +20 -0
- package/dist/components/fields/color/context.js.map +1 -0
- package/dist/components/fields/color/index.d.ts +4 -0
- package/dist/components/fields/index.d.ts +10 -4
- package/dist/components/form/FieldWrapper/FieldWrapper.js +1 -1
- package/dist/components/form/Form/Field.js +1 -1
- package/dist/components/form/Form/Form.js +1 -1
- package/dist/components/form/Form/ResetButton/ResetButton.js +1 -1
- package/dist/components/form/Form/SubmitButton/SubmitButton.js +1 -1
- package/dist/components/form/Form/SubmitError.js +1 -1
- package/dist/components/form/Form/index.js +1 -1
- package/dist/components/form/Form/use-field/use-field-props.js +1 -1
- package/dist/components/form/Form/use-field/use-field.js +1 -1
- package/dist/components/form/Form/use-form.js +1 -1
- package/dist/components/form/Form/validation.js +1 -1
- package/dist/components/form/Label.js +1 -1
- package/dist/components/form/validation/ValidationIndicator.js +1 -1
- package/dist/components/form/validation/resolve-validation-props.js +1 -1
- package/dist/components/form/validation/use-validation-props.js +1 -1
- package/dist/components/form/wrapper.js +1 -1
- package/dist/components/helpers/DisplayTransition/DisplayTransition.js +1 -1
- package/dist/components/helpers/IconSwitch/IconSwitch.d.ts +26 -0
- package/dist/components/helpers/IconSwitch/IconSwitch.js +1 -1
- package/dist/components/layout/Board/Board.d.ts +8 -0
- package/dist/components/layout/Board/Board.js +6 -5
- package/dist/components/layout/Board/Board.js.map +1 -1
- package/dist/components/layout/Board/BoardProvider.js +1 -1
- package/dist/components/layout/Board/BoardResponsive.js +1 -1
- package/dist/components/layout/Board/Widget.js +1 -1
- package/dist/components/layout/Board/WidgetHost.js +1 -1
- package/dist/components/layout/Board/board-context.js +1 -1
- package/dist/components/layout/Board/board-store.js +1 -1
- package/dist/components/layout/Board/grid-core/calculate.js +1 -1
- package/dist/components/layout/Board/grid-core/collision.js +1 -1
- package/dist/components/layout/Board/grid-core/compactors.js +2 -2
- package/dist/components/layout/Board/grid-core/constraints.js +1 -1
- package/dist/components/layout/Board/grid-core/group-move.js +84 -4
- package/dist/components/layout/Board/grid-core/group-move.js.map +1 -1
- package/dist/components/layout/Board/grid-core/layout.js +1 -1
- package/dist/components/layout/Board/grid-core/sort.js +1 -1
- package/dist/components/layout/Board/index.js +1 -1
- package/dist/components/layout/Board/responsive-utils.js +1 -1
- package/dist/components/layout/Board/use-board-layout.js +1 -1
- package/dist/components/layout/Board/use-board-registry.js +1 -1
- package/dist/components/layout/Board/use-board-select-modifier-key.js +1 -1
- package/dist/components/layout/Board/use-board-selection.js +1 -1
- package/dist/components/layout/Flex.js +1 -1
- package/dist/components/layout/Flow.js +1 -1
- package/dist/components/layout/Grid.js +1 -1
- package/dist/components/layout/Panel.js +1 -1
- package/dist/components/layout/Prefix.js +1 -1
- package/dist/components/layout/ResizablePanel.js +1 -1
- package/dist/components/layout/Space.js +1 -1
- package/dist/components/layout/Suffix.js +1 -1
- package/dist/components/navigation/Pagination/Pagination.d.ts +9 -0
- package/dist/components/navigation/Pagination/Pagination.js +258 -0
- package/dist/components/navigation/Pagination/Pagination.js.map +1 -0
- package/dist/components/navigation/Pagination/index.d.ts +4 -0
- package/dist/components/navigation/Pagination/types.d.ts +81 -0
- package/dist/components/navigation/Pagination/use-pagination.d.ts +52 -0
- package/dist/components/navigation/Pagination/use-pagination.js +83 -0
- package/dist/components/navigation/Pagination/use-pagination.js.map +1 -0
- 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/navigation/index.d.ts +5 -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/PeriodCalendar.js +1 -1
- package/dist/components/other/Calendar/RangeCalendar.js +1 -1
- package/dist/components/other/CubeLogo/CubeLogo.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/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 +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 +24 -8
- package/dist/components/shared/DraggableCollection.js.map +1 -1
- package/dist/components/shared/InvalidIcon.js +1 -1
- package/dist/components/shared/ValidIcon.js +1 -1
- package/dist/components/status/LoadingAnimation/LoadingAnimation.js +1 -1
- package/dist/components/status/Spin/Cube.js +1 -1
- package/dist/components/status/Spin/InternalSpinner.js +1 -1
- package/dist/components/status/Spin/Spin.js +1 -1
- package/dist/components/status/Spin/SpinsContainer.js +1 -1
- package/dist/data/item-themes.js +1 -1
- package/dist/data/themes.js +1 -1
- package/dist/eslint-plugin/defaults.generated.js +223 -5
- package/dist/eslint-plugin/defaults.generated.js.map +1 -1
- package/dist/eslint-plugin/index.js +1 -1
- package/dist/eslint-plugin/rules/no-redundant-default-prop.js +1 -1
- package/dist/i18n/I18nProvider.js +1 -1
- package/dist/i18n/createFormatter.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/instance.js +1 -1
- package/dist/i18n/locales/de-DE/uikit.js +36 -1
- package/dist/i18n/locales/en-US/uikit.js +36 -1
- package/dist/i18n/locales/en-US/uikit.json.d.ts +41 -1
- package/dist/i18n/locales/es-ES/uikit.js +36 -1
- package/dist/i18n/locales/es-MX/uikit.js +36 -1
- package/dist/i18n/locales/fr-FR/uikit.js +36 -1
- package/dist/i18n/locales/it-IT/uikit.js +36 -1
- package/dist/i18n/locales/ja-JP/uikit.js +36 -1
- package/dist/i18n/locales/nb-NO/uikit.js +36 -1
- package/dist/i18n/locales/pt-BR/uikit.js +36 -1
- package/dist/i18n/locales/pt-PT/uikit.js +36 -1
- package/dist/i18n/locales/sv-SE/uikit.js +36 -1
- package/dist/i18n/locales/vi-VN/uikit.js +36 -1
- package/dist/i18n/locales.js +1 -1
- package/dist/i18n/useFormatter.js +1 -1
- package/dist/i18n/useI18n.js +1 -1
- package/dist/icons/AdjustmentsHorizontalIcon.js +1 -1
- package/dist/icons/AdjustmentsIcon.js +1 -1
- package/dist/icons/AiIcon.js +1 -1
- package/dist/icons/AreaChartIcon.js +1 -1
- package/dist/icons/BackwardIcon.js +1 -1
- package/dist/icons/BarChartIcon.js +1 -1
- package/dist/icons/BellFilledIcon.js +1 -1
- package/dist/icons/BellIcon.js +1 -1
- package/dist/icons/BooleanIcon.js +1 -1
- package/dist/icons/CalendarEditIcon.js +1 -1
- package/dist/icons/CalendarIcon.js +1 -1
- package/dist/icons/CaretDownIcon.js +1 -1
- package/dist/icons/CaretUpIcon.js +1 -1
- package/dist/icons/ChartAreaStackedIcon.js +1 -1
- package/dist/icons/ChartAreaStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBarGroupedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarGroupedIcon.js +1 -1
- package/dist/icons/ChartBarHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarLineIcon.js +1 -1
- package/dist/icons/ChartBarStackedHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageHorizontalIcon.js +1 -1
- package/dist/icons/ChartBarStackedPercentageIcon.js +1 -1
- package/dist/icons/ChartBoxPlot2Icon.js +1 -1
- package/dist/icons/ChartBoxPlotIcon.js +1 -1
- package/dist/icons/ChartBubbleIcon.js +1 -1
- package/dist/icons/ChartDonut2Icon.js +1 -1
- package/dist/icons/ChartFunnelIcon.js +1 -1
- package/dist/icons/ChartHeatmapIcon.js +1 -1
- package/dist/icons/ChartKPIIcon.js +1 -1
- package/dist/icons/ChartPie2Icon.js +1 -1
- package/dist/icons/ChartScatterIcon.js +1 -1
- package/dist/icons/CheckCircleFilledIcon.js +1 -1
- package/dist/icons/CheckCircleIcon.js +1 -1
- package/dist/icons/CheckIcon.js +1 -1
- package/dist/icons/CircleFilledIcon.js +1 -1
- package/dist/icons/ClearIcon.js +1 -1
- package/dist/icons/CloseCircleFilledIcon.js +1 -1
- package/dist/icons/CloseCircleIcon.js +1 -1
- package/dist/icons/CloseIcon.js +1 -1
- package/dist/icons/CodeIcon.js +1 -1
- package/dist/icons/ColumnTotalIcon.js +1 -1
- package/dist/icons/CopyIcon.js +1 -1
- package/dist/icons/CountIcon.js +1 -1
- package/dist/icons/CubeIcon.js +1 -1
- package/dist/icons/CubePauseIcon.js +1 -1
- package/dist/icons/CubePlayIcon.js +1 -1
- package/dist/icons/CurrencyDollarIcon.js +1 -1
- package/dist/icons/DangerIcon.js +1 -1
- package/dist/icons/DashboardIcon.js +1 -1
- package/dist/icons/DatabaseIcon.js +1 -1
- package/dist/icons/DecimalDecreaseIcon.js +1 -1
- package/dist/icons/DecimalIncreaseIcon.js +1 -1
- package/dist/icons/DirectionIcon.js +1 -1
- package/dist/icons/DonutIcon.js +1 -1
- package/dist/icons/DownIcon.js +1 -1
- package/dist/icons/EditIcon.js +1 -1
- package/dist/icons/ExclamationCircleFilledIcon.js +1 -1
- package/dist/icons/ExclamationCircleIcon.js +1 -1
- package/dist/icons/ExclamationIcon.js +1 -1
- package/dist/icons/EyeIcon.js +1 -1
- package/dist/icons/EyeInvisibleIcon.js +1 -1
- package/dist/icons/FilterIcon.js +1 -1
- package/dist/icons/FolderFilledIcon.js +1 -1
- package/dist/icons/FolderIcon.js +1 -1
- package/dist/icons/FolderOpenFilledIcon.js +1 -1
- package/dist/icons/FolderOpenIcon.js +1 -1
- package/dist/icons/ForwardIcon.js +1 -1
- package/dist/icons/GripVerticalIcon.js +1 -1
- package/dist/icons/HierarchyIcon.js +1 -1
- package/dist/icons/HierarchyOpenIcon.js +1 -1
- package/dist/icons/Icon.js +1 -1
- package/dist/icons/InfoCircleIcon.js +1 -1
- package/dist/icons/InfoIcon.js +1 -1
- package/dist/icons/KeyIcon.js +1 -1
- package/dist/icons/LeftIcon.js +1 -1
- package/dist/icons/LineChartIcon.js +1 -1
- package/dist/icons/LoadingIcon.js +1 -1
- package/dist/icons/LockFilledIcon.js +1 -1
- package/dist/icons/LockIcon.js +1 -1
- package/dist/icons/MoreIcon.js +1 -1
- package/dist/icons/NotAllowedIcon.js +1 -1
- package/dist/icons/Number123Icon.js +1 -1
- package/dist/icons/NumberIcon.js +1 -1
- package/dist/icons/PauseCircleFilledIcon.js +1 -1
- package/dist/icons/PauseCircleIcon.js +1 -1
- package/dist/icons/PauseIcon.js +1 -1
- package/dist/icons/PercentageIcon.js +1 -1
- package/dist/icons/PieChartIcon.js +1 -1
- package/dist/icons/PipetteIcon.js +1 -1
- package/dist/icons/PlayCircleIcon.js +1 -1
- package/dist/icons/PlayIcon.js +1 -1
- package/dist/icons/PlusIcon.js +1 -1
- package/dist/icons/ProgressBarIcon.js +1 -1
- package/dist/icons/ReloadIcon.js +1 -1
- package/dist/icons/ReportIcon.js +1 -1
- package/dist/icons/ReturnIcon.js +1 -1
- package/dist/icons/RightIcon.js +1 -1
- package/dist/icons/RowTotalsIcon.js +1 -1
- package/dist/icons/SchemeIcon.js +1 -1
- package/dist/icons/SearchIcon.js +1 -1
- package/dist/icons/SemanticQueryIcon.js +1 -1
- package/dist/icons/SettingsIcon.js +1 -1
- package/dist/icons/ShieldFilledIcon.js +1 -1
- package/dist/icons/ShieldIcon.js +1 -1
- package/dist/icons/SlashIcon.js +1 -1
- package/dist/icons/SparklesIcon.js +1 -1
- package/dist/icons/SqlIcon.js +1 -1
- package/dist/icons/StatsIcon.js +1 -1
- package/dist/icons/StopIcon.js +1 -1
- package/dist/icons/StringIcon.js +1 -1
- package/dist/icons/SubtotalsIcon.js +1 -1
- package/dist/icons/SwitchIcon.js +1 -1
- package/dist/icons/TableIcon.js +1 -1
- package/dist/icons/ThumbsDownIcon.js +1 -1
- package/dist/icons/ThumbsUpIcon.js +1 -1
- package/dist/icons/ThunderboltCrossedIcon.js +1 -1
- package/dist/icons/ThunderboltFilledIcon.js +1 -1
- package/dist/icons/ThunderboltIcon.js +1 -1
- package/dist/icons/TimeIcon.js +1 -1
- package/dist/icons/TrashIcon.js +1 -1
- package/dist/icons/UnlockIcon.js +1 -1
- package/dist/icons/UpIcon.js +1 -1
- package/dist/icons/UserGroupIcon.js +1 -1
- package/dist/icons/UserIcon.js +1 -1
- package/dist/icons/UserLockIcon.js +1 -1
- package/dist/icons/ViewIcon.js +1 -1
- package/dist/icons/WarningFilledIcon.js +1 -1
- package/dist/icons/WarningIcon.js +1 -1
- package/dist/icons/wrap-icon.js +1 -1
- package/dist/index.d.ts +28 -14
- package/dist/index.js +15 -7
- 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/lazy-styles.js +1 -1
- package/dist/tokens/palette-config.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.d.ts +1 -1
- package/dist/tokens/typography.js +11 -2
- package/dist/tokens/typography.js.map +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/useBufferedValue.d.ts +56 -0
- package/dist/utils/react/useBufferedValue.js +86 -0
- package/dist/utils/react/useBufferedValue.js.map +1 -0
- package/dist/utils/react/useCombinedRefs.js +1 -1
- package/dist/utils/react/useControlledFocusVisible.js +1 -1
- package/dist/utils/react/useEventBus.js +1 -1
- package/dist/utils/react/useId.js +1 -1
- package/dist/utils/react/useIsDarwin.js +1 -1
- package/dist/utils/react/useKeySymbols.js +1 -1
- package/dist/utils/react/useLayoutEffect.js +1 -1
- package/dist/utils/react/useLocalStorage.js +1 -1
- package/dist/utils/react/useMergeStyles.js +1 -1
- package/dist/utils/react/usePopoverSync.js +1 -1
- package/dist/utils/react/useQaProps.js +1 -1
- package/dist/utils/react/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/ButtonGroup.md +1 -1
- package/docs/components/data/DataTable.md +298 -0
- package/docs/components/data/ItemTable.md +984 -0
- package/docs/components/fields/ColorInput.md +284 -0
- package/docs/components/fields/ColorPicker.md +85 -144
- package/docs/components/fields/ColorSwatchGroup.md +206 -0
- package/docs/components/fields/FilterPicker.md +1 -1
- package/docs/components/fields/ListBox.md +4 -0
- package/docs/components/fields/PasswordInput.md +1 -0
- package/docs/components/fields/Picker.md +1 -1
- package/docs/components/fields/SearchInput.md +1 -0
- package/docs/components/fields/TextArea.md +1 -0
- package/docs/components/fields/TextInput.md +1 -0
- package/docs/components/layout/Board.md +2 -1
- package/docs/components/navigation/Pagination.md +245 -0
- package/package.json +8 -3
- package/dist/components/fields/ColorPicker/ColorPickerPanel.js.map +0 -1
- package/dist/components/fields/ColorPicker/channels.js.map +0 -1
- package/dist/components/fields/ColorPicker/color.d.ts +0 -15
- package/dist/components/fields/ColorPicker/color.js.map +0 -1
- package/dist/components/organisms/FileTabs/FileTabs.d.ts +0 -54
- package/dist/components/organisms/FileTabs/FileTabs.js +0 -282
- package/dist/components/organisms/FileTabs/FileTabs.js.map +0 -1
- package/docs/components/organisms/FileTabs.md +0 -51
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-table-columns.js","names":[],"sources":["../../../../src/components/data/TableBase/use-table-columns.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nimport type {\n CubeResolvedColumn,\n CubeTableColumn,\n CubeTableColumnLayout,\n} from './types';\n\n/** @default when a column declares neither `width` nor `minWidth`. */\nexport const DEFAULT_MIN_WIDTH = 150;\n\n/**\n * Reads `key` as a data path. A plain key is a single property lookup; dots\n * walk nested objects (`'owner.name'`). Anything richer belongs in `getValue`.\n */\nexport function readPath(row: any, path: string): unknown {\n if (row == null) return undefined;\n if (!path.includes('.')) return row[path];\n\n let current: any = row;\n\n for (const part of path.split('.')) {\n if (current == null) return undefined;\n current = current[part];\n }\n\n return current;\n}\n\n/** Only the value-pipeline members, so both raw and resolved columns fit. */\ntype ValueColumn<T> = Pick<CubeTableColumn<T>, 'key' | 'getValue' | 'format'>;\n\nexport function getColumnValue<T>(\n column: ValueColumn<T>,\n row: T,\n rowIndex: number,\n): unknown {\n return column.getValue\n ? column.getValue(row, rowIndex)\n : readPath(row, column.key);\n}\n\n/**\n * Display text for a cell — what client sort, client search and TSV copy all\n * operate on. Deliberately NOT the rendered output: `render` may return\n * arbitrary React, and stringifying that is how cloud's filter ended up\n * matching `\"[object Object]\"` against the query `\"object\"`.\n *\n * Returns `null` when the column cannot produce text, so callers can skip it\n * rather than coerce a non-primitive.\n */\nexport function getColumnText<T>(\n column: ValueColumn<T>,\n row: T,\n rowIndex: number,\n): string | null {\n const value = getColumnValue(column, row, rowIndex);\n\n if (column.format) return column.format(value, row, rowIndex);\n if (value == null) return '';\n\n const type = typeof value;\n\n if (type === 'string') return value as string;\n if (type === 'number' || type === 'boolean' || type === 'bigint') {\n return String(value);\n }\n if (value instanceof Date) return value.toISOString();\n\n return null;\n}\n\nfunction clamp(value: number, min: number, max: number | null): number {\n return Math.min(Math.max(value, min), max ?? Number.POSITIVE_INFINITY);\n}\n\nexport interface UseTableColumnsOptions<T> {\n columns: CubeTableColumn<T>[];\n /** Content-box width of the scroller, or `null` before the first measure. */\n containerWidth: number | null;\n /** User-resized widths, keyed by column key. Wins over `column.width`. */\n columnWidths?: Record<string, number>;\n /** Extra leading columns owned by the table (selection, drag handle). */\n leadingColumns?: CubeTableColumn<T>[];\n /** Extra trailing columns owned by the table (row menu). */\n trailingColumns?: CubeTableColumn<T>[];\n}\n\n/**\n * Normalizes the public column list into resolved leaves: visual order, ARIA\n * indices, pixel widths, and sticky offsets for pinned columns.\n *\n * Width resolution mirrors ag-grid's `fitGridWidth`: fixed columns take their\n * width, the remainder is split across flex columns by weight, and each result\n * is clamped to `[minWidth, maxWidth]`. Clamping perturbs the sum, so the\n * residual is redistributed across the still-unclamped columns until it\n * settles. When even the minimums do not fit, every column takes its minimum\n * and the table scrolls horizontally.\n */\nexport function useTableColumns<T>({\n columns,\n containerWidth,\n columnWidths,\n leadingColumns,\n trailingColumns,\n}: UseTableColumnsOptions<T>): CubeTableColumnLayout<T> {\n return useMemo(() => {\n const visible = [\n ...(leadingColumns ?? []),\n ...columns,\n ...(trailingColumns ?? []),\n ].filter((column) => !column.isHidden);\n\n // Pinned columns lead and trail regardless of their position in the source\n // array, so `aria-colindex` and DOM order agree and nothing needs CSS\n // `order:` to be reshuffled.\n const ordered = [\n ...visible.filter((c) => c.pin === 'start'),\n ...visible.filter((c) => !c.pin),\n ...visible.filter((c) => c.pin === 'end'),\n ];\n\n const structuralKeys = new Set(\n [...(leadingColumns ?? []), ...(trailingColumns ?? [])].map((c) => c.key),\n );\n\n const specs = ordered.map((column) => {\n const isStructural = structuralKeys.has(column.key);\n const explicit = columnWidths?.[column.key] ?? column.width;\n const minWidth =\n column.minWidth ??\n (explicit != null ? explicit : isStructural ? 0 : DEFAULT_MIN_WIDTH);\n\n return {\n column,\n isStructural,\n fixed: explicit ?? null,\n minWidth,\n maxWidth: column.maxWidth ?? null,\n flex: explicit != null ? null : column.flex ?? 1,\n };\n });\n\n const resolved = new Map<string, number>();\n let isOverflowing = false;\n\n if (containerWidth != null && containerWidth > 0) {\n const fixedTotal = specs.reduce((sum, s) => sum + (s.fixed ?? 0), 0);\n const flexSpecs = specs.filter((s) => s.fixed == null);\n const minTotal = specs.reduce(\n (sum, s) => sum + (s.fixed ?? s.minWidth),\n 0,\n );\n\n if (minTotal > containerWidth) {\n isOverflowing = true;\n for (const spec of specs) {\n resolved.set(spec.column.key, spec.fixed ?? spec.minWidth);\n }\n } else {\n let remaining = containerWidth - fixedTotal;\n let pool = flexSpecs;\n\n // Each pass assigns proportional widths, freezes whatever hit a bound,\n // and re-splits the leftover among the rest.\n while (pool.length > 0) {\n const totalFlex = pool.reduce((sum, s) => sum + (s.flex ?? 1), 0);\n const nextPool: typeof pool = [];\n let consumed = 0;\n\n for (const spec of pool) {\n const ideal = (remaining * (spec.flex ?? 1)) / (totalFlex || 1);\n const clamped = clamp(ideal, spec.minWidth, spec.maxWidth);\n\n if (clamped !== ideal) {\n resolved.set(spec.column.key, clamped);\n consumed += clamped;\n } else {\n nextPool.push(spec);\n }\n }\n\n if (nextPool.length === pool.length) {\n // Nothing was clamped this pass — the proportional split stands.\n const totalLeft = nextPool.reduce(\n (sum, s) => sum + (s.flex ?? 1),\n 0,\n );\n for (const spec of nextPool) {\n resolved.set(\n spec.column.key,\n (remaining * (spec.flex ?? 1)) / (totalLeft || 1),\n );\n }\n break;\n }\n\n remaining -= consumed;\n pool = nextPool;\n }\n\n for (const spec of specs) {\n if (spec.fixed != null) resolved.set(spec.column.key, spec.fixed);\n }\n }\n }\n\n let pinnedStartWidth = 0;\n let pinnedEndWidth = 0;\n\n const out: CubeResolvedColumn<T>[] = specs.map((spec, index) => ({\n ...spec.column,\n index,\n ariaColIndex: index + 1,\n width: resolved.get(spec.column.key) ?? null,\n minWidth: spec.minWidth,\n maxWidth: spec.maxWidth,\n flex: spec.flex,\n align: spec.column.align ?? 'start',\n pinOffset: null,\n isPinEdge: false,\n isStructural: spec.isStructural,\n }));\n\n // Sticky offsets accumulate inwards from each edge.\n for (const column of out) {\n if (column.pin !== 'start') continue;\n column.pinOffset = pinnedStartWidth;\n pinnedStartWidth += column.width ?? column.minWidth;\n }\n\n for (let i = out.length - 1; i >= 0; i--) {\n const column = out[i];\n if (column.pin !== 'end') continue;\n column.pinOffset = pinnedEndWidth;\n pinnedEndWidth += column.width ?? column.minWidth;\n }\n\n const lastPinnedStart = out.filter((c) => c.pin === 'start').at(-1);\n const firstPinnedEnd = out.find((c) => c.pin === 'end');\n\n if (lastPinnedStart) lastPinnedStart.isPinEdge = true;\n if (firstPinnedEnd) firstPinnedEnd.isPinEdge = true;\n\n const totalWidth = out.every((c) => c.width != null)\n ? out.reduce((sum, c) => sum + (c.width ?? 0), 0)\n : null;\n\n return {\n columns: out,\n pinnedStartWidth,\n pinnedEndWidth,\n totalWidth,\n isOverflowing,\n };\n }, [columns, containerWidth, columnWidths, leadingColumns, trailingColumns]);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.157.1 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { useDebouncedValue } from "../../../_internal/hooks/use-debounced-value.js";
|
|
4
|
+
import { getColumnText } from "./use-table-columns.js";
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { useControlledState } from "@react-stately/utils";
|
|
7
|
+
|
|
8
|
+
//#region src/components/data/TableBase/use-table-search.ts
|
|
9
|
+
/**
|
|
10
|
+
* Default matcher: a case-insensitive substring test against each searchable
|
|
11
|
+
* column's **display text**.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately not the raw value. Cloud's filter tested
|
|
14
|
+
* `String(row[column.key])`, which meant a column rendering `owner.profile.name`
|
|
15
|
+
* was unsearchable, and an object-valued column stringified to
|
|
16
|
+
* `"[object Object]"` — so the query "object" matched every row with a nested
|
|
17
|
+
* value. `getColumnText` returns `null` for anything it cannot honestly turn
|
|
18
|
+
* into text, and those columns are skipped rather than coerced.
|
|
19
|
+
*/
|
|
20
|
+
function defaultMatcher(columns, row, rowIndex, query) {
|
|
21
|
+
return columns.some((column) => {
|
|
22
|
+
if (column.isSearchable === false) return false;
|
|
23
|
+
const text = getColumnText(column, row, rowIndex);
|
|
24
|
+
return text != null && text.toLowerCase().includes(query);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function useTableSearch({ columns, rows, mode = "client", value, defaultValue, onChange, delay = 500, filter }) {
|
|
28
|
+
const [committed, setCommitted] = useControlledState(value, defaultValue ?? "", onChange);
|
|
29
|
+
const [draft, setDraft] = useState(committed);
|
|
30
|
+
const debounced = useDebouncedValue(draft, delay);
|
|
31
|
+
const pushedRef = useRef(committed);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (committed === pushedRef.current) return;
|
|
34
|
+
pushedRef.current = committed;
|
|
35
|
+
setDraft(committed);
|
|
36
|
+
}, [committed]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (debounced === pushedRef.current) return;
|
|
39
|
+
pushedRef.current = debounced;
|
|
40
|
+
setCommitted(debounced);
|
|
41
|
+
}, [debounced]);
|
|
42
|
+
const searchValue = draft;
|
|
43
|
+
const query = debounced.trim().toLowerCase();
|
|
44
|
+
return {
|
|
45
|
+
searchValue,
|
|
46
|
+
setSearchValue: useEvent((next) => setDraft(next)),
|
|
47
|
+
query,
|
|
48
|
+
searchedRows: useMemo(() => {
|
|
49
|
+
if (mode !== "client" || !query) return rows;
|
|
50
|
+
return rows.filter((row, index) => filter ? filter(row, query) : defaultMatcher(columns, row, index, query));
|
|
51
|
+
}, [
|
|
52
|
+
mode,
|
|
53
|
+
query,
|
|
54
|
+
rows,
|
|
55
|
+
columns,
|
|
56
|
+
filter
|
|
57
|
+
]),
|
|
58
|
+
isFiltered: query.length > 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { useTableSearch };
|
|
64
|
+
//# sourceMappingURL=use-table-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-table-search.js","names":[],"sources":["../../../../src/components/data/TableBase/use-table-search.ts"],"sourcesContent":["import { useControlledState } from '@react-stately/utils';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useDebouncedValue, useEvent } from '../../../_internal/hooks';\n\nimport { getColumnText } from './use-table-columns';\n\nimport type { CubeTableColumn } from './types';\n\nexport type CubeTableSearchMode = 'client' | 'server';\n\nexport interface UseTableSearchOptions<T> {\n columns: CubeTableColumn<T>[];\n rows: readonly T[];\n /** @default 'client' */\n mode?: CubeTableSearchMode;\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n /** Debounces the filter AND the callback, in both modes. @default 500 */\n delay?: number;\n /** Replaces the default matcher in client mode. */\n filter?: (row: T, query: string) => boolean;\n}\n\nexport interface UseTableSearchResult<T> {\n /** The immediate term — what the input shows. */\n searchValue: string;\n setSearchValue: (value: string) => void;\n /** The debounced term — what the filter and the callback act on. */\n query: string;\n /** Filtered in client mode; the original array otherwise. */\n searchedRows: readonly T[];\n /** `true` when a non-empty term is narrowing the data. */\n isFiltered: boolean;\n}\n\n/**\n * Default matcher: a case-insensitive substring test against each searchable\n * column's **display text**.\n *\n * Deliberately not the raw value. Cloud's filter tested\n * `String(row[column.key])`, which meant a column rendering `owner.profile.name`\n * was unsearchable, and an object-valued column stringified to\n * `\"[object Object]\"` — so the query \"object\" matched every row with a nested\n * value. `getColumnText` returns `null` for anything it cannot honestly turn\n * into text, and those columns are skipped rather than coerced.\n */\nfunction defaultMatcher<T>(\n columns: CubeTableColumn<T>[],\n row: T,\n rowIndex: number,\n query: string,\n): boolean {\n return columns.some((column) => {\n if (column.isSearchable === false) return false;\n\n const text = getColumnText(column, row, rowIndex);\n\n return text != null && text.toLowerCase().includes(query);\n });\n}\n\nexport function useTableSearch<T>({\n columns,\n rows,\n mode = 'client',\n value,\n defaultValue,\n onChange,\n delay = 500,\n filter,\n}: UseTableSearchOptions<T>): UseTableSearchResult<T> {\n const [committed, setCommitted] = useControlledState<string>(\n value as string,\n defaultValue ?? '',\n onChange as (v: string) => void,\n );\n\n // What the input shows, updated on every keystroke. The committed value —\n // the one `onChange` reports and the filter runs on — trails it by `delay`.\n //\n // Two separate values rather than one, because `useControlledState` calls\n // `onChange` the moment it is set: routing keystrokes straight into it fired\n // a request per character in `searchMode=\"server\"`, which is the thing the\n // debounce exists to prevent. Debouncing the input itself instead would make\n // typing lag, so the split is the point.\n const [draft, setDraft] = useState(committed);\n const debounced = useDebouncedValue(draft, delay);\n\n // What we last pushed outward, so the sync below can tell a genuine external\n // change from the echo of our own debounce.\n const pushedRef = useRef(committed);\n\n // A controlled `searchValue` changing from OUTSIDE — a cleared filter, a\n // restored URL — wins over whatever is half-typed.\n //\n // The echo has to be filtered out or this reverts the input mid-word: with a\n // short delay the debounce commits letter 1 while letter 2 is already typed,\n // and syncing unconditionally puts letter 1 back. At `searchDelay={0}` that\n // happens on every keystroke and nothing longer than one character can ever\n // be typed.\n useEffect(() => {\n if (committed === pushedRef.current) return;\n\n pushedRef.current = committed;\n setDraft(committed);\n }, [committed]);\n\n useEffect(() => {\n if (debounced === pushedRef.current) return;\n\n pushedRef.current = debounced;\n setCommitted(debounced);\n // `committed` is deliberately not a dependency: reacting to it here would\n // fight the effect above and push a stale draft back out.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [debounced]);\n\n const searchValue = draft;\n const query = debounced.trim().toLowerCase();\n\n const setSearchValue = useEvent((next: string) => setDraft(next));\n\n const searchedRows = useMemo(() => {\n if (mode !== 'client' || !query) return rows;\n\n return rows.filter((row, index) =>\n filter ? filter(row, query) : defaultMatcher(columns, row, index, query),\n );\n }, [mode, query, rows, columns, filter]);\n\n return {\n searchValue,\n setSearchValue,\n query,\n searchedRows,\n isFiltered: query.length > 0,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgDA,SAAS,eACP,SACA,KACA,UACA,OACS;AACT,QAAO,QAAQ,MAAM,WAAW;AAC9B,MAAI,OAAO,iBAAiB,MAAO,QAAO;EAE1C,MAAM,OAAO,cAAc,QAAQ,KAAK,SAAS;AAEjD,SAAO,QAAQ,QAAQ,KAAK,aAAa,CAAC,SAAS,MAAM;GACzD;;AAGJ,SAAgB,eAAkB,EAChC,SACA,MACA,OAAO,UACP,OACA,cACA,UACA,QAAQ,KACR,UACoD;CACpD,MAAM,CAAC,WAAW,gBAAgB,mBAChC,OACA,gBAAgB,IAChB,SACD;CAUD,MAAM,CAAC,OAAO,YAAY,SAAS,UAAU;CAC7C,MAAM,YAAY,kBAAkB,OAAO,MAAM;CAIjD,MAAM,YAAY,OAAO,UAAU;AAUnC,iBAAgB;AACd,MAAI,cAAc,UAAU,QAAS;AAErC,YAAU,UAAU;AACpB,WAAS,UAAU;IAClB,CAAC,UAAU,CAAC;AAEf,iBAAgB;AACd,MAAI,cAAc,UAAU,QAAS;AAErC,YAAU,UAAU;AACpB,eAAa,UAAU;IAItB,CAAC,UAAU,CAAC;CAEf,MAAM,cAAc;CACpB,MAAM,QAAQ,UAAU,MAAM,CAAC,aAAa;AAY5C,QAAO;EACL;EACA,gBAZqB,UAAU,SAAiB,SAAS,KAAK,CAAC;EAa/D;EACA,cAZmB,cAAc;AACjC,OAAI,SAAS,YAAY,CAAC,MAAO,QAAO;AAExC,UAAO,KAAK,QAAQ,KAAK,UACvB,SAAS,OAAO,KAAK,MAAM,GAAG,eAAe,SAAS,KAAK,OAAO,MAAM,CACzE;KACA;GAAC;GAAM;GAAO;GAAM;GAAS;GAAO,CAAC;EAOtC,YAAY,MAAM,SAAS;EAC5B"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.157.1 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { RowCollection } from "./RowCollection.js";
|
|
4
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
5
|
+
import { useMultipleSelectionState } from "react-stately";
|
|
6
|
+
import { SelectionManager } from "@react-stately/selection";
|
|
7
|
+
|
|
8
|
+
//#region src/components/data/TableBase/use-table-selection.ts
|
|
9
|
+
/**
|
|
10
|
+
* Reserved key for the checkbox column. Prefixed so it cannot collide with a
|
|
11
|
+
* real data key, and structural so the value pipeline, sorting and search all
|
|
12
|
+
* skip it.
|
|
13
|
+
*/
|
|
14
|
+
const SELECTION_COLUMN_KEY = "__cube-selection__";
|
|
15
|
+
/** Reserved key for the row-number column. Structural, like the checkbox. */
|
|
16
|
+
const ROW_NUMBER_COLUMN_KEY = "__cube-row-number__";
|
|
17
|
+
/** Square-ish, so the checkbox sits centred without stealing content width. */
|
|
18
|
+
const SELECTION_COLUMN_WIDTH = {
|
|
19
|
+
xsmall: 32,
|
|
20
|
+
small: 36,
|
|
21
|
+
medium: 44,
|
|
22
|
+
large: 48,
|
|
23
|
+
xlarge: 52
|
|
24
|
+
};
|
|
25
|
+
function toSelection(keys) {
|
|
26
|
+
if (keys === void 0) return void 0;
|
|
27
|
+
return keys === "all" ? "all" : new Set(keys);
|
|
28
|
+
}
|
|
29
|
+
function useTableSelection(options) {
|
|
30
|
+
const { rows, filteredRows, getRowKey, selectionMode, selectedKeys: selectedKeysProp, defaultSelectedKeys, onSelectionChange, selectAllMode, isRowSelectable, disabledKeys } = options;
|
|
31
|
+
const isEnabled = selectionMode !== "none";
|
|
32
|
+
/**
|
|
33
|
+
* Two distinct notions of "not available", deliberately kept apart:
|
|
34
|
+
*
|
|
35
|
+
* - `disabledKeys` — the row is inert. Not focusable, not interactive. This
|
|
36
|
+
* is React Aria's standard meaning.
|
|
37
|
+
* - `isRowSelectable` — the row is fully interactive, only its checkbox is
|
|
38
|
+
* inert. This is what Cloud's tables do today.
|
|
39
|
+
*
|
|
40
|
+
* A `SelectionManager` has one `disabledBehavior`, so it gets the union under
|
|
41
|
+
* `'selection'` (neither kind can be selected) and the hard-disabled set is
|
|
42
|
+
* tracked separately for focus and interaction.
|
|
43
|
+
*/
|
|
44
|
+
const hardDisabledKeys = useMemo(() => new Set(disabledKeys ?? []), [disabledKeys]);
|
|
45
|
+
const unselectableKeys = useMemo(() => {
|
|
46
|
+
const keys = new Set(hardDisabledKeys);
|
|
47
|
+
if (isRowSelectable) filteredRows.forEach((row, index) => {
|
|
48
|
+
if (!isRowSelectable(row)) keys.add(getRowKey(row, index));
|
|
49
|
+
});
|
|
50
|
+
return keys;
|
|
51
|
+
}, [
|
|
52
|
+
hardDisabledKeys,
|
|
53
|
+
isRowSelectable,
|
|
54
|
+
filteredRows,
|
|
55
|
+
getRowKey
|
|
56
|
+
]);
|
|
57
|
+
const collection = useMemo(() => new RowCollection(rows, getRowKey, unselectableKeys), [
|
|
58
|
+
rows,
|
|
59
|
+
getRowKey,
|
|
60
|
+
unselectableKeys
|
|
61
|
+
]);
|
|
62
|
+
const rowByKey = useMemo(() => {
|
|
63
|
+
const map = /* @__PURE__ */ new Map();
|
|
64
|
+
filteredRows.forEach((row, index) => map.set(getRowKey(row, index), row));
|
|
65
|
+
rows.forEach((row, index) => map.set(getRowKey(row, index), row));
|
|
66
|
+
return map;
|
|
67
|
+
}, [
|
|
68
|
+
rows,
|
|
69
|
+
filteredRows,
|
|
70
|
+
getRowKey
|
|
71
|
+
]);
|
|
72
|
+
const rowByKeyRef = useRef(rowByKey);
|
|
73
|
+
rowByKeyRef.current = rowByKey;
|
|
74
|
+
/**
|
|
75
|
+
* Where a shift-range starts, and how far it currently reaches.
|
|
76
|
+
*
|
|
77
|
+
* React Aria's `SelectionManager.extendSelection` keeps this on the `Selection`
|
|
78
|
+
* object itself (`selectedKeys.anchorKey`), which cannot survive our public
|
|
79
|
+
* API: `selectedKeys` is `Key[]`, and `useMultipleSelectionState` rebuilds
|
|
80
|
+
* whatever it is given with `new Selection(value)` — a constructor that only
|
|
81
|
+
* copies the anchor when the input is already a `Selection`, a class no
|
|
82
|
+
* package exports. A controlled table would silently reset the anchor to the
|
|
83
|
+
* clicked row and turn every shift-click into a plain toggle.
|
|
84
|
+
*
|
|
85
|
+
* So the range is computed here instead, over `RowCollection`'s index. The
|
|
86
|
+
* semantics match `extendSelection` exactly: the previous range is removed
|
|
87
|
+
* before the new one is added, so shift-clicking back shrinks the range
|
|
88
|
+
* rather than leaving the overshoot selected.
|
|
89
|
+
*/
|
|
90
|
+
const anchorRef = useRef(null);
|
|
91
|
+
const extentRef = useRef(null);
|
|
92
|
+
const handleSelectionChange = useEvent((keys) => {
|
|
93
|
+
if (!onSelectionChange) return;
|
|
94
|
+
if (keys === "all") {
|
|
95
|
+
onSelectionChange("all", [...rowByKeyRef.current.values()]);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const list = [...keys];
|
|
99
|
+
onSelectionChange(list, list.map((key) => rowByKeyRef.current.get(key)).filter((row) => row !== void 0));
|
|
100
|
+
});
|
|
101
|
+
const state = useMultipleSelectionState({
|
|
102
|
+
selectionMode,
|
|
103
|
+
selectedKeys: useMemo(() => toSelection(selectedKeysProp), [selectedKeysProp]),
|
|
104
|
+
defaultSelectedKeys: useMemo(() => toSelection(defaultSelectedKeys), [defaultSelectedKeys]),
|
|
105
|
+
disabledKeys: unselectableKeys,
|
|
106
|
+
disabledBehavior: "selection",
|
|
107
|
+
onSelectionChange: handleSelectionChange
|
|
108
|
+
});
|
|
109
|
+
const selectionManager = useMemo(() => new SelectionManager(collection, state), [collection, state]);
|
|
110
|
+
const selectedKeys = state.selectedKeys;
|
|
111
|
+
const isAll = selectedKeys === "all";
|
|
112
|
+
const canSelect = useCallback((key) => isEnabled && !unselectableKeys.has(key), [isEnabled, unselectableKeys]);
|
|
113
|
+
const isSelected = useCallback((key) => isAll ? canSelect(key) : selectedKeys.has(key), [
|
|
114
|
+
isAll,
|
|
115
|
+
selectedKeys,
|
|
116
|
+
canSelect
|
|
117
|
+
]);
|
|
118
|
+
/** Keys the header checkbox acts on, which is what `selectAllMode` decides. */
|
|
119
|
+
const scopeKeys = useMemo(() => {
|
|
120
|
+
if (!isEnabled || selectionMode === "single") return [];
|
|
121
|
+
return (selectAllMode === "page" ? rows : filteredRows).map((row, index) => getRowKey(row, index)).filter((key) => !unselectableKeys.has(key));
|
|
122
|
+
}, [
|
|
123
|
+
isEnabled,
|
|
124
|
+
selectionMode,
|
|
125
|
+
selectAllMode,
|
|
126
|
+
rows,
|
|
127
|
+
filteredRows,
|
|
128
|
+
getRowKey,
|
|
129
|
+
unselectableKeys
|
|
130
|
+
]);
|
|
131
|
+
const selectAllState = useMemo(() => {
|
|
132
|
+
if (isAll) return "all";
|
|
133
|
+
if (!scopeKeys.length) return "none";
|
|
134
|
+
const set = selectedKeys;
|
|
135
|
+
let count = 0;
|
|
136
|
+
for (const key of scopeKeys) if (set.has(key)) count++;
|
|
137
|
+
return count === 0 ? "none" : count === scopeKeys.length ? "all" : "some";
|
|
138
|
+
}, [
|
|
139
|
+
isAll,
|
|
140
|
+
selectedKeys,
|
|
141
|
+
scopeKeys
|
|
142
|
+
]);
|
|
143
|
+
const toggleSelectAll = useEvent(() => {
|
|
144
|
+
anchorRef.current = null;
|
|
145
|
+
extentRef.current = null;
|
|
146
|
+
if (selectAllState === "all") {
|
|
147
|
+
state.setSelectedKeys(/* @__PURE__ */ new Set());
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (selectAllMode === "all") {
|
|
151
|
+
state.setSelectedKeys("all");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const next = new Set(isAll ? [] : selectedKeys);
|
|
155
|
+
scopeKeys.forEach((key) => next.add(key));
|
|
156
|
+
state.setSelectedKeys(next);
|
|
157
|
+
});
|
|
158
|
+
const clearSelection = useEvent(() => {
|
|
159
|
+
anchorRef.current = null;
|
|
160
|
+
extentRef.current = null;
|
|
161
|
+
state.setSelectedKeys(/* @__PURE__ */ new Set());
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* Shift held on the press that produced this change. `Checkbox` reports only
|
|
165
|
+
* the next value, so the modifier is captured from the pointer/key event on
|
|
166
|
+
* the cell and read back here.
|
|
167
|
+
*/
|
|
168
|
+
const shiftRef = useRef(false);
|
|
169
|
+
const captureShift = useCallback((event) => {
|
|
170
|
+
shiftRef.current = event.shiftKey;
|
|
171
|
+
}, []);
|
|
172
|
+
/** Selectable keys between two rows, inclusive, in either direction. */
|
|
173
|
+
const keysBetween = useCallback((from, to) => {
|
|
174
|
+
const fromIndex = collection.indexOf(from);
|
|
175
|
+
const toIndex = collection.indexOf(to);
|
|
176
|
+
if (fromIndex < 0 || toIndex < 0) return [];
|
|
177
|
+
const [lo, hi] = fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
|
|
178
|
+
const all = collection.getKeys();
|
|
179
|
+
const range = [];
|
|
180
|
+
for (let i = lo; i <= hi; i++) range.push(all[i]);
|
|
181
|
+
return range;
|
|
182
|
+
}, [collection]);
|
|
183
|
+
const toggleRow = useEvent((key) => {
|
|
184
|
+
if (!canSelect(key)) return;
|
|
185
|
+
if (selectionMode === "single") {
|
|
186
|
+
state.setSelectedKeys(isSelected(key) ? /* @__PURE__ */ new Set() : new Set([key]));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const anchor = anchorRef.current;
|
|
190
|
+
if (shiftRef.current && anchor != null && collection.indexOf(anchor) >= 0) {
|
|
191
|
+
const next = new Set(isAll ? scopeKeys : selectedKeys);
|
|
192
|
+
if (extentRef.current != null) keysBetween(anchor, extentRef.current).forEach((k) => next.delete(k));
|
|
193
|
+
keysBetween(anchor, key).forEach((k) => {
|
|
194
|
+
if (canSelect(k)) next.add(k);
|
|
195
|
+
});
|
|
196
|
+
extentRef.current = key;
|
|
197
|
+
state.setSelectedKeys(next);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
anchorRef.current = key;
|
|
201
|
+
extentRef.current = null;
|
|
202
|
+
selectionManager.toggleSelection(key);
|
|
203
|
+
});
|
|
204
|
+
const selectedRows = useMemo(() => {
|
|
205
|
+
if (isAll) return [...rowByKey.values()];
|
|
206
|
+
return [...selectedKeys].map((key) => rowByKey.get(key)).filter((row) => row !== void 0);
|
|
207
|
+
}, [
|
|
208
|
+
isAll,
|
|
209
|
+
selectedKeys,
|
|
210
|
+
rowByKey
|
|
211
|
+
]);
|
|
212
|
+
return {
|
|
213
|
+
isEnabled,
|
|
214
|
+
selectionMode,
|
|
215
|
+
selectionManager,
|
|
216
|
+
collection,
|
|
217
|
+
isSelected,
|
|
218
|
+
canSelect,
|
|
219
|
+
isRowDisabled: useCallback((key) => hardDisabledKeys.has(key), [hardDisabledKeys]),
|
|
220
|
+
toggleRow,
|
|
221
|
+
captureShift,
|
|
222
|
+
selectAllState,
|
|
223
|
+
toggleSelectAll,
|
|
224
|
+
clearSelection,
|
|
225
|
+
selectedRows,
|
|
226
|
+
selectedCount: isAll ? rowByKey.size : selectedKeys.size,
|
|
227
|
+
selectedKeys: isAll ? "all" : [...selectedKeys]
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//#endregion
|
|
232
|
+
export { ROW_NUMBER_COLUMN_KEY, SELECTION_COLUMN_KEY, SELECTION_COLUMN_WIDTH, useTableSelection };
|
|
233
|
+
//# sourceMappingURL=use-table-selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-table-selection.js","names":[],"sources":["../../../../src/components/data/TableBase/use-table-selection.ts"],"sourcesContent":["import { SelectionManager } from '@react-stately/selection';\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useMultipleSelectionState } from 'react-stately';\n\nimport { useEvent } from '../../../_internal/hooks';\n\nimport { RowCollection } from './RowCollection';\n\nimport type { Key, Selection } from '@react-types/shared';\nimport type { CubeTableSelectAllMode, CubeTableSelectionMode } from './types';\n\n/**\n * Reserved key for the checkbox column. Prefixed so it cannot collide with a\n * real data key, and structural so the value pipeline, sorting and search all\n * skip it.\n */\nexport const SELECTION_COLUMN_KEY = '__cube-selection__';\n\n/** Reserved key for the row-number column. Structural, like the checkbox. */\nexport const ROW_NUMBER_COLUMN_KEY = '__cube-row-number__';\n\n/** Square-ish, so the checkbox sits centred without stealing content width. */\nexport const SELECTION_COLUMN_WIDTH: Record<string, number> = {\n xsmall: 32,\n small: 36,\n medium: 44,\n large: 48,\n xlarge: 52,\n};\n\nexport interface UseTableSelectionOptions<T> {\n /** Rows currently on screen — one page, or everything when unpaginated. */\n rows: readonly T[];\n /**\n * Every row passing the current search/filter, across pages. Only differs\n * from `rows` under client pagination, and only `selectAllMode=\"filtered\"`\n * reads it.\n */\n filteredRows: readonly T[];\n getRowKey: (row: T, index: number) => Key;\n selectionMode: CubeTableSelectionMode;\n selectedKeys?: Key[] | 'all';\n defaultSelectedKeys?: Key[] | 'all';\n onSelectionChange?: (keys: Key[] | 'all', rows: T[]) => void;\n selectAllMode: CubeTableSelectAllMode;\n isRowSelectable?: (row: T) => boolean;\n disabledKeys?: Key[];\n}\n\nexport type CubeTableSelectAllState = 'none' | 'some' | 'all';\n\nfunction toSelection(keys: Key[] | 'all' | undefined): Selection | undefined {\n if (keys === undefined) return undefined;\n\n return keys === 'all' ? 'all' : new Set(keys);\n}\n\nexport function useTableSelection<T>(options: UseTableSelectionOptions<T>) {\n const {\n rows,\n filteredRows,\n getRowKey,\n selectionMode,\n selectedKeys: selectedKeysProp,\n defaultSelectedKeys,\n onSelectionChange,\n selectAllMode,\n isRowSelectable,\n disabledKeys,\n } = options;\n\n const isEnabled = selectionMode !== 'none';\n\n /**\n * Two distinct notions of \"not available\", deliberately kept apart:\n *\n * - `disabledKeys` — the row is inert. Not focusable, not interactive. This\n * is React Aria's standard meaning.\n * - `isRowSelectable` — the row is fully interactive, only its checkbox is\n * inert. This is what Cloud's tables do today.\n *\n * A `SelectionManager` has one `disabledBehavior`, so it gets the union under\n * `'selection'` (neither kind can be selected) and the hard-disabled set is\n * tracked separately for focus and interaction.\n */\n const hardDisabledKeys = useMemo(\n () => new Set(disabledKeys ?? []),\n [disabledKeys],\n );\n\n const unselectableKeys = useMemo(() => {\n const keys = new Set(hardDisabledKeys);\n\n if (isRowSelectable) {\n // Scanned over the filtered set, not just the page: a select-all that\n // reaches beyond the page must respect it there too.\n filteredRows.forEach((row, index) => {\n if (!isRowSelectable(row)) keys.add(getRowKey(row, index));\n });\n }\n\n return keys;\n }, [hardDisabledKeys, isRowSelectable, filteredRows, getRowKey]);\n\n const collection = useMemo(\n () => new RowCollection(rows, getRowKey, unselectableKeys),\n [rows, getRowKey, unselectableKeys],\n );\n\n const rowByKey = useMemo(() => {\n const map = new Map<Key, T>();\n\n // The page first, then the wider filtered set, so a key present in both\n // resolves to the row the user can actually see.\n filteredRows.forEach((row, index) => map.set(getRowKey(row, index), row));\n rows.forEach((row, index) => map.set(getRowKey(row, index), row));\n\n return map;\n }, [rows, filteredRows, getRowKey]);\n\n const rowByKeyRef = useRef(rowByKey);\n\n rowByKeyRef.current = rowByKey;\n\n /**\n * Where a shift-range starts, and how far it currently reaches.\n *\n * React Aria's `SelectionManager.extendSelection` keeps this on the `Selection`\n * object itself (`selectedKeys.anchorKey`), which cannot survive our public\n * API: `selectedKeys` is `Key[]`, and `useMultipleSelectionState` rebuilds\n * whatever it is given with `new Selection(value)` — a constructor that only\n * copies the anchor when the input is already a `Selection`, a class no\n * package exports. A controlled table would silently reset the anchor to the\n * clicked row and turn every shift-click into a plain toggle.\n *\n * So the range is computed here instead, over `RowCollection`'s index. The\n * semantics match `extendSelection` exactly: the previous range is removed\n * before the new one is added, so shift-clicking back shrinks the range\n * rather than leaving the overshoot selected.\n */\n const anchorRef = useRef<Key | null>(null);\n const extentRef = useRef<Key | null>(null);\n\n const handleSelectionChange = useEvent((keys: Selection) => {\n if (!onSelectionChange) return;\n\n if (keys === 'all') {\n // The sentinel means \"everything, including rows the client has not\n // loaded\", so the row list can only ever be what is loaded.\n onSelectionChange('all', [...rowByKeyRef.current.values()]);\n\n return;\n }\n\n const list = [...keys];\n\n onSelectionChange(\n list,\n list\n .map((key) => rowByKeyRef.current.get(key))\n .filter((row): row is T => row !== undefined),\n );\n });\n\n const controlledSelection = useMemo(\n () => toSelection(selectedKeysProp),\n [selectedKeysProp],\n );\n const defaultSelection = useMemo(\n () => toSelection(defaultSelectedKeys),\n [defaultSelectedKeys],\n );\n\n const state = useMultipleSelectionState({\n selectionMode,\n selectedKeys: controlledSelection,\n defaultSelectedKeys: defaultSelection,\n disabledKeys: unselectableKeys,\n disabledBehavior: 'selection',\n onSelectionChange: handleSelectionChange,\n });\n\n const selectionManager = useMemo(\n () => new SelectionManager(collection, state),\n [collection, state],\n );\n\n const selectedKeys = state.selectedKeys;\n const isAll = selectedKeys === 'all';\n\n const canSelect = useCallback(\n (key: Key) => isEnabled && !unselectableKeys.has(key),\n [isEnabled, unselectableKeys],\n );\n\n const isSelected = useCallback(\n (key: Key) =>\n isAll ? canSelect(key) : (selectedKeys as Set<Key>).has(key),\n [isAll, selectedKeys, canSelect],\n );\n\n /** Keys the header checkbox acts on, which is what `selectAllMode` decides. */\n const scopeKeys = useMemo(() => {\n if (!isEnabled || selectionMode === 'single') return [];\n\n const source = selectAllMode === 'page' ? rows : filteredRows;\n\n return source\n .map((row, index) => getRowKey(row, index))\n .filter((key) => !unselectableKeys.has(key));\n }, [\n isEnabled,\n selectionMode,\n selectAllMode,\n rows,\n filteredRows,\n getRowKey,\n unselectableKeys,\n ]);\n\n const selectAllState: CubeTableSelectAllState = useMemo(() => {\n if (isAll) return 'all';\n if (!scopeKeys.length) return 'none';\n\n const set = selectedKeys as Set<Key>;\n let count = 0;\n\n for (const key of scopeKeys) if (set.has(key)) count++;\n\n return count === 0 ? 'none' : count === scopeKeys.length ? 'all' : 'some';\n }, [isAll, selectedKeys, scopeKeys]);\n\n const toggleSelectAll = useEvent(() => {\n anchorRef.current = null;\n extentRef.current = null;\n\n if (selectAllState === 'all') {\n // Clearing drops the whole selection, not just the scope: leaving keys\n // selected on other pages after the user clicked an unchecked-looking\n // box is the kind of thing nobody discovers until they delete something.\n state.setSelectedKeys(new Set());\n\n return;\n }\n\n if (selectAllMode === 'all') {\n state.setSelectedKeys('all');\n\n return;\n }\n\n const next = new Set(isAll ? [] : (selectedKeys as Set<Key>));\n\n scopeKeys.forEach((key) => next.add(key));\n state.setSelectedKeys(next);\n });\n\n const clearSelection = useEvent(() => {\n anchorRef.current = null;\n extentRef.current = null;\n state.setSelectedKeys(new Set());\n });\n\n /**\n * Shift held on the press that produced this change. `Checkbox` reports only\n * the next value, so the modifier is captured from the pointer/key event on\n * the cell and read back here.\n */\n const shiftRef = useRef(false);\n\n const captureShift = useCallback((event: { shiftKey: boolean }) => {\n shiftRef.current = event.shiftKey;\n }, []);\n\n /** Selectable keys between two rows, inclusive, in either direction. */\n const keysBetween = useCallback(\n (from: Key, to: Key) => {\n const fromIndex = collection.indexOf(from);\n const toIndex = collection.indexOf(to);\n\n if (fromIndex < 0 || toIndex < 0) return [];\n\n const [lo, hi] =\n fromIndex <= toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];\n const all = collection.getKeys();\n const range: Key[] = [];\n\n for (let i = lo; i <= hi; i++) range.push(all[i]);\n\n return range;\n },\n [collection],\n );\n\n const toggleRow = useEvent((key: Key) => {\n if (!canSelect(key)) return;\n\n if (selectionMode === 'single') {\n state.setSelectedKeys(isSelected(key) ? new Set() : new Set([key]));\n\n return;\n }\n\n const anchor = anchorRef.current;\n\n if (shiftRef.current && anchor != null && collection.indexOf(anchor) >= 0) {\n const next = new Set(isAll ? scopeKeys : (selectedKeys as Set<Key>));\n\n // Drop the range this shift-click supersedes before drawing the new one,\n // so clicking back toward the anchor shrinks the selection.\n if (extentRef.current != null) {\n keysBetween(anchor, extentRef.current).forEach((k) => next.delete(k));\n }\n\n keysBetween(anchor, key).forEach((k) => {\n if (canSelect(k)) next.add(k);\n });\n\n extentRef.current = key;\n state.setSelectedKeys(next);\n\n return;\n }\n\n anchorRef.current = key;\n extentRef.current = null;\n selectionManager.toggleSelection(key);\n });\n\n const selectedRows = useMemo(() => {\n if (isAll) return [...rowByKey.values()];\n\n return [...(selectedKeys as Set<Key>)]\n .map((key) => rowByKey.get(key))\n .filter((row): row is T => row !== undefined);\n }, [isAll, selectedKeys, rowByKey]);\n\n return {\n isEnabled,\n selectionMode,\n selectionManager,\n collection,\n isSelected,\n canSelect,\n isRowDisabled: useCallback(\n (key: Key) => hardDisabledKeys.has(key),\n [hardDisabledKeys],\n ),\n toggleRow,\n captureShift,\n selectAllState,\n toggleSelectAll,\n clearSelection,\n selectedRows,\n selectedCount: isAll ? rowByKey.size : (selectedKeys as Set<Key>).size,\n selectedKeys: (isAll ? 'all' : [...(selectedKeys as Set<Key>)]) as\n | Key[]\n | 'all',\n };\n}\n\nexport type CubeTableSelectionState<T> = ReturnType<\n typeof useTableSelection<T>\n>;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.157.1 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { getColumnText, getColumnValue } from "./use-table-columns.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { useCollator } from "react-aria";
|
|
6
|
+
import { useControlledState } from "@react-stately/utils";
|
|
7
|
+
|
|
8
|
+
//#region src/components/data/TableBase/use-table-sort.ts
|
|
9
|
+
/**
|
|
10
|
+
* Sort state plus, in client mode, the reordered rows.
|
|
11
|
+
*
|
|
12
|
+
* The cycle is tri-state — `asc → desc → unsorted` — matching ag-grid's default
|
|
13
|
+
* `sortingOrder`, because losing the ability to get back to the source order is
|
|
14
|
+
* a real loss when the source order is meaningful. `disallowSortRemoval` on a
|
|
15
|
+
* column reduces it to `asc ↔ desc`.
|
|
16
|
+
*/
|
|
17
|
+
function useTableSort({ columns, rows, mode, sort: sortProp, defaultSort, onSortChange }) {
|
|
18
|
+
const collator = useCollator({
|
|
19
|
+
numeric: true,
|
|
20
|
+
sensitivity: "base"
|
|
21
|
+
});
|
|
22
|
+
const [sort, setSort] = useControlledState(sortProp, defaultSort ?? null, onSortChange);
|
|
23
|
+
const hasSortableColumn = columns.some((column) => column.isSortable);
|
|
24
|
+
const resolvedMode = mode ?? (hasSortableColumn ? "client" : "off");
|
|
25
|
+
const isSortable = useEvent((column) => resolvedMode !== "off" && column.isSortable === true);
|
|
26
|
+
const toggleSort = useEvent((columnKey) => {
|
|
27
|
+
const column = columns.find((entry) => entry.key === columnKey);
|
|
28
|
+
if (!column || !isSortable(column)) return;
|
|
29
|
+
if (sort?.columnKey !== columnKey) {
|
|
30
|
+
setSort({
|
|
31
|
+
columnKey,
|
|
32
|
+
direction: "asc"
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (sort.direction === "asc") {
|
|
37
|
+
setSort({
|
|
38
|
+
columnKey,
|
|
39
|
+
direction: "desc"
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setSort(column.disallowSortRemoval ? {
|
|
44
|
+
columnKey,
|
|
45
|
+
direction: "asc"
|
|
46
|
+
} : null);
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
sort,
|
|
50
|
+
sortedRows: useMemo(() => {
|
|
51
|
+
if (resolvedMode !== "client" || !sort) return rows;
|
|
52
|
+
const column = columns.find((entry) => entry.key === sort.columnKey);
|
|
53
|
+
if (!column) return rows;
|
|
54
|
+
const direction = sort.direction === "asc" ? 1 : -1;
|
|
55
|
+
return rows.map((row, index) => ({
|
|
56
|
+
row,
|
|
57
|
+
index
|
|
58
|
+
})).sort((a, b) => {
|
|
59
|
+
const result = compareByColumn(column, collator, a.row, a.index, b.row, b.index);
|
|
60
|
+
return result !== 0 ? result * direction : a.index - b.index;
|
|
61
|
+
}).map((entry) => entry.row);
|
|
62
|
+
}, [
|
|
63
|
+
resolvedMode,
|
|
64
|
+
sort,
|
|
65
|
+
rows,
|
|
66
|
+
columns,
|
|
67
|
+
collator
|
|
68
|
+
]),
|
|
69
|
+
toggleSort,
|
|
70
|
+
isSortable,
|
|
71
|
+
mode: resolvedMode
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function compareByColumn(column, collator, rowA, indexA, rowB, indexB) {
|
|
75
|
+
const valueA = getColumnValue(column, rowA, indexA);
|
|
76
|
+
const valueB = getColumnValue(column, rowB, indexB);
|
|
77
|
+
if (column.compare) return column.compare(valueA, valueB, rowA, rowB);
|
|
78
|
+
if (valueA == null && valueB == null) return 0;
|
|
79
|
+
if (valueA == null) return -1;
|
|
80
|
+
if (valueB == null) return 1;
|
|
81
|
+
if (typeof valueA === "number" && typeof valueB === "number") return valueA - valueB;
|
|
82
|
+
if (typeof valueA === "boolean" && typeof valueB === "boolean") return Number(valueA) - Number(valueB);
|
|
83
|
+
if (valueA instanceof Date && valueB instanceof Date) return valueA.getTime() - valueB.getTime();
|
|
84
|
+
const textA = getColumnText(column, rowA, indexA) ?? String(valueA);
|
|
85
|
+
const textB = getColumnText(column, rowB, indexB) ?? String(valueB);
|
|
86
|
+
return collator.compare(textA, textB);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { compareByColumn, useTableSort };
|
|
91
|
+
//# sourceMappingURL=use-table-sort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-table-sort.js","names":[],"sources":["../../../../src/components/data/TableBase/use-table-sort.ts"],"sourcesContent":["import { useControlledState } from '@react-stately/utils';\nimport { useMemo } from 'react';\nimport { useCollator } from 'react-aria';\n\nimport { useEvent } from '../../../_internal/hooks';\n\nimport { getColumnText, getColumnValue } from './use-table-columns';\n\nimport type { CubeTableColumn, CubeTableSort } from './types';\n\nexport type CubeTableSortMode = 'client' | 'server' | 'off';\n\nexport interface UseTableSortOptions<T> {\n columns: CubeTableColumn<T>[];\n rows: readonly T[];\n /** @default 'client' when any column is sortable, else 'off' */\n mode?: CubeTableSortMode;\n sort?: CubeTableSort | null;\n defaultSort?: CubeTableSort | null;\n onSortChange?: (sort: CubeTableSort | null) => void;\n}\n\nexport interface UseTableSortResult<T> {\n sort: CubeTableSort | null;\n /** `rows` reordered in client mode; the original array otherwise. */\n sortedRows: readonly T[];\n /** Advances a column through the sort cycle. */\n toggleSort: (columnKey: string) => void;\n isSortable: (column: CubeTableColumn<T>) => boolean;\n /**\n * The mode after defaulting. The renderer needs this exact answer to decide\n * whether a header is clickable, and deriving it a second time at the call\n * site is how `DataTable` ended up sorting on `defaultSorts` but ignoring\n * every click.\n */\n mode: CubeTableSortMode;\n}\n\n/**\n * Sort state plus, in client mode, the reordered rows.\n *\n * The cycle is tri-state — `asc → desc → unsorted` — matching ag-grid's default\n * `sortingOrder`, because losing the ability to get back to the source order is\n * a real loss when the source order is meaningful. `disallowSortRemoval` on a\n * column reduces it to `asc ↔ desc`.\n */\nexport function useTableSort<T>({\n columns,\n rows,\n mode,\n sort: sortProp,\n defaultSort,\n onSortChange,\n}: UseTableSortOptions<T>): UseTableSortResult<T> {\n // A collator gives locale-correct, case-insensitive ordering — \"Ä\" sorts next\n // to \"A\" rather than after \"Z\", which a raw `<` comparison gets wrong.\n const collator = useCollator({ numeric: true, sensitivity: 'base' });\n\n const [sort, setSort] = useControlledState<CubeTableSort | null>(\n sortProp as CubeTableSort | null,\n defaultSort ?? null,\n onSortChange as (value: CubeTableSort | null) => void,\n );\n\n const hasSortableColumn = columns.some((column) => column.isSortable);\n const resolvedMode: CubeTableSortMode =\n mode ?? (hasSortableColumn ? 'client' : 'off');\n\n const isSortable = useEvent(\n (column: CubeTableColumn<T>) =>\n resolvedMode !== 'off' && column.isSortable === true,\n );\n\n const toggleSort = useEvent((columnKey: string) => {\n const column = columns.find((entry) => entry.key === columnKey);\n\n if (!column || !isSortable(column)) return;\n\n if (sort?.columnKey !== columnKey) {\n setSort({ columnKey, direction: 'asc' });\n\n return;\n }\n\n if (sort.direction === 'asc') {\n setSort({ columnKey, direction: 'desc' });\n\n return;\n }\n\n setSort(\n column.disallowSortRemoval ? { columnKey, direction: 'asc' } : null,\n );\n });\n\n const sortedRows = useMemo(() => {\n if (resolvedMode !== 'client' || !sort) return rows;\n\n const column = columns.find((entry) => entry.key === sort.columnKey);\n\n if (!column) return rows;\n\n const direction = sort.direction === 'asc' ? 1 : -1;\n\n // `map`/`sort`/`map` rather than sorting in place: `rows` is the caller's\n // array and `Array.prototype.sort` mutates. Carrying the original index also\n // makes the sort stable across engines.\n return rows\n .map((row, index) => ({ row, index }))\n .sort((a, b) => {\n const result = compareByColumn(\n column,\n collator,\n a.row,\n a.index,\n b.row,\n b.index,\n );\n\n return result !== 0 ? result * direction : a.index - b.index;\n })\n .map((entry) => entry.row);\n }, [resolvedMode, sort, rows, columns, collator]);\n\n // The resolved mode is returned rather than left for the caller to derive\n // again: the renderer needs the same answer to decide whether a header is\n // clickable, and two independent derivations drift.\n return { sort, sortedRows, toggleSort, isSortable, mode: resolvedMode };\n}\n\nexport function compareByColumn<T>(\n column: CubeTableColumn<T>,\n collator: Intl.Collator,\n rowA: T,\n indexA: number,\n rowB: T,\n indexB: number,\n): number {\n const valueA = getColumnValue(column, rowA, indexA);\n const valueB = getColumnValue(column, rowB, indexB);\n\n if (column.compare) return column.compare(valueA, valueB, rowA, rowB);\n\n // Nullish always sorts first, then gets flipped with the direction. Mixing\n // them into the value comparison instead produces an unstable order.\n if (valueA == null && valueB == null) return 0;\n if (valueA == null) return -1;\n if (valueB == null) return 1;\n\n if (typeof valueA === 'number' && typeof valueB === 'number') {\n return valueA - valueB;\n }\n if (typeof valueA === 'boolean' && typeof valueB === 'boolean') {\n return Number(valueA) - Number(valueB);\n }\n if (valueA instanceof Date && valueB instanceof Date) {\n return valueA.getTime() - valueB.getTime();\n }\n\n // Fall back to display text, so a column with a `format` sorts the way it\n // reads rather than the way it is stored.\n const textA = getColumnText(column, rowA, indexA) ?? String(valueA);\n const textB = getColumnText(column, rowB, indexB) ?? String(valueB);\n\n return collator.compare(textA, textB);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA8CA,SAAgB,aAAgB,EAC9B,SACA,MACA,MACA,MAAM,UACN,aACA,gBACgD;CAGhD,MAAM,WAAW,YAAY;EAAE,SAAS;EAAM,aAAa;EAAQ,CAAC;CAEpE,MAAM,CAAC,MAAM,WAAW,mBACtB,UACA,eAAe,MACf,aACD;CAED,MAAM,oBAAoB,QAAQ,MAAM,WAAW,OAAO,WAAW;CACrE,MAAM,eACJ,SAAS,oBAAoB,WAAW;CAE1C,MAAM,aAAa,UAChB,WACC,iBAAiB,SAAS,OAAO,eAAe,KACnD;CAED,MAAM,aAAa,UAAU,cAAsB;EACjD,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,QAAQ,UAAU;AAE/D,MAAI,CAAC,UAAU,CAAC,WAAW,OAAO,CAAE;AAEpC,MAAI,MAAM,cAAc,WAAW;AACjC,WAAQ;IAAE;IAAW,WAAW;IAAO,CAAC;AAExC;;AAGF,MAAI,KAAK,cAAc,OAAO;AAC5B,WAAQ;IAAE;IAAW,WAAW;IAAQ,CAAC;AAEzC;;AAGF,UACE,OAAO,sBAAsB;GAAE;GAAW,WAAW;GAAO,GAAG,KAChE;GACD;AAkCF,QAAO;EAAE;EAAM,YAhCI,cAAc;AAC/B,OAAI,iBAAiB,YAAY,CAAC,KAAM,QAAO;GAE/C,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,QAAQ,KAAK,UAAU;AAEpE,OAAI,CAAC,OAAQ,QAAO;GAEpB,MAAM,YAAY,KAAK,cAAc,QAAQ,IAAI;AAKjD,UAAO,KACJ,KAAK,KAAK,WAAW;IAAE;IAAK;IAAO,EAAE,CACrC,MAAM,GAAG,MAAM;IACd,MAAM,SAAS,gBACb,QACA,UACA,EAAE,KACF,EAAE,OACF,EAAE,KACF,EAAE,MACH;AAED,WAAO,WAAW,IAAI,SAAS,YAAY,EAAE,QAAQ,EAAE;KACvD,CACD,KAAK,UAAU,MAAM,IAAI;KAC3B;GAAC;GAAc;GAAM;GAAM;GAAS;GAAS,CAAC;EAKtB;EAAY;EAAY,MAAM;EAAc;;AAGzE,SAAgB,gBACd,QACA,UACA,MACA,QACA,MACA,QACQ;CACR,MAAM,SAAS,eAAe,QAAQ,MAAM,OAAO;CACnD,MAAM,SAAS,eAAe,QAAQ,MAAM,OAAO;AAEnD,KAAI,OAAO,QAAS,QAAO,OAAO,QAAQ,QAAQ,QAAQ,MAAM,KAAK;AAIrE,KAAI,UAAU,QAAQ,UAAU,KAAM,QAAO;AAC7C,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,UAAU,KAAM,QAAO;AAE3B,KAAI,OAAO,WAAW,YAAY,OAAO,WAAW,SAClD,QAAO,SAAS;AAElB,KAAI,OAAO,WAAW,aAAa,OAAO,WAAW,UACnD,QAAO,OAAO,OAAO,GAAG,OAAO,OAAO;AAExC,KAAI,kBAAkB,QAAQ,kBAAkB,KAC9C,QAAO,OAAO,SAAS,GAAG,OAAO,SAAS;CAK5C,MAAM,QAAQ,cAAc,QAAQ,MAAM,OAAO,IAAI,OAAO,OAAO;CACnE,MAAM,QAAQ,cAAc,QAAQ,MAAM,OAAO,IAAI,OAAO,OAAO;AAEnE,QAAO,SAAS,QAAQ,OAAO,MAAM"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** @license MIT | @cube-dev/ui-kit v0.157.1 | Cube Dev Team */
|
|
2
|
+
import { useEvent } from "../../../_internal/hooks/use-event.js";
|
|
3
|
+
import { compareByColumn } from "./use-table-sort.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
import { useControlledState } from "@react-stately/utils";
|
|
6
|
+
import { useCollator } from "@react-aria/i18n";
|
|
7
|
+
|
|
8
|
+
//#region src/components/data/TableBase/use-table-sorts.ts
|
|
9
|
+
const EMPTY = [];
|
|
10
|
+
/**
|
|
11
|
+
* Multi-column sorting.
|
|
12
|
+
*
|
|
13
|
+
* `ItemTable` sorts by one column, which is right for a list. An analytical
|
|
14
|
+
* grid is routinely ordered by one dimension and then another, and Cloud's
|
|
15
|
+
* reports send an array of sorts to the query — so the order of the array is
|
|
16
|
+
* the sort precedence, and it has to survive round-tripping.
|
|
17
|
+
*
|
|
18
|
+
* Clicking a header cycles that column `asc → desc → off` exactly as the single
|
|
19
|
+
* version does; the difference is that it edits its entry in place rather than
|
|
20
|
+
* replacing the whole sort, so the other columns keep their precedence.
|
|
21
|
+
*/
|
|
22
|
+
function useTableSorts({ columns, rows, mode, sorts: sortsProp, defaultSorts, onSortsChange }) {
|
|
23
|
+
const collator = useCollator({
|
|
24
|
+
numeric: true,
|
|
25
|
+
sensitivity: "base"
|
|
26
|
+
});
|
|
27
|
+
const [sorts, setSorts] = useControlledState(sortsProp, defaultSorts ?? EMPTY, onSortsChange);
|
|
28
|
+
const hasSortableColumn = columns.some((column) => column.isSortable);
|
|
29
|
+
const resolvedMode = mode ?? (hasSortableColumn ? "client" : "off");
|
|
30
|
+
const isSortable = useEvent((column) => resolvedMode !== "off" && column.isSortable === true);
|
|
31
|
+
const toggleSort = useEvent((columnKey) => {
|
|
32
|
+
const column = columns.find((entry) => entry.key === columnKey);
|
|
33
|
+
if (!column || !isSortable(column)) return;
|
|
34
|
+
const index = sorts.findIndex((entry) => entry.columnKey === columnKey);
|
|
35
|
+
if (index === -1) {
|
|
36
|
+
setSorts([...sorts, {
|
|
37
|
+
columnKey,
|
|
38
|
+
direction: "asc"
|
|
39
|
+
}]);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const next = [...sorts];
|
|
43
|
+
if (next[index].direction === "asc") {
|
|
44
|
+
next[index] = {
|
|
45
|
+
columnKey,
|
|
46
|
+
direction: "desc"
|
|
47
|
+
};
|
|
48
|
+
setSorts(next);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (column.disallowSortRemoval) {
|
|
52
|
+
next[index] = {
|
|
53
|
+
columnKey,
|
|
54
|
+
direction: "asc"
|
|
55
|
+
};
|
|
56
|
+
setSorts(next);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
next.splice(index, 1);
|
|
60
|
+
setSorts(next);
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
sorts,
|
|
64
|
+
sortedRows: useMemo(() => {
|
|
65
|
+
if (resolvedMode !== "client" || !sorts.length) return rows;
|
|
66
|
+
const active = sorts.map((sort) => ({
|
|
67
|
+
sort,
|
|
68
|
+
column: columns.find((entry) => entry.key === sort.columnKey)
|
|
69
|
+
})).filter((entry) => entry.column != null);
|
|
70
|
+
if (!active.length) return rows;
|
|
71
|
+
return rows.map((row, index) => ({
|
|
72
|
+
row,
|
|
73
|
+
index
|
|
74
|
+
})).sort((a, b) => {
|
|
75
|
+
for (const { sort, column } of active) {
|
|
76
|
+
const result = compareByColumn(column, collator, a.row, a.index, b.row, b.index);
|
|
77
|
+
if (result !== 0) return result * (sort.direction === "asc" ? 1 : -1);
|
|
78
|
+
}
|
|
79
|
+
return a.index - b.index;
|
|
80
|
+
}).map((entry) => entry.row);
|
|
81
|
+
}, [
|
|
82
|
+
resolvedMode,
|
|
83
|
+
sorts,
|
|
84
|
+
rows,
|
|
85
|
+
columns,
|
|
86
|
+
collator
|
|
87
|
+
]),
|
|
88
|
+
toggleSort,
|
|
89
|
+
isSortable,
|
|
90
|
+
sortRank: useEvent((columnKey) => sorts.findIndex((entry) => entry.columnKey === columnKey) + 1),
|
|
91
|
+
mode: resolvedMode
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { useTableSorts };
|
|
97
|
+
//# sourceMappingURL=use-table-sorts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-table-sorts.js","names":[],"sources":["../../../../src/components/data/TableBase/use-table-sorts.ts"],"sourcesContent":["import { useCollator } from '@react-aria/i18n';\nimport { useControlledState } from '@react-stately/utils';\nimport { useMemo } from 'react';\n\nimport { useEvent } from '../../../_internal/hooks';\n\nimport { compareByColumn } from './use-table-sort';\n\nimport type { CubeTableColumn, CubeTableSort } from './types';\n\nexport interface UseTableSortsOptions<T> {\n columns: CubeTableColumn<T>[];\n rows: readonly T[];\n mode?: 'client' | 'server' | 'off';\n sorts?: CubeTableSort[];\n defaultSorts?: CubeTableSort[];\n onSortsChange?: (sorts: CubeTableSort[]) => void;\n}\n\nconst EMPTY: CubeTableSort[] = [];\n\n/**\n * Multi-column sorting.\n *\n * `ItemTable` sorts by one column, which is right for a list. An analytical\n * grid is routinely ordered by one dimension and then another, and Cloud's\n * reports send an array of sorts to the query — so the order of the array is\n * the sort precedence, and it has to survive round-tripping.\n *\n * Clicking a header cycles that column `asc → desc → off` exactly as the single\n * version does; the difference is that it edits its entry in place rather than\n * replacing the whole sort, so the other columns keep their precedence.\n */\nexport function useTableSorts<T>({\n columns,\n rows,\n mode,\n sorts: sortsProp,\n defaultSorts,\n onSortsChange,\n}: UseTableSortsOptions<T>) {\n const collator = useCollator({ numeric: true, sensitivity: 'base' });\n\n const [sorts, setSorts] = useControlledState<CubeTableSort[]>(\n sortsProp as CubeTableSort[],\n defaultSorts ?? EMPTY,\n onSortsChange as (value: CubeTableSort[]) => void,\n );\n\n const hasSortableColumn = columns.some((column) => column.isSortable);\n const resolvedMode = mode ?? (hasSortableColumn ? 'client' : 'off');\n\n const isSortable = useEvent(\n (column: CubeTableColumn<T>) =>\n resolvedMode !== 'off' && column.isSortable === true,\n );\n\n const toggleSort = useEvent((columnKey: string) => {\n const column = columns.find((entry) => entry.key === columnKey);\n\n if (!column || !isSortable(column)) return;\n\n const index = sorts.findIndex((entry) => entry.columnKey === columnKey);\n\n if (index === -1) {\n // Appended, not prepended: a newly sorted column is the least\n // significant, so the ordering the user already established still leads.\n setSorts([...sorts, { columnKey, direction: 'asc' }]);\n\n return;\n }\n\n const next = [...sorts];\n\n if (next[index].direction === 'asc') {\n next[index] = { columnKey, direction: 'desc' };\n setSorts(next);\n\n return;\n }\n\n if (column.disallowSortRemoval) {\n next[index] = { columnKey, direction: 'asc' };\n setSorts(next);\n\n return;\n }\n\n next.splice(index, 1);\n setSorts(next);\n });\n\n const sortedRows = useMemo(() => {\n if (resolvedMode !== 'client' || !sorts.length) return rows;\n\n const active = sorts\n .map((sort) => ({\n sort,\n column: columns.find((entry) => entry.key === sort.columnKey),\n }))\n .filter(\n (entry): entry is { sort: CubeTableSort; column: CubeTableColumn<T> } =>\n entry.column != null,\n );\n\n if (!active.length) return rows;\n\n // Not sorted in place: `rows` belongs to the caller and `sort` mutates.\n // The original index is carried so the result is stable when every sort\n // ties.\n return rows\n .map((row, index) => ({ row, index }))\n .sort((a, b) => {\n for (const { sort, column } of active) {\n const result = compareByColumn(\n column,\n collator,\n a.row,\n a.index,\n b.row,\n b.index,\n );\n\n if (result !== 0) {\n return result * (sort.direction === 'asc' ? 1 : -1);\n }\n }\n\n return a.index - b.index;\n })\n .map((entry) => entry.row);\n }, [resolvedMode, sorts, rows, columns, collator]);\n\n /** Where a column sits in the precedence, 1-based. `0` when unsorted. */\n const sortRank = useEvent(\n (columnKey: string) =>\n sorts.findIndex((entry) => entry.columnKey === columnKey) + 1,\n );\n\n // Returned for the same reason as the single-column hook: the renderer needs\n // this exact answer to decide whether a header is clickable.\n return {\n sorts,\n sortedRows,\n toggleSort,\n isSortable,\n sortRank,\n mode: resolvedMode,\n };\n}\n"],"mappings":";;;;;;;;AAmBA,MAAM,QAAyB,EAAE;;;;;;;;;;;;;AAcjC,SAAgB,cAAiB,EAC/B,SACA,MACA,MACA,OAAO,WACP,cACA,iBAC0B;CAC1B,MAAM,WAAW,YAAY;EAAE,SAAS;EAAM,aAAa;EAAQ,CAAC;CAEpE,MAAM,CAAC,OAAO,YAAY,mBACxB,WACA,gBAAgB,OAChB,cACD;CAED,MAAM,oBAAoB,QAAQ,MAAM,WAAW,OAAO,WAAW;CACrE,MAAM,eAAe,SAAS,oBAAoB,WAAW;CAE7D,MAAM,aAAa,UAChB,WACC,iBAAiB,SAAS,OAAO,eAAe,KACnD;CAED,MAAM,aAAa,UAAU,cAAsB;EACjD,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,QAAQ,UAAU;AAE/D,MAAI,CAAC,UAAU,CAAC,WAAW,OAAO,CAAE;EAEpC,MAAM,QAAQ,MAAM,WAAW,UAAU,MAAM,cAAc,UAAU;AAEvE,MAAI,UAAU,IAAI;AAGhB,YAAS,CAAC,GAAG,OAAO;IAAE;IAAW,WAAW;IAAO,CAAC,CAAC;AAErD;;EAGF,MAAM,OAAO,CAAC,GAAG,MAAM;AAEvB,MAAI,KAAK,OAAO,cAAc,OAAO;AACnC,QAAK,SAAS;IAAE;IAAW,WAAW;IAAQ;AAC9C,YAAS,KAAK;AAEd;;AAGF,MAAI,OAAO,qBAAqB;AAC9B,QAAK,SAAS;IAAE;IAAW,WAAW;IAAO;AAC7C,YAAS,KAAK;AAEd;;AAGF,OAAK,OAAO,OAAO,EAAE;AACrB,WAAS,KAAK;GACd;AAmDF,QAAO;EACL;EACA,YAnDiB,cAAc;AAC/B,OAAI,iBAAiB,YAAY,CAAC,MAAM,OAAQ,QAAO;GAEvD,MAAM,SAAS,MACZ,KAAK,UAAU;IACd;IACA,QAAQ,QAAQ,MAAM,UAAU,MAAM,QAAQ,KAAK,UAAU;IAC9D,EAAE,CACF,QACE,UACC,MAAM,UAAU,KACnB;AAEH,OAAI,CAAC,OAAO,OAAQ,QAAO;AAK3B,UAAO,KACJ,KAAK,KAAK,WAAW;IAAE;IAAK;IAAO,EAAE,CACrC,MAAM,GAAG,MAAM;AACd,SAAK,MAAM,EAAE,MAAM,YAAY,QAAQ;KACrC,MAAM,SAAS,gBACb,QACA,UACA,EAAE,KACF,EAAE,OACF,EAAE,KACF,EAAE,MACH;AAED,SAAI,WAAW,EACb,QAAO,UAAU,KAAK,cAAc,QAAQ,IAAI;;AAIpD,WAAO,EAAE,QAAQ,EAAE;KACnB,CACD,KAAK,UAAU,MAAM,IAAI;KAC3B;GAAC;GAAc;GAAO;GAAM;GAAS;GAAS,CAAC;EAahD;EACA;EACA,UAZe,UACd,cACC,MAAM,WAAW,UAAU,MAAM,cAAc,UAAU,GAAG,EAC/D;EAUC,MAAM;EACP"}
|