@qijenchen/design-system 0.1.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/dist/components/Accordion/accordion.d.ts +37 -0
- package/dist/components/Accordion/accordion.d.ts.map +1 -0
- package/dist/components/Accordion/accordion.js +78 -0
- package/dist/components/Accordion/accordion.js.map +1 -0
- package/dist/components/Alert/alert.d.ts +47 -0
- package/dist/components/Alert/alert.d.ts.map +1 -0
- package/dist/components/Alert/alert.js +132 -0
- package/dist/components/Alert/alert.js.map +1 -0
- package/dist/components/AppShell/_demo-helpers.d.ts +49 -0
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.d.ts +76 -0
- package/dist/components/AppShell/app-shell.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.js +214 -0
- package/dist/components/AppShell/app-shell.js.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts +40 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.js +23 -0
- package/dist/components/AspectRatio/aspect-ratio.js.map +1 -0
- package/dist/components/Avatar/avatar.d.ts +85 -0
- package/dist/components/Avatar/avatar.d.ts.map +1 -0
- package/dist/components/Avatar/avatar.js +195 -0
- package/dist/components/Avatar/avatar.js.map +1 -0
- package/dist/components/Badge/badge.d.ts +43 -0
- package/dist/components/Badge/badge.d.ts.map +1 -0
- package/dist/components/Badge/badge.js +69 -0
- package/dist/components/Badge/badge.js.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts +163 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.js +300 -0
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +46 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js +78 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -0
- package/dist/components/Button/button-group.d.ts +49 -0
- package/dist/components/Button/button-group.d.ts.map +1 -0
- package/dist/components/Button/button-group.js +46 -0
- package/dist/components/Button/button-group.js.map +1 -0
- package/dist/components/Button/button.d.ts +203 -0
- package/dist/components/Button/button.d.ts.map +1 -0
- package/dist/components/Button/button.js +309 -0
- package/dist/components/Button/button.js.map +1 -0
- package/dist/components/Calendar/calendar.d.ts +81 -0
- package/dist/components/Calendar/calendar.d.ts.map +1 -0
- package/dist/components/Calendar/calendar.js +282 -0
- package/dist/components/Calendar/calendar.js.map +1 -0
- package/dist/components/Carousel/carousel.d.ts +61 -0
- package/dist/components/Carousel/carousel.d.ts.map +1 -0
- package/dist/components/Carousel/carousel.js +276 -0
- package/dist/components/Carousel/carousel.js.map +1 -0
- package/dist/components/Chart/chart.d.ts +94 -0
- package/dist/components/Chart/chart.d.ts.map +1 -0
- package/dist/components/Chart/chart.js +233 -0
- package/dist/components/Chart/chart.js.map +1 -0
- package/dist/components/Checkbox/checkbox-group.d.ts +58 -0
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox-group.js +28 -0
- package/dist/components/Checkbox/checkbox-group.js.map +1 -0
- package/dist/components/Checkbox/checkbox.d.ts +73 -0
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox.js +125 -0
- package/dist/components/Checkbox/checkbox.js.map +1 -0
- package/dist/components/Chip/chip.d.ts +54 -0
- package/dist/components/Chip/chip.d.ts.map +1 -0
- package/dist/components/Chip/chip.js +224 -0
- package/dist/components/Chip/chip.js.map +1 -0
- package/dist/components/CircularProgress/circular-progress.d.ts +40 -0
- package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -0
- package/dist/components/CircularProgress/circular-progress.js +118 -0
- package/dist/components/CircularProgress/circular-progress.js.map +1 -0
- package/dist/components/Coachmark/coachmark.d.ts +100 -0
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -0
- package/dist/components/Coachmark/coachmark.js +107 -0
- package/dist/components/Coachmark/coachmark.js.map +1 -0
- package/dist/components/Combobox/combobox.d.ts +150 -0
- package/dist/components/Combobox/combobox.d.ts.map +1 -0
- package/dist/components/Combobox/combobox.js +595 -0
- package/dist/components/Combobox/combobox.js.map +1 -0
- package/dist/components/Command/command.d.ts +106 -0
- package/dist/components/Command/command.d.ts.map +1 -0
- package/dist/components/Command/command.js +123 -0
- package/dist/components/Command/command.js.map +1 -0
- package/dist/components/DataTable/active-editor-controller.d.ts +66 -0
- package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.d.ts +37 -0
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.js +377 -0
- package/dist/components/DataTable/cell-registry.js.map +1 -0
- package/dist/components/DataTable/column-types.d.ts +145 -0
- package/dist/components/DataTable/column-types.d.ts.map +1 -0
- package/dist/components/DataTable/column-types.js +17 -0
- package/dist/components/DataTable/column-types.js.map +1 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +49 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts +30 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +78 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.js +220 -0
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts +19 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +181 -0
- package/dist/components/DataTable/data-table.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.js +1851 -0
- package/dist/components/DataTable/data-table.js.map +1 -0
- package/dist/components/DataTable/filter-operators.d.ts +116 -0
- package/dist/components/DataTable/filter-operators.d.ts.map +1 -0
- package/dist/components/DataTable/filter-tree.d.ts +66 -0
- package/dist/components/DataTable/filter-tree.d.ts.map +1 -0
- package/dist/components/DataTable/lib/column-meta.d.ts +49 -0
- package/dist/components/DataTable/lib/column-meta.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts +61 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.js +168 -0
- package/dist/components/DateGrid/date-grid.js.map +1 -0
- package/dist/components/DatePicker/date-picker.d.ts +119 -0
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -0
- package/dist/components/DatePicker/date-picker.js +743 -0
- package/dist/components/DatePicker/date-picker.js.map +1 -0
- package/dist/components/DescriptionList/description-list.d.ts +60 -0
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -0
- package/dist/components/DescriptionList/description-list.js +77 -0
- package/dist/components/DescriptionList/description-list.js.map +1 -0
- package/dist/components/Dialog/dialog.d.ts +54 -0
- package/dist/components/Dialog/dialog.d.ts.map +1 -0
- package/dist/components/Dialog/dialog.js +151 -0
- package/dist/components/Dialog/dialog.js.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +111 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.js +288 -0
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -0
- package/dist/components/Empty/empty.d.ts +40 -0
- package/dist/components/Empty/empty.d.ts.map +1 -0
- package/dist/components/Empty/empty.js +66 -0
- package/dist/components/Empty/empty.js.map +1 -0
- package/dist/components/Field/field-context.d.ts +77 -0
- package/dist/components/Field/field-context.d.ts.map +1 -0
- package/dist/components/Field/field-context.js +37 -0
- package/dist/components/Field/field-context.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +5 -0
- package/dist/components/Field/field-types.d.ts.map +1 -0
- package/dist/components/Field/field-types.js +13 -0
- package/dist/components/Field/field-types.js.map +1 -0
- package/dist/components/Field/field-wrapper.d.ts +17 -0
- package/dist/components/Field/field-wrapper.d.ts.map +1 -0
- package/dist/components/Field/field-wrapper.js +252 -0
- package/dist/components/Field/field-wrapper.js.map +1 -0
- package/dist/components/Field/field.d.ts +127 -0
- package/dist/components/Field/field.d.ts.map +1 -0
- package/dist/components/Field/field.js +295 -0
- package/dist/components/Field/field.js.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts +74 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.js +62 -0
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -0
- package/dist/components/FileItem/file-item.d.ts +44 -0
- package/dist/components/FileItem/file-item.d.ts.map +1 -0
- package/dist/components/FileItem/file-item.js +202 -0
- package/dist/components/FileItem/file-item.js.map +1 -0
- package/dist/components/FileUpload/file-upload.d.ts +97 -0
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -0
- package/dist/components/FileUpload/file-upload.js +231 -0
- package/dist/components/FileUpload/file-upload.js.map +1 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts +73 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.d.ts +82 -0
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.js +752 -0
- package/dist/components/FileViewer/file-viewer.js.map +1 -0
- package/dist/components/FileViewer/image-renderer.d.ts +9 -0
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -0
- package/dist/components/FileViewer/image-renderer.js +165 -0
- package/dist/components/FileViewer/image-renderer.js.map +1 -0
- package/dist/components/HoverCard/hover-card.d.ts +30 -0
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -0
- package/dist/components/HoverCard/hover-card.js +61 -0
- package/dist/components/HoverCard/hover-card.js.map +1 -0
- package/dist/components/Input/input.d.ts +72 -0
- package/dist/components/Input/input.d.ts.map +1 -0
- package/dist/components/Input/input.js +148 -0
- package/dist/components/Input/input.js.map +1 -0
- package/dist/components/LinkInput/link-input.d.ts +46 -0
- package/dist/components/LinkInput/link-input.d.ts.map +1 -0
- package/dist/components/LinkInput/link-input.js +215 -0
- package/dist/components/LinkInput/link-input.js.map +1 -0
- package/dist/components/Menu/menu-item.d.ts +83 -0
- package/dist/components/Menu/menu-item.d.ts.map +1 -0
- package/dist/components/Menu/menu-item.js +209 -0
- package/dist/components/Menu/menu-item.js.map +1 -0
- package/dist/components/NameCard/name-card.d.ts +85 -0
- package/dist/components/NameCard/name-card.d.ts.map +1 -0
- package/dist/components/NameCard/name-card.js +153 -0
- package/dist/components/NameCard/name-card.js.map +1 -0
- package/dist/components/Notice/notice.d.ts +69 -0
- package/dist/components/Notice/notice.d.ts.map +1 -0
- package/dist/components/Notice/notice.js +121 -0
- package/dist/components/Notice/notice.js.map +1 -0
- package/dist/components/NumberInput/number-input.d.ts +57 -0
- package/dist/components/NumberInput/number-input.d.ts.map +1 -0
- package/dist/components/NumberInput/number-input.js +131 -0
- package/dist/components/NumberInput/number-input.js.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +23 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js +111 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +57 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js +35 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts +7 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js +25 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker.d.ts +77 -0
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker.js +263 -0
- package/dist/components/PeoplePicker/people-picker.js.map +1 -0
- package/dist/components/PeoplePicker/person-display.d.ts +66 -0
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -0
- package/dist/components/PeoplePicker/person-display.js +203 -0
- package/dist/components/PeoplePicker/person-display.js.map +1 -0
- package/dist/components/Popover/popover.d.ts +50 -0
- package/dist/components/Popover/popover.d.ts.map +1 -0
- package/dist/components/Popover/popover.js +113 -0
- package/dist/components/Popover/popover.js.map +1 -0
- package/dist/components/ProgressBar/progress-bar.d.ts +37 -0
- package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -0
- package/dist/components/ProgressBar/progress-bar.js +86 -0
- package/dist/components/ProgressBar/progress-bar.js.map +1 -0
- package/dist/components/RadioGroup/radio-group.d.ts +78 -0
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -0
- package/dist/components/RadioGroup/radio-group.js +153 -0
- package/dist/components/RadioGroup/radio-group.js.map +1 -0
- package/dist/components/Rating/rating.d.ts +46 -0
- package/dist/components/Rating/rating.d.ts.map +1 -0
- package/dist/components/Rating/rating.js +179 -0
- package/dist/components/Rating/rating.js.map +1 -0
- package/dist/components/ScrollArea/scroll-area.d.ts +45 -0
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -0
- package/dist/components/ScrollArea/scroll-area.js +65 -0
- package/dist/components/ScrollArea/scroll-area.js.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts +102 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.js +171 -0
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -0
- package/dist/components/Select/select.d.ts +102 -0
- package/dist/components/Select/select.d.ts.map +1 -0
- package/dist/components/Select/select.js +435 -0
- package/dist/components/Select/select.js.map +1 -0
- package/dist/components/SelectMenu/select-menu.d.ts +103 -0
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -0
- package/dist/components/SelectMenu/select-menu.js +239 -0
- package/dist/components/SelectMenu/select-menu.js.map +1 -0
- package/dist/components/SelectionControl/selection-item.d.ts +69 -0
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -0
- package/dist/components/SelectionControl/selection-item.js +142 -0
- package/dist/components/SelectionControl/selection-item.js.map +1 -0
- package/dist/components/Separator/separator.d.ts +17 -0
- package/dist/components/Separator/separator.d.ts.map +1 -0
- package/dist/components/Separator/separator.js +39 -0
- package/dist/components/Separator/separator.js.map +1 -0
- package/dist/components/Sheet/sheet.d.ts +56 -0
- package/dist/components/Sheet/sheet.d.ts.map +1 -0
- package/dist/components/Sheet/sheet.js +145 -0
- package/dist/components/Sheet/sheet.js.map +1 -0
- package/dist/components/Sidebar/sidebar.d.ts +195 -0
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar/sidebar.js +826 -0
- package/dist/components/Sidebar/sidebar.js.map +1 -0
- package/dist/components/Skeleton/skeleton.d.ts +16 -0
- package/dist/components/Skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton/skeleton.js +30 -0
- package/dist/components/Skeleton/skeleton.js.map +1 -0
- package/dist/components/Slider/slider.d.ts +48 -0
- package/dist/components/Slider/slider.d.ts.map +1 -0
- package/dist/components/Slider/slider.js +108 -0
- package/dist/components/Slider/slider.js.map +1 -0
- package/dist/components/Steps/steps.d.ts +71 -0
- package/dist/components/Steps/steps.d.ts.map +1 -0
- package/dist/components/Steps/steps.js +583 -0
- package/dist/components/Steps/steps.js.map +1 -0
- package/dist/components/Switch/switch.d.ts +112 -0
- package/dist/components/Switch/switch.d.ts.map +1 -0
- package/dist/components/Switch/switch.js +179 -0
- package/dist/components/Switch/switch.js.map +1 -0
- package/dist/components/Tabs/tabs.d.ts +104 -0
- package/dist/components/Tabs/tabs.d.ts.map +1 -0
- package/dist/components/Tabs/tabs.js +316 -0
- package/dist/components/Tabs/tabs.js.map +1 -0
- package/dist/components/Tag/tag.d.ts +86 -0
- package/dist/components/Tag/tag.d.ts.map +1 -0
- package/dist/components/Tag/tag.js +172 -0
- package/dist/components/Tag/tag.js.map +1 -0
- package/dist/components/Textarea/textarea.d.ts +74 -0
- package/dist/components/Textarea/textarea.d.ts.map +1 -0
- package/dist/components/Textarea/textarea.js +224 -0
- package/dist/components/Textarea/textarea.js.map +1 -0
- package/dist/components/TimePicker/time-columns.d.ts +46 -0
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -0
- package/dist/components/TimePicker/time-columns.js +173 -0
- package/dist/components/TimePicker/time-columns.js.map +1 -0
- package/dist/components/TimePicker/time-picker.d.ts +94 -0
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -0
- package/dist/components/TimePicker/time-picker.js +253 -0
- package/dist/components/TimePicker/time-picker.js.map +1 -0
- package/dist/components/Toast/toast.d.ts +61 -0
- package/dist/components/Toast/toast.d.ts.map +1 -0
- package/dist/components/Toast/toast.js +76 -0
- package/dist/components/Toast/toast.js.map +1 -0
- package/dist/components/Tooltip/tooltip.d.ts +20 -0
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip/tooltip.js +53 -0
- package/dist/components/Tooltip/tooltip.js.map +1 -0
- package/dist/components/TreeView/tree-view.d.ts +166 -0
- package/dist/components/TreeView/tree-view.d.ts.map +1 -0
- package/dist/components/TreeView/tree-view.js +617 -0
- package/dist/components/TreeView/tree-view.js.map +1 -0
- package/dist/hooks/use-controllable.d.ts +16 -0
- package/dist/hooks/use-controllable.d.ts.map +1 -0
- package/dist/hooks/use-controllable.js +26 -0
- package/dist/hooks/use-controllable.js.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts +2 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.js +19 -0
- package/dist/hooks/use-is-narrow-viewport.js.map +1 -0
- package/dist/hooks/use-is-touch-device.d.ts +8 -0
- package/dist/hooks/use-is-touch-device.d.ts.map +1 -0
- package/dist/hooks/use-is-touch-device.js +16 -0
- package/dist/hooks/use-is-touch-device.js.map +1 -0
- package/dist/hooks/use-overflow-items.d.ts +124 -0
- package/dist/hooks/use-overflow-items.d.ts.map +1 -0
- package/dist/hooks/use-overflow-items.js +97 -0
- package/dist/hooks/use-overflow-items.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/drag-visual.d.ts +158 -0
- package/dist/lib/drag-visual.d.ts.map +1 -0
- package/dist/lib/drag-visual.js +96 -0
- package/dist/lib/drag-visual.js.map +1 -0
- package/dist/lib/i18n/i18n-context.d.ts +105 -0
- package/dist/lib/i18n/i18n-context.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.d.ts +54 -0
- package/dist/lib/multi-select-ordering.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.js +13 -0
- package/dist/lib/multi-select-ordering.js.map +1 -0
- package/dist/lib/utils.d.ts +12 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +79 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +370 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.js +272 -0
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts +80 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.js +75 -0
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +101 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js +105 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +28 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.js +85 -0
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts +102 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.js +74 -0
- package/dist/patterns/resize-handle/resize-handle.js.map +1 -0
- package/dist/react-day-picker.css +457 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts +40 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts +12 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.js +7 -0
- package/dist/tokens/elevation/overlay-geometry.js.map +1 -0
- package/dist/tokens/motion/motion.d.ts +15 -0
- package/dist/tokens/motion/motion.d.ts.map +1 -0
- package/dist/tokens/motion/motion.js +9 -0
- package/dist/tokens/motion/motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.d.ts +53 -0
- package/dist/tokens/uiSize/icon-size.d.ts.map +1 -0
- package/package.json +92 -0
- package/src/README.md +32 -0
- package/src/components/Accordion/accordion.tsx +104 -0
- package/src/components/Alert/alert.tsx +188 -0
- package/src/components/AppShell/_demo-helpers.tsx +198 -0
- package/src/components/AppShell/app-shell.tsx +364 -0
- package/src/components/AspectRatio/aspect-ratio.tsx +58 -0
- package/src/components/Avatar/avatar.tsx +368 -0
- package/src/components/Badge/badge.tsx +104 -0
- package/src/components/Breadcrumb/breadcrumb.tsx +619 -0
- package/src/components/BulkActionBar/bulk-action-bar.tsx +156 -0
- package/src/components/Button/button-group.tsx +96 -0
- package/src/components/Button/button.tsx +539 -0
- package/src/components/Calendar/calendar.tsx +411 -0
- package/src/components/Carousel/carousel.tsx +371 -0
- package/src/components/Chart/chart.tsx +376 -0
- package/src/components/Checkbox/checkbox-group.tsx +94 -0
- package/src/components/Checkbox/checkbox.tsx +237 -0
- package/src/components/Chip/chip.tsx +359 -0
- package/src/components/CircularProgress/circular-progress.tsx +204 -0
- package/src/components/Coachmark/coachmark.tsx +255 -0
- package/src/components/Combobox/combobox.tsx +826 -0
- package/src/components/Command/command.tsx +187 -0
- package/src/components/DataTable/active-editor-controller.ts +72 -0
- package/src/components/DataTable/cell-registry.tsx +520 -0
- package/src/components/DataTable/column-types.ts +180 -0
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +261 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +813 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +483 -0
- package/src/components/DataTable/data-table-sort-manager.tsx +210 -0
- package/src/components/DataTable/data-table.css +165 -0
- package/src/components/DataTable/data-table.tsx +2924 -0
- package/src/components/DataTable/filter-operators.ts +225 -0
- package/src/components/DataTable/filter-tree.ts +313 -0
- package/src/components/DataTable/lib/column-meta.ts +79 -0
- package/src/components/DateGrid/date-grid.tsx +209 -0
- package/src/components/DatePicker/date-picker.tsx +1114 -0
- package/src/components/DescriptionList/description-list.tsx +141 -0
- package/src/components/Dialog/dialog.tsx +267 -0
- package/src/components/DropdownMenu/dropdown-menu.tsx +475 -0
- package/src/components/Empty/empty.tsx +108 -0
- package/src/components/Field/field-context.ts +136 -0
- package/src/components/Field/field-types.ts +52 -0
- package/src/components/Field/field-wrapper.tsx +348 -0
- package/src/components/Field/field.tsx +535 -0
- package/src/components/FieldControlGroup/field-control-group.tsx +136 -0
- package/src/components/FileItem/file-item.tsx +322 -0
- package/src/components/FileUpload/file-upload.tsx +326 -0
- package/src/components/FileViewer/file-viewer-types.ts +76 -0
- package/src/components/FileViewer/file-viewer.tsx +1065 -0
- package/src/components/FileViewer/image-renderer.tsx +256 -0
- package/src/components/HoverCard/hover-card.tsx +79 -0
- package/src/components/Input/input.tsx +233 -0
- package/src/components/LinkInput/link-input.tsx +304 -0
- package/src/components/Menu/menu-item.tsx +334 -0
- package/src/components/NameCard/name-card.tsx +319 -0
- package/src/components/Notice/notice.tsx +196 -0
- package/src/components/NumberInput/number-input.tsx +203 -0
- package/src/components/OverflowIndicator/overflow-indicator.tsx +156 -0
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +100 -0
- package/src/components/PeoplePicker/people-picker-helpers.ts +76 -0
- package/src/components/PeoplePicker/people-picker.tsx +455 -0
- package/src/components/PeoplePicker/person-display.tsx +358 -0
- package/src/components/Popover/popover.tsx +183 -0
- package/src/components/ProgressBar/progress-bar.tsx +157 -0
- package/src/components/README.md +58 -0
- package/src/components/RadioGroup/radio-group.tsx +261 -0
- package/src/components/Rating/rating.tsx +295 -0
- package/src/components/ScrollArea/scroll-area.tsx +110 -0
- package/src/components/SegmentedControl/segmented-control.tsx +304 -0
- package/src/components/Select/select.tsx +658 -0
- package/src/components/SelectMenu/select-menu.tsx +430 -0
- package/src/components/SelectionControl/selection-item.tsx +261 -0
- package/src/components/Separator/separator.tsx +48 -0
- package/src/components/Sheet/sheet.tsx +240 -0
- package/src/components/Sidebar/sidebar.tsx +1280 -0
- package/src/components/Skeleton/skeleton.tsx +35 -0
- package/src/components/Slider/slider.tsx +158 -0
- package/src/components/Steps/steps.tsx +850 -0
- package/src/components/Switch/switch.tsx +285 -0
- package/src/components/Tabs/tabs.tsx +515 -0
- package/src/components/Tag/tag.tsx +246 -0
- package/src/components/Textarea/textarea.tsx +280 -0
- package/src/components/TimePicker/time-columns.tsx +260 -0
- package/src/components/TimePicker/time-picker.tsx +419 -0
- package/src/components/Toast/toast.tsx +129 -0
- package/src/components/Tooltip/tooltip.tsx +68 -0
- package/src/components/TreeView/tree-view.tsx +1031 -0
- package/src/hooks/use-controllable.ts +40 -0
- package/src/hooks/use-is-narrow-viewport.ts +19 -0
- package/src/hooks/use-is-touch-device.ts +21 -0
- package/src/hooks/use-overflow-items.ts +256 -0
- package/src/index.ts +85 -0
- package/src/lib/README.md +82 -0
- package/src/lib/drag-visual.ts +272 -0
- package/src/lib/i18n/README.md +60 -0
- package/src/lib/i18n/i18n-context.tsx +129 -0
- package/src/lib/multi-select-ordering.ts +61 -0
- package/src/lib/utils.ts +93 -0
- package/src/patterns/README.md +67 -0
- package/src/patterns/element-anatomy/item-anatomy.tsx +744 -0
- package/src/patterns/header-canonical/chrome-header.tsx +175 -0
- package/src/patterns/header-canonical/header-canonical.css +27 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +217 -0
- package/src/patterns/overlay-surface/overlay-surface.tsx +191 -0
- package/src/patterns/resize-handle/resize-handle.tsx +188 -0
- package/src/stories-helpers/anatomy/anatomy-utils.tsx +64 -0
- package/src/styles/preset.css +31 -0
- package/src/styles/tokens.css +35 -0
- package/src/tokens/README.md +53 -0
- package/src/tokens/color/primitives.css +429 -0
- package/src/tokens/color/semantic.css +539 -0
- package/src/tokens/elevation/overlay-geometry.ts +13 -0
- package/src/tokens/layoutSpace/layoutSpace.css +36 -0
- package/src/tokens/motion/motion.css +30 -0
- package/src/tokens/motion/motion.ts +17 -0
- package/src/tokens/opacity/opacity.css +23 -0
- package/src/tokens/radius/radius.css +19 -0
- package/src/tokens/typography/typography.css +118 -0
- package/src/tokens/uiSize/icon-size.ts +52 -0
- package/src/tokens/uiSize/uiSize.css +125 -0
|
@@ -0,0 +1,1851 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { Empty } from "../Empty/empty.js";
|
|
5
|
+
import { useReactTable, getExpandedRowModel, getSortedRowModel, getCoreRowModel, flexRender } from "@tanstack/react-table";
|
|
6
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
7
|
+
import { TableScrollProvider } from "../Field/field-context.js";
|
|
8
|
+
import { cva } from "class-variance-authority";
|
|
9
|
+
import { ArrowUp, ArrowDown, ChevronDown, X, Filter, EyeOff, ArrowUpDown, GripVertical } from "lucide-react";
|
|
10
|
+
import { useSensors, useSensor, PointerSensor, KeyboardSensor, pointerWithin, rectIntersection, DndContext, MeasuringStrategy, DragOverlay, useDraggable, useDroppable, useDndContext } from "@dnd-kit/core";
|
|
11
|
+
import { cn } from "../../lib/utils.js";
|
|
12
|
+
import { ICON_SIZE, ItemInlineActionButton } from "../../patterns/element-anatomy/item-anatomy.js";
|
|
13
|
+
import { reconstructFullRowGhost, isReorderNoop, snapToCursorModifier, dragSourceStyle, dropIndicatorColumn, dragActiveCursor, dropIndicatorRow } from "../../lib/drag-visual.js";
|
|
14
|
+
import { nakedCellEditableDisplayHover } from "../Field/field-wrapper.js";
|
|
15
|
+
import { Tooltip, TooltipTrigger, TooltipContent } from "../Tooltip/tooltip.js";
|
|
16
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from "../DropdownMenu/dropdown-menu.js";
|
|
17
|
+
import { columnTypeDefaults } from "./column-types.js";
|
|
18
|
+
import { resolveCellComponent } from "./cell-registry.js";
|
|
19
|
+
import { DataTableInteractionLayer } from "./data-table-interaction-layer.js";
|
|
20
|
+
import { Checkbox } from "../Checkbox/checkbox.js";
|
|
21
|
+
import { RadioGroupItem } from "../RadioGroup/radio-group.js";
|
|
22
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
23
|
+
import { useControllable } from "../../hooks/use-controllable.js";
|
|
24
|
+
import { Button } from "../Button/button.js";
|
|
25
|
+
const dataTableVariants = cva("bg-surface rounded-md overflow-hidden", {
|
|
26
|
+
variants: { bordered: { true: "border border-divider", false: "" } },
|
|
27
|
+
defaultVariants: { bordered: true }
|
|
28
|
+
});
|
|
29
|
+
const cellEditId = (rowId, colId) => `${rowId}__${colId}`;
|
|
30
|
+
const SELECT_COL_ID = "__select__";
|
|
31
|
+
const cellPadding = { paddingBlock: "var(--table-cell-py)", paddingInline: "var(--table-cell-px)" };
|
|
32
|
+
const HEADER_BG = "bg-muted";
|
|
33
|
+
const MIN_COLUMN_WIDTH = 80;
|
|
34
|
+
function columnSizeStyle(col, opts) {
|
|
35
|
+
const baseSize = col.getSize();
|
|
36
|
+
const minSize = col.columnDef.minSize ?? (opts.resize ? MIN_COLUMN_WIDTH : baseSize);
|
|
37
|
+
const maxSize = col.columnDef.maxSize;
|
|
38
|
+
if (opts.isSystemCol) {
|
|
39
|
+
return { width: baseSize, minWidth: baseSize, maxWidth: maxSize };
|
|
40
|
+
}
|
|
41
|
+
if (opts.resize) {
|
|
42
|
+
return { width: baseSize, minWidth: minSize, maxWidth: maxSize };
|
|
43
|
+
}
|
|
44
|
+
return { flex: `1 1 ${baseSize}px`, minWidth: baseSize, maxWidth: maxSize };
|
|
45
|
+
}
|
|
46
|
+
const SYSTEM_COL_IDS = /* @__PURE__ */ new Set([SELECT_COL_ID, "__drag__", "__actions__"]);
|
|
47
|
+
const isSystemColumn = (colId) => SYSTEM_COL_IDS.has(colId);
|
|
48
|
+
let sharedResizeObserver = null;
|
|
49
|
+
const roCallbacks = /* @__PURE__ */ new WeakMap();
|
|
50
|
+
function getSharedRO() {
|
|
51
|
+
if (sharedResizeObserver) return sharedResizeObserver;
|
|
52
|
+
sharedResizeObserver = new ResizeObserver((entries) => {
|
|
53
|
+
entries.forEach((entry) => {
|
|
54
|
+
const cb = roCallbacks.get(entry.target);
|
|
55
|
+
if (cb) cb(entry);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return sharedResizeObserver;
|
|
59
|
+
}
|
|
60
|
+
function observeShared(el, cb) {
|
|
61
|
+
const obs = getSharedRO();
|
|
62
|
+
roCallbacks.set(el, cb);
|
|
63
|
+
obs.observe(el);
|
|
64
|
+
return () => {
|
|
65
|
+
roCallbacks.delete(el);
|
|
66
|
+
obs.unobserve(el);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function TruncateCell({ children, className }) {
|
|
70
|
+
const ref = React.useRef(null);
|
|
71
|
+
const [isTruncated, setIsTruncated] = React.useState(false);
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
const el = ref.current;
|
|
74
|
+
if (!el) return;
|
|
75
|
+
const check = () => setIsTruncated(el.scrollWidth > el.clientWidth);
|
|
76
|
+
check();
|
|
77
|
+
return observeShared(el, check);
|
|
78
|
+
}, []);
|
|
79
|
+
const span = /* @__PURE__ */ jsx("span", { ref, className: cn("truncate min-w-0", className), children });
|
|
80
|
+
if (!isTruncated) return span;
|
|
81
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
82
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: span }),
|
|
83
|
+
/* @__PURE__ */ jsx(TooltipContent, { children })
|
|
84
|
+
] });
|
|
85
|
+
}
|
|
86
|
+
const SortableRowCtx = React.createContext(null);
|
|
87
|
+
function SortableRowProvider(props) {
|
|
88
|
+
return props.role === "primary" ? /* @__PURE__ */ jsx(SourceRowProvider, { ...props }) : /* @__PURE__ */ jsx(MirrorRowProvider, { ...props });
|
|
89
|
+
}
|
|
90
|
+
function SourceRowProvider({
|
|
91
|
+
id,
|
|
92
|
+
disabled,
|
|
93
|
+
role,
|
|
94
|
+
invalidDrop,
|
|
95
|
+
children
|
|
96
|
+
}) {
|
|
97
|
+
const draggable = useDraggable({ id, disabled, data: { type: "row" } });
|
|
98
|
+
const droppable = useDroppable({ id, disabled, data: { type: "row" } });
|
|
99
|
+
const setRefs = React.useCallback((el) => {
|
|
100
|
+
draggable.setNodeRef(el);
|
|
101
|
+
droppable.setNodeRef(el);
|
|
102
|
+
}, [draggable.setNodeRef, droppable.setNodeRef]);
|
|
103
|
+
const isDragging = draggable.isDragging;
|
|
104
|
+
const style = { ...dragSourceStyle(isDragging) };
|
|
105
|
+
const handleAttrs = draggable.attributes;
|
|
106
|
+
const ctxValue = {
|
|
107
|
+
setNodeRef: setRefs,
|
|
108
|
+
role,
|
|
109
|
+
style,
|
|
110
|
+
attributes: {},
|
|
111
|
+
isDragging,
|
|
112
|
+
// row 不接 listeners(button-only),baseRowDiv `{...(extra?.listeners ?? {})}` 自動 noop
|
|
113
|
+
rowListeners: void 0,
|
|
114
|
+
rowAttributes: {},
|
|
115
|
+
// Button activator + listener:portal'd RowDragHandle Button 走這條 ctx,
|
|
116
|
+
// user 從任何 region 看見 button → 點下啟動 drag,activator rect = button DOM(24×24),
|
|
117
|
+
// ghost 起點 = button 位置(table outer 左 12px),cursor 在 ghost 左前段(自然視覺)。
|
|
118
|
+
handleSetActivatorNodeRef: draggable.setActivatorNodeRef,
|
|
119
|
+
handleListeners: draggable.listeners,
|
|
120
|
+
handleAttributes: handleAttrs,
|
|
121
|
+
invalidDrop
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ jsx(SortableRowCtx.Provider, { value: ctxValue, children: children(ctxValue) });
|
|
124
|
+
}
|
|
125
|
+
function MirrorRowProvider({
|
|
126
|
+
id,
|
|
127
|
+
disabled,
|
|
128
|
+
role,
|
|
129
|
+
invalidDrop,
|
|
130
|
+
children
|
|
131
|
+
}) {
|
|
132
|
+
var _a;
|
|
133
|
+
const droppable = useDroppable({ id, disabled, data: { type: "row" } });
|
|
134
|
+
const dndCtx = useDndContext();
|
|
135
|
+
const isDragging = ((_a = dndCtx.active) == null ? void 0 : _a.id) === id;
|
|
136
|
+
const ctxValue = {
|
|
137
|
+
setNodeRef: droppable.setNodeRef,
|
|
138
|
+
role,
|
|
139
|
+
style: { ...dragSourceStyle(isDragging) },
|
|
140
|
+
attributes: {},
|
|
141
|
+
isDragging,
|
|
142
|
+
rowListeners: void 0,
|
|
143
|
+
rowAttributes: {},
|
|
144
|
+
handleSetActivatorNodeRef: void 0,
|
|
145
|
+
handleListeners: void 0,
|
|
146
|
+
handleAttributes: {},
|
|
147
|
+
invalidDrop
|
|
148
|
+
};
|
|
149
|
+
return /* @__PURE__ */ jsx(SortableRowCtx.Provider, { value: ctxValue, children: children(ctxValue) });
|
|
150
|
+
}
|
|
151
|
+
function DraggableHeaderCell({
|
|
152
|
+
id,
|
|
153
|
+
disabled,
|
|
154
|
+
isLocked,
|
|
155
|
+
dropIndicatorSide,
|
|
156
|
+
children
|
|
157
|
+
}) {
|
|
158
|
+
const draggable = useDraggable({ id, disabled, data: { type: "column", columnId: id } });
|
|
159
|
+
const droppable = useDroppable({ id, disabled, data: { type: "column", columnId: id } });
|
|
160
|
+
const setRefs = React.useCallback((el) => {
|
|
161
|
+
draggable.setNodeRef(el);
|
|
162
|
+
droppable.setNodeRef(el);
|
|
163
|
+
}, [draggable.setNodeRef, droppable.setNodeRef]);
|
|
164
|
+
const isDragging = draggable.isDragging;
|
|
165
|
+
const dragStyle = {
|
|
166
|
+
...dragSourceStyle(isDragging)
|
|
167
|
+
};
|
|
168
|
+
const childProps = children.props;
|
|
169
|
+
const { role: _draggableRole, ...draggableAttrs } = draggable.attributes;
|
|
170
|
+
const indicatorClass = dropIndicatorSide === "before" ? dropIndicatorColumn.pseudoBefore : dropIndicatorSide === "after" ? dropIndicatorColumn.pseudoAfter : "";
|
|
171
|
+
return React.cloneElement(children, {
|
|
172
|
+
ref: setRefs,
|
|
173
|
+
style: { ...childProps.style ?? {}, ...dragStyle },
|
|
174
|
+
"data-column-id": id,
|
|
175
|
+
"data-column-locked": isLocked || void 0,
|
|
176
|
+
...disabled ? {} : { ...draggableAttrs, ...draggable.listeners },
|
|
177
|
+
// 2026-05-06 v14.9 cursor canonical(對齊 Notion / Jira):
|
|
178
|
+
// **idle hover NOT 顯 cursor-grab** — header click 觸發 sort,grab cursor 會誤導 user 以為「點 = 拖」;
|
|
179
|
+
// **drag activation 後**(isDragging=true,過 8px activationConstraint)才顯 cursor-grabbing。
|
|
180
|
+
// user 點 = sort / 長壓 = drag,兩語意分開不互踩。
|
|
181
|
+
className: cn(childProps.className, isDragging && dragActiveCursor, indicatorClass)
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function RowDragHandle({ disabled, anyDragActive }) {
|
|
185
|
+
const ctx = React.useContext(SortableRowCtx);
|
|
186
|
+
const [rowEl, setRowEl] = React.useState(null);
|
|
187
|
+
const [portalTarget, setPortalTarget] = React.useState(null);
|
|
188
|
+
const [pos, setPos] = React.useState(null);
|
|
189
|
+
const [buttonHovered, setButtonHovered] = React.useState(false);
|
|
190
|
+
const anchorRef = React.useCallback((node) => {
|
|
191
|
+
setRowEl((node == null ? void 0 : node.parentElement) ?? null);
|
|
192
|
+
}, []);
|
|
193
|
+
React.useLayoutEffect(() => {
|
|
194
|
+
if (!rowEl || !ctx || ctx.role !== "primary") return;
|
|
195
|
+
const tableEl = rowEl.closest("[data-data-table-outer]");
|
|
196
|
+
setPortalTarget((tableEl == null ? void 0 : tableEl.parentElement) ?? null);
|
|
197
|
+
const update = () => {
|
|
198
|
+
if (!tableEl) return;
|
|
199
|
+
const rRect = rowEl.getBoundingClientRect();
|
|
200
|
+
const tRect = tableEl.getBoundingClientRect();
|
|
201
|
+
const rowHovered = rowEl.hasAttribute("data-hovered");
|
|
202
|
+
setPos({
|
|
203
|
+
top: rRect.top + rRect.height / 2,
|
|
204
|
+
left: tRect.left,
|
|
205
|
+
// table outer 左 border line position(viewport coords)
|
|
206
|
+
rowHovered
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
update();
|
|
210
|
+
const observer = new MutationObserver(update);
|
|
211
|
+
observer.observe(rowEl, { attributes: true, attributeFilter: ["data-hovered"] });
|
|
212
|
+
let scrollRafId = 0;
|
|
213
|
+
const onScroll = () => {
|
|
214
|
+
if (scrollRafId) cancelAnimationFrame(scrollRafId);
|
|
215
|
+
scrollRafId = requestAnimationFrame(() => {
|
|
216
|
+
scrollRafId = 0;
|
|
217
|
+
update();
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
window.addEventListener("scroll", onScroll, true);
|
|
221
|
+
window.addEventListener("resize", onScroll);
|
|
222
|
+
return () => {
|
|
223
|
+
observer.disconnect();
|
|
224
|
+
if (scrollRafId) cancelAnimationFrame(scrollRafId);
|
|
225
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
226
|
+
window.removeEventListener("resize", onScroll);
|
|
227
|
+
};
|
|
228
|
+
}, [rowEl, ctx]);
|
|
229
|
+
const anchor = /* @__PURE__ */ jsx(
|
|
230
|
+
"span",
|
|
231
|
+
{
|
|
232
|
+
ref: anchorRef,
|
|
233
|
+
"aria-hidden": true,
|
|
234
|
+
style: { position: "absolute", top: 0, left: 0, width: 0, height: 0, pointerEvents: "none" }
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
if (!ctx || ctx.role !== "primary" || !pos) return anchor;
|
|
238
|
+
const canDrag = !disabled;
|
|
239
|
+
const showInvalid = !!ctx.invalidDrop && !!ctx.isDragging;
|
|
240
|
+
const visible = ctx.isDragging || !anyDragActive && (pos.rowHovered || buttonHovered);
|
|
241
|
+
const handle = /* @__PURE__ */ jsx(
|
|
242
|
+
Button,
|
|
243
|
+
{
|
|
244
|
+
ref: canDrag ? ctx.handleSetActivatorNodeRef : void 0,
|
|
245
|
+
variant: "tertiary",
|
|
246
|
+
iconOnly: true,
|
|
247
|
+
size: "xs",
|
|
248
|
+
startIcon: GripVertical,
|
|
249
|
+
"aria-label": canDrag ? "拖曳重排此列" : "排序中無法拖曳",
|
|
250
|
+
"aria-disabled": !canDrag || void 0,
|
|
251
|
+
tabIndex: canDrag ? 0 : -1,
|
|
252
|
+
onMouseEnter: () => setButtonHovered(true),
|
|
253
|
+
onMouseLeave: () => setButtonHovered(false),
|
|
254
|
+
style: {
|
|
255
|
+
position: "fixed",
|
|
256
|
+
top: pos.top,
|
|
257
|
+
left: pos.left,
|
|
258
|
+
transform: "translate(-50%, -50%)",
|
|
259
|
+
zIndex: 50,
|
|
260
|
+
// 2026-05-12 fix v2(user 抓「drag column sort 啟用時 button 不是 disable 視覺」):
|
|
261
|
+
// 前 Round 4.5 加 `aria-disabled:opacity-[var(--opacity-disabled)]` 在 Button cva
|
|
262
|
+
// 沒生效 — 因為 inline style `opacity` 永遠 win over Tailwind class。Fix:把 disabled
|
|
263
|
+
// state opacity 也 compute 進 inline style。priority order:invisible 0 → drag 0.5 →
|
|
264
|
+
// canDrag=false(sort active)disabled visual var(--opacity-disabled) 0.45 → idle 1。
|
|
265
|
+
opacity: visible ? ctx.isDragging ? 0.5 : canDrag ? 1 : "var(--opacity-disabled)" : 0,
|
|
266
|
+
pointerEvents: visible ? "auto" : "none",
|
|
267
|
+
transition: "opacity 150ms ease"
|
|
268
|
+
},
|
|
269
|
+
className: cn(
|
|
270
|
+
// 2026-05-12 debug fix(user 抓「hover 還是透明」)— Round 4.5 我未授權加
|
|
271
|
+
// `border / shadow / hover:bg-neutral-hover` = over-design + hover override 讓
|
|
272
|
+
// drag button hover bg 變 neutral-hover 跟 row hover bg 同色 → 視覺融入 row = 透明。
|
|
273
|
+
// 撤回:**只保 bg-surface-raised(idle + hover + 所有 state 都同 bg)**,
|
|
274
|
+
// border / shadow / hover override 全 retire(user verbatim「我有叫你加 elevation 嗎」)。
|
|
275
|
+
// 對所有 state(idle / hover / aria-disabled / data-state)套同 bg-surface-raised — 跟
|
|
276
|
+
// row 任何 state 視覺都有 token-level 對比(在 token 差異存在的 mode;light mode --surface-raised
|
|
277
|
+
// 等於 --surface 是 design token semantic,非本 fix scope)。
|
|
278
|
+
"bg-surface-raised hover:bg-surface-raised aria-disabled:bg-surface-raised",
|
|
279
|
+
canDrag && !showInvalid && "cursor-grab",
|
|
280
|
+
canDrag && showInvalid && "cursor-not-allowed !text-error !border-error",
|
|
281
|
+
// drag 進行中 source button cursor(opacity 0.5 via style;aria-disabled visual 由 Button cva 接管)
|
|
282
|
+
ctx.isDragging && "cursor-grabbing"
|
|
283
|
+
),
|
|
284
|
+
...canDrag ? ctx.handleListeners ?? {} : {},
|
|
285
|
+
...canDrag ? ctx.handleAttributes ?? {} : {}
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
const wrapped = disabled ? /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
289
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: handle }),
|
|
290
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: "排序中無法拖曳,清除排序後可重排" })
|
|
291
|
+
] }) : handle;
|
|
292
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
293
|
+
anchor,
|
|
294
|
+
portalTarget && createPortal(wrapped, portalTarget)
|
|
295
|
+
] });
|
|
296
|
+
}
|
|
297
|
+
function DataTableInner({
|
|
298
|
+
columns,
|
|
299
|
+
data,
|
|
300
|
+
size = "md",
|
|
301
|
+
autoRowHeight = false,
|
|
302
|
+
height = "400px",
|
|
303
|
+
overscan = 5,
|
|
304
|
+
emptyState,
|
|
305
|
+
enableHover = true,
|
|
306
|
+
bordered,
|
|
307
|
+
estimateRowHeight,
|
|
308
|
+
tableOptions,
|
|
309
|
+
rowActions,
|
|
310
|
+
cellErrors,
|
|
311
|
+
pinnedLeftColumns,
|
|
312
|
+
pinnedRightColumns,
|
|
313
|
+
inlineEdit = false,
|
|
314
|
+
selection: selectionProp,
|
|
315
|
+
defaultSelection,
|
|
316
|
+
onSelectionChange,
|
|
317
|
+
selectable = false,
|
|
318
|
+
isRowSelectable,
|
|
319
|
+
getRowId,
|
|
320
|
+
getRowAriaLabel,
|
|
321
|
+
preserveSelectionOnFilter = false,
|
|
322
|
+
columnVisibility: columnVisibilityProp,
|
|
323
|
+
defaultColumnVisibility,
|
|
324
|
+
onColumnVisibilityChange,
|
|
325
|
+
enableMultiSort = true,
|
|
326
|
+
onColumnFilterTrigger,
|
|
327
|
+
onCellCommit,
|
|
328
|
+
enableRowDrag = false,
|
|
329
|
+
onRowReorder,
|
|
330
|
+
enableColumnResize = false,
|
|
331
|
+
onColumnResize,
|
|
332
|
+
enableColumnReorder = false,
|
|
333
|
+
onColumnReorder,
|
|
334
|
+
experimentalSpreadsheetOverlay = false,
|
|
335
|
+
experimentalActiveEditorController = false,
|
|
336
|
+
spreadsheetMode = false,
|
|
337
|
+
className,
|
|
338
|
+
...props
|
|
339
|
+
}, ref) {
|
|
340
|
+
var _a, _b, _c;
|
|
341
|
+
const [editingCellId, setEditingCellId] = React.useState(null);
|
|
342
|
+
const [editingDraft, setEditingDraft] = React.useState(void 0);
|
|
343
|
+
const exitEdit = React.useCallback(() => {
|
|
344
|
+
setEditingCellId(null);
|
|
345
|
+
setEditingDraft(void 0);
|
|
346
|
+
}, []);
|
|
347
|
+
const [selectedCellId, setSelectedCellId] = React.useState(null);
|
|
348
|
+
const [rangeAnchor, setRangeAnchor] = React.useState(null);
|
|
349
|
+
const [rangeFocus, setRangeFocus] = React.useState(null);
|
|
350
|
+
React.useEffect(() => {
|
|
351
|
+
if (!spreadsheetMode) return;
|
|
352
|
+
if (selectedCellId == null && rangeAnchor == null) return;
|
|
353
|
+
const handler = (e) => {
|
|
354
|
+
const target = e.target;
|
|
355
|
+
if (!target) return;
|
|
356
|
+
if (!target.closest("[data-data-table-outer]")) {
|
|
357
|
+
setSelectedCellId(null);
|
|
358
|
+
setRangeAnchor(null);
|
|
359
|
+
setRangeFocus(null);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
document.addEventListener("pointerdown", handler, true);
|
|
363
|
+
return () => document.removeEventListener("pointerdown", handler, true);
|
|
364
|
+
}, [spreadsheetMode, selectedCellId, rangeAnchor]);
|
|
365
|
+
const commitCell = React.useCallback(
|
|
366
|
+
(rowId, colId, next) => {
|
|
367
|
+
onCellCommit == null ? void 0 : onCellCommit(rowId, colId, next);
|
|
368
|
+
setEditingCellId(null);
|
|
369
|
+
setEditingDraft(void 0);
|
|
370
|
+
},
|
|
371
|
+
[onCellCommit]
|
|
372
|
+
);
|
|
373
|
+
const isCellEditable = React.useCallback(
|
|
374
|
+
// any-allow: free-form consumer meta — same rationale as L143 renderTypedValue
|
|
375
|
+
(meta, row) => {
|
|
376
|
+
const e = meta == null ? void 0 : meta.editable;
|
|
377
|
+
if (typeof e === "function") return e(row) === true;
|
|
378
|
+
return e === true;
|
|
379
|
+
},
|
|
380
|
+
[]
|
|
381
|
+
);
|
|
382
|
+
const isCellDisabled = React.useCallback(
|
|
383
|
+
// any-allow: free-form consumer meta — same rationale as L143 renderTypedValue
|
|
384
|
+
(meta, row) => {
|
|
385
|
+
const d = meta == null ? void 0 : meta.disabled;
|
|
386
|
+
if (typeof d === "function") return d(row) === true;
|
|
387
|
+
return d === true;
|
|
388
|
+
},
|
|
389
|
+
[]
|
|
390
|
+
);
|
|
391
|
+
const canEditCell = React.useCallback(
|
|
392
|
+
(meta, row) => isCellEditable(meta, row) && !isCellDisabled(meta, row),
|
|
393
|
+
[isCellEditable, isCellDisabled]
|
|
394
|
+
);
|
|
395
|
+
const [sorting, setSorting] = React.useState(((_a = tableOptions == null ? void 0 : tableOptions.state) == null ? void 0 : _a.sorting) ?? []);
|
|
396
|
+
const [columnVisibility, setColumnVisibility] = useControllable({
|
|
397
|
+
value: columnVisibilityProp,
|
|
398
|
+
defaultValue: defaultColumnVisibility ?? {},
|
|
399
|
+
onChange: onColumnVisibilityChange
|
|
400
|
+
});
|
|
401
|
+
const enabled = selectable !== false;
|
|
402
|
+
const mode = selectable === "single" ? "single" : "multi";
|
|
403
|
+
const [selection, setSelection] = useControllable({
|
|
404
|
+
value: selectionProp,
|
|
405
|
+
defaultValue: defaultSelection ?? [],
|
|
406
|
+
onChange: onSelectionChange
|
|
407
|
+
});
|
|
408
|
+
const anchorRowIdRef = React.useRef(null);
|
|
409
|
+
const dsProcessedColumns = React.useMemo(() => {
|
|
410
|
+
return columns.map((c) => {
|
|
411
|
+
const meta = c.meta;
|
|
412
|
+
if (!meta) return c;
|
|
413
|
+
const cAny = c;
|
|
414
|
+
const updates = {};
|
|
415
|
+
if (meta.width !== void 0 && cAny.size === void 0) updates.size = meta.width;
|
|
416
|
+
if (meta.minWidth !== void 0 && cAny.minSize === void 0) updates.minSize = meta.minWidth;
|
|
417
|
+
if (meta.maxWidth !== void 0 && cAny.maxSize === void 0) updates.maxSize = meta.maxWidth;
|
|
418
|
+
return Object.keys(updates).length > 0 ? { ...c, ...updates } : c;
|
|
419
|
+
});
|
|
420
|
+
}, [columns]);
|
|
421
|
+
const columnsWithSelection = React.useMemo(() => {
|
|
422
|
+
if (!enabled) return dsProcessedColumns;
|
|
423
|
+
const selectCol = {
|
|
424
|
+
id: SELECT_COL_ID,
|
|
425
|
+
size: 40,
|
|
426
|
+
enableSorting: false,
|
|
427
|
+
enableResizing: false,
|
|
428
|
+
enableHiding: false,
|
|
429
|
+
// selection col 不能藏(L3 column visibility)
|
|
430
|
+
header: "Select",
|
|
431
|
+
// header cell 由下方自訂 render 取代
|
|
432
|
+
cell: () => null
|
|
433
|
+
// body cell 由下方自訂 render 取代
|
|
434
|
+
};
|
|
435
|
+
return [selectCol, ...dsProcessedColumns];
|
|
436
|
+
}, [dsProcessedColumns, enabled]);
|
|
437
|
+
const effectivePinnedLeft = React.useMemo(() => {
|
|
438
|
+
const list = pinnedLeftColumns ?? [];
|
|
439
|
+
const out = [...list];
|
|
440
|
+
if (enabled && !out.includes(SELECT_COL_ID)) out.unshift(SELECT_COL_ID);
|
|
441
|
+
return out;
|
|
442
|
+
}, [pinnedLeftColumns, enabled]);
|
|
443
|
+
const userColumnOrder = (_b = tableOptions == null ? void 0 : tableOptions.state) == null ? void 0 : _b.columnOrder;
|
|
444
|
+
const effectiveColumnOrder = React.useMemo(() => {
|
|
445
|
+
if (!userColumnOrder) return userColumnOrder;
|
|
446
|
+
if (!enabled) return userColumnOrder;
|
|
447
|
+
const out = [...userColumnOrder];
|
|
448
|
+
if (enabled && !out.includes(SELECT_COL_ID)) out.unshift(SELECT_COL_ID);
|
|
449
|
+
return out;
|
|
450
|
+
}, [userColumnOrder, enabled]);
|
|
451
|
+
const table = useReactTable({
|
|
452
|
+
...tableOptions,
|
|
453
|
+
data,
|
|
454
|
+
columns: columnsWithSelection,
|
|
455
|
+
state: {
|
|
456
|
+
sorting,
|
|
457
|
+
columnVisibility,
|
|
458
|
+
...tableOptions == null ? void 0 : tableOptions.state,
|
|
459
|
+
// columnPinning + columnOrder 在 user state 後 override,確保 __select__ 永遠左
|
|
460
|
+
columnPinning: { left: effectivePinnedLeft, right: pinnedRightColumns ?? [] },
|
|
461
|
+
...effectiveColumnOrder ? { columnOrder: effectiveColumnOrder } : {}
|
|
462
|
+
},
|
|
463
|
+
enableMultiSort,
|
|
464
|
+
// **#1 fix(2026-05-04)**:chain user `tableOptions.onSortingChange`(spread 在前被 override = 之前 bug)
|
|
465
|
+
// 同 onColumnVisibilityChange:both internal setState + forward 給 user external state
|
|
466
|
+
onSortingChange: (updater) => {
|
|
467
|
+
var _a2;
|
|
468
|
+
setSorting(updater);
|
|
469
|
+
(_a2 = tableOptions == null ? void 0 : tableOptions.onSortingChange) == null ? void 0 : _a2.call(tableOptions, updater);
|
|
470
|
+
},
|
|
471
|
+
onColumnVisibilityChange: (updater) => {
|
|
472
|
+
var _a2;
|
|
473
|
+
const next = typeof updater === "function" ? updater(columnVisibility) : updater;
|
|
474
|
+
setColumnVisibility(next);
|
|
475
|
+
(_a2 = tableOptions == null ? void 0 : tableOptions.onColumnVisibilityChange) == null ? void 0 : _a2.call(tableOptions, updater);
|
|
476
|
+
},
|
|
477
|
+
getCoreRowModel: getCoreRowModel(),
|
|
478
|
+
getSortedRowModel: getSortedRowModel(),
|
|
479
|
+
// L4 nested rows:啟用 expanded row model(consumer 透過 tableOptions.getSubRows + state.expanded forward)
|
|
480
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
481
|
+
getRowId,
|
|
482
|
+
// 2026-05-06 v14 column resize:`onChange` mode → drag 中 column 即時跟動 cursor(world-class
|
|
483
|
+
// canonical:TanStack docs / AG Grid / Excel / Google Sheets 全部 live resize)。前 v13.2
|
|
484
|
+
// 用 `onEnd` 拖完才 jump,user 報「感覺超頓像 bug」。tanstack 內部管 columnSizing state
|
|
485
|
+
// (uncontrolled);`columnSizingState` 變動透過 useEffect 觀測 + 呼 callback。
|
|
486
|
+
//
|
|
487
|
+
// 前 v11 用 `onColumnSizingChange` 接管 updater 但忘了 setColumnSizing,導致 state 永遠不變動 →
|
|
488
|
+
// column.getSize() 永遠回初始值 → drag visual 完全沒效果(user 報 "drag 沒反應")。本 v13.2 改回
|
|
489
|
+
// tanstack uncontrolled state(預設行為)+ useEffect 觀測 columnSizing 變動 fire callback。
|
|
490
|
+
enableColumnResizing: enableColumnResize,
|
|
491
|
+
columnResizeMode: "onChange"
|
|
492
|
+
});
|
|
493
|
+
const columnSizingState = table.getState().columnSizing;
|
|
494
|
+
const prevColumnSizingRef = React.useRef(columnSizingState);
|
|
495
|
+
React.useEffect(() => {
|
|
496
|
+
if (!onColumnResize) return;
|
|
497
|
+
const prev = prevColumnSizingRef.current;
|
|
498
|
+
Object.keys(columnSizingState).forEach((id) => {
|
|
499
|
+
if (columnSizingState[id] !== prev[id]) {
|
|
500
|
+
onColumnResize(id, columnSizingState[id]);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
prevColumnSizingRef.current = columnSizingState;
|
|
504
|
+
}, [columnSizingState, onColumnResize]);
|
|
505
|
+
const { rows } = table.getRowModel();
|
|
506
|
+
const isEmpty = rows.length === 0;
|
|
507
|
+
const hasHeightConstraint = height !== "auto";
|
|
508
|
+
const isFillHeight = hasHeightConstraint && /^(100%|100vh|fill)$/.test(height);
|
|
509
|
+
const VIRTUAL_THRESHOLD = 30;
|
|
510
|
+
const useVirtual = hasHeightConstraint && !isEmpty && rows.length > VIRTUAL_THRESHOLD;
|
|
511
|
+
const hasRowActions = !!rowActions;
|
|
512
|
+
const tableRef = React.useRef(null);
|
|
513
|
+
const bodyRef = React.useRef(null);
|
|
514
|
+
const centerHeaderRef = React.useRef(null);
|
|
515
|
+
const centerBodyRef = React.useRef(null);
|
|
516
|
+
const leftHeaderRef = React.useRef(null);
|
|
517
|
+
const rightHeaderRef = React.useRef(null);
|
|
518
|
+
const [leftWidth, setLeftWidth] = React.useState(0);
|
|
519
|
+
const [rightWidth, setRightWidth] = React.useState(0);
|
|
520
|
+
const ESTIMATE_BY_SIZE = { sm: 32, md: 40, lg: 48 };
|
|
521
|
+
const resolvedEstimate = estimateRowHeight ?? ESTIMATE_BY_SIZE[size] ?? 40;
|
|
522
|
+
const effectiveOverscan = enableRowDrag ? Math.max(overscan, 5) : overscan;
|
|
523
|
+
const activeDragIdRef = React.useRef(null);
|
|
524
|
+
const virtualizer = useVirtualizer({
|
|
525
|
+
count: useVirtual ? rows.length : 0,
|
|
526
|
+
// V scroll 現在在 centerBodyRef(不是外層 bodyRef)
|
|
527
|
+
getScrollElement: () => centerBodyRef.current,
|
|
528
|
+
estimateSize: () => resolvedEstimate,
|
|
529
|
+
overscan: effectiveOverscan,
|
|
530
|
+
enabled: useVirtual,
|
|
531
|
+
// 2026-05-14 P3 perf tune(per codex+Layer A 共識,user 拍板「全部做完」+
|
|
532
|
+
// CPU-throttle-reproducible verify infra):150ms → 250ms 減少 scroll
|
|
533
|
+
// start/end flip 次數 → TableScrollContext 重 cascade visible rich cell
|
|
534
|
+
// tree 機會降低。對齊 TanStack Virtual `isScrollingResetDelay` API。
|
|
535
|
+
isScrollingResetDelay: 250
|
|
536
|
+
});
|
|
537
|
+
const [bodyMaxHeight, setBodyMaxHeight] = React.useState(null);
|
|
538
|
+
React.useLayoutEffect(() => {
|
|
539
|
+
var _a2;
|
|
540
|
+
if (!isFillHeight) {
|
|
541
|
+
setBodyMaxHeight(null);
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
let rafId = null;
|
|
545
|
+
let stableTimer = null;
|
|
546
|
+
let lastValue = null;
|
|
547
|
+
let pendingValue = null;
|
|
548
|
+
const compute = () => {
|
|
549
|
+
if (!tableRef.current) return;
|
|
550
|
+
const parentEl = tableRef.current.parentElement;
|
|
551
|
+
const slotH = (parentEl == null ? void 0 : parentEl.getBoundingClientRect().height) ?? tableRef.current.getBoundingClientRect().height;
|
|
552
|
+
const headerEl = tableRef.current.firstElementChild;
|
|
553
|
+
const headerH = (headerEl == null ? void 0 : headerEl.getBoundingClientRect().height) ?? 0;
|
|
554
|
+
const next = Math.max(0, slotH - headerH);
|
|
555
|
+
if (lastValue != null && Math.abs(next - lastValue) < 4) return;
|
|
556
|
+
lastValue = next;
|
|
557
|
+
pendingValue = next;
|
|
558
|
+
if (stableTimer != null) clearTimeout(stableTimer);
|
|
559
|
+
stableTimer = setTimeout(() => {
|
|
560
|
+
if (pendingValue != null) setBodyMaxHeight(pendingValue);
|
|
561
|
+
stableTimer = null;
|
|
562
|
+
}, 100);
|
|
563
|
+
};
|
|
564
|
+
const scheduleCompute = () => {
|
|
565
|
+
if (rafId != null) return;
|
|
566
|
+
rafId = requestAnimationFrame(() => {
|
|
567
|
+
rafId = null;
|
|
568
|
+
compute();
|
|
569
|
+
});
|
|
570
|
+
};
|
|
571
|
+
compute();
|
|
572
|
+
const obs = new ResizeObserver(scheduleCompute);
|
|
573
|
+
if ((_a2 = tableRef.current) == null ? void 0 : _a2.parentElement) obs.observe(tableRef.current.parentElement);
|
|
574
|
+
return () => {
|
|
575
|
+
obs.disconnect();
|
|
576
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
577
|
+
if (stableTimer != null) clearTimeout(stableTimer);
|
|
578
|
+
};
|
|
579
|
+
}, [isFillHeight]);
|
|
580
|
+
const leftBodyRef = React.useRef(null);
|
|
581
|
+
const rightBodyRef = React.useRef(null);
|
|
582
|
+
const onCenterBodyScroll = React.useCallback(() => {
|
|
583
|
+
const cb = centerBodyRef.current;
|
|
584
|
+
if (!cb) return;
|
|
585
|
+
if (centerHeaderRef.current) centerHeaderRef.current.scrollLeft = cb.scrollLeft;
|
|
586
|
+
if (leftBodyRef.current) leftBodyRef.current.scrollTop = cb.scrollTop;
|
|
587
|
+
if (rightBodyRef.current) rightBodyRef.current.scrollTop = cb.scrollTop;
|
|
588
|
+
}, []);
|
|
589
|
+
const rangeCellIds = React.useMemo(() => {
|
|
590
|
+
if (!spreadsheetMode || !rangeAnchor || !rangeFocus || rangeAnchor === rangeFocus) return void 0;
|
|
591
|
+
const parseCell = (id) => {
|
|
592
|
+
const lastColon = id.lastIndexOf(":");
|
|
593
|
+
return { rowId: id.slice(0, lastColon), colId: id.slice(lastColon + 1) };
|
|
594
|
+
};
|
|
595
|
+
const a = parseCell(rangeAnchor);
|
|
596
|
+
const f = parseCell(rangeFocus);
|
|
597
|
+
const allRows = table.getRowModel().rows.map((r) => r.id);
|
|
598
|
+
const allCols = table.getVisibleLeafColumns().map((c) => c.id).filter((id) => id !== SELECT_COL_ID);
|
|
599
|
+
const aRowIdx = allRows.indexOf(a.rowId);
|
|
600
|
+
const fRowIdx = allRows.indexOf(f.rowId);
|
|
601
|
+
const aColIdx = allCols.indexOf(a.colId);
|
|
602
|
+
const fColIdx = allCols.indexOf(f.colId);
|
|
603
|
+
if (aRowIdx < 0 || fRowIdx < 0 || aColIdx < 0 || fColIdx < 0) return void 0;
|
|
604
|
+
const rowStart = Math.min(aRowIdx, fRowIdx);
|
|
605
|
+
const rowEnd = Math.max(aRowIdx, fRowIdx);
|
|
606
|
+
const colStart = Math.min(aColIdx, fColIdx);
|
|
607
|
+
const colEnd = Math.max(aColIdx, fColIdx);
|
|
608
|
+
const ids = [];
|
|
609
|
+
for (let r = rowStart; r <= rowEnd; r++) {
|
|
610
|
+
for (let c = colStart; c <= colEnd; c++) {
|
|
611
|
+
ids.push(`${allRows[r]}:${allCols[c]}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return ids;
|
|
615
|
+
}, [spreadsheetMode, rangeAnchor, rangeFocus, table]);
|
|
616
|
+
const rangeCellIdSet = React.useMemo(() => new Set(rangeCellIds || []), [rangeCellIds]);
|
|
617
|
+
const leftCols = table.getLeftVisibleLeafColumns();
|
|
618
|
+
const centerCols = table.getCenterVisibleLeafColumns();
|
|
619
|
+
const rightCols = table.getRightVisibleLeafColumns();
|
|
620
|
+
const hasLeft = leftCols.length > 0;
|
|
621
|
+
const hasRight = rightCols.length > 0 || hasRowActions;
|
|
622
|
+
const centerColsWidth = centerCols.reduce((a, c) => a + c.getSize(), 0);
|
|
623
|
+
React.useEffect(() => {
|
|
624
|
+
const measure = () => {
|
|
625
|
+
if (leftHeaderRef.current) setLeftWidth(leftHeaderRef.current.offsetWidth);
|
|
626
|
+
if (rightHeaderRef.current) setRightWidth(rightHeaderRef.current.offsetWidth);
|
|
627
|
+
};
|
|
628
|
+
measure();
|
|
629
|
+
const obs = new ResizeObserver(measure);
|
|
630
|
+
if (leftHeaderRef.current) obs.observe(leftHeaderRef.current);
|
|
631
|
+
if (rightHeaderRef.current) obs.observe(rightHeaderRef.current);
|
|
632
|
+
return () => obs.disconnect();
|
|
633
|
+
}, [hasLeft, hasRight, rows.length]);
|
|
634
|
+
const rowHeight = `h-table-row-${size}`;
|
|
635
|
+
const enterLeaveHandlers = React.useMemo(() => {
|
|
636
|
+
if (!enableHover) return { onMouseOver: void 0, onMouseOut: void 0 };
|
|
637
|
+
const findRowIndex = (target) => {
|
|
638
|
+
if (!(target instanceof HTMLElement)) return null;
|
|
639
|
+
const rowEl = target.closest("[data-row-index]");
|
|
640
|
+
return (rowEl == null ? void 0 : rowEl.dataset.rowIndex) ?? null;
|
|
641
|
+
};
|
|
642
|
+
return {
|
|
643
|
+
onMouseOver: (e) => {
|
|
644
|
+
var _a2;
|
|
645
|
+
if (activeDragIdRef.current != null) {
|
|
646
|
+
const target = e.target instanceof HTMLElement ? e.target : null;
|
|
647
|
+
const rowEl = target == null ? void 0 : target.closest("[data-sortable-row-id]");
|
|
648
|
+
const isSource = (rowEl == null ? void 0 : rowEl.dataset.sortableRowId) === activeDragIdRef.current;
|
|
649
|
+
if (!isSource) return;
|
|
650
|
+
}
|
|
651
|
+
const idx = findRowIndex(e.target);
|
|
652
|
+
if (idx == null) return;
|
|
653
|
+
(_a2 = tableRef.current) == null ? void 0 : _a2.querySelectorAll(`[data-row-index="${idx}"]`).forEach((el) => el.dataset.hovered = "");
|
|
654
|
+
},
|
|
655
|
+
onMouseOut: (e) => {
|
|
656
|
+
var _a2;
|
|
657
|
+
const idx = findRowIndex(e.target);
|
|
658
|
+
if (idx == null) return;
|
|
659
|
+
const related = e.relatedTarget instanceof HTMLElement ? e.relatedTarget.closest("[data-row-index]") : null;
|
|
660
|
+
if ((related == null ? void 0 : related.dataset.rowIndex) === idx) return;
|
|
661
|
+
(_a2 = tableRef.current) == null ? void 0 : _a2.querySelectorAll(`[data-row-index="${idx}"]`).forEach((el) => delete el.dataset.hovered);
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
}, [enableHover]);
|
|
665
|
+
const hoverProps = (_idx) => ({});
|
|
666
|
+
const renderCellContent = (cell) => {
|
|
667
|
+
const meta = cell.column.columnDef.meta;
|
|
668
|
+
const colType = meta == null ? void 0 : meta.type;
|
|
669
|
+
const wrap = autoRowHeight && (meta == null ? void 0 : meta.wrap) === true;
|
|
670
|
+
const isKnownCompound = colType === "select" || colType === "multiSelect" || colType === "person" || colType === "multiPerson" || colType === "url" || colType === "date" || colType === "time";
|
|
671
|
+
const rowId = cell.row.id;
|
|
672
|
+
const colId = cell.column.id;
|
|
673
|
+
const editable = isCellEditable(meta, cell.row.original);
|
|
674
|
+
const disabled = isCellDisabled(meta, cell.row.original);
|
|
675
|
+
const isEditingThisCell = editingCellId === cellEditId(rowId, colId);
|
|
676
|
+
let content;
|
|
677
|
+
if (colType) {
|
|
678
|
+
const Cell = resolveCellComponent(colType);
|
|
679
|
+
const cellMode = experimentalActiveEditorController && isEditingThisCell ? "display" : isEditingThisCell && !disabled ? "edit" : "display";
|
|
680
|
+
content = /* @__PURE__ */ jsx(
|
|
681
|
+
Cell,
|
|
682
|
+
{
|
|
683
|
+
value: cell.getValue(),
|
|
684
|
+
meta: meta ?? {},
|
|
685
|
+
mode: cellMode,
|
|
686
|
+
size,
|
|
687
|
+
autoRowHeight,
|
|
688
|
+
isEditable: editable,
|
|
689
|
+
isDisabled: disabled,
|
|
690
|
+
onCommit: (next) => commitCell(rowId, colId, next),
|
|
691
|
+
onCommitLive: (next) => onCellCommit == null ? void 0 : onCellCommit(rowId, colId, next),
|
|
692
|
+
onCancel: exitEdit,
|
|
693
|
+
onRequestEdit: () => !disabled && setEditingCellId(cellEditId(rowId, colId))
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
} else {
|
|
697
|
+
content = flexRender(cell.column.columnDef.cell, cell.getContext());
|
|
698
|
+
}
|
|
699
|
+
const isConsumerCompound = !colType && React.isValidElement(content);
|
|
700
|
+
return isEditingThisCell ? content : wrap ? /* @__PURE__ */ jsx("span", { className: "break-words min-w-0", children: content }) : isKnownCompound || isConsumerCompound ? content : /* @__PURE__ */ jsx(TruncateCell, { children: content });
|
|
701
|
+
};
|
|
702
|
+
const iconSize = ICON_SIZE[size];
|
|
703
|
+
const dragDisabled = sorting.length > 0;
|
|
704
|
+
const { allRowIds, parentMap } = React.useMemo(() => {
|
|
705
|
+
const ids = [];
|
|
706
|
+
const pmap = /* @__PURE__ */ new Map();
|
|
707
|
+
const walk = (r, parentId) => {
|
|
708
|
+
ids.push(r.id);
|
|
709
|
+
pmap.set(r.id, parentId);
|
|
710
|
+
const subs = r.subRows;
|
|
711
|
+
if (subs && Array.isArray(subs)) subs.forEach((s) => walk(s, r.id));
|
|
712
|
+
};
|
|
713
|
+
rows.forEach((r) => {
|
|
714
|
+
if ((r.depth ?? 0) === 0) walk(r, "");
|
|
715
|
+
});
|
|
716
|
+
return { allRowIds: ids, parentMap: pmap };
|
|
717
|
+
}, [rows]);
|
|
718
|
+
const [activeDragId, setActiveDragId] = React.useState(null);
|
|
719
|
+
React.useEffect(() => {
|
|
720
|
+
activeDragIdRef.current = activeDragId;
|
|
721
|
+
if (enableRowDrag && useVirtual) virtualizer.measure();
|
|
722
|
+
}, [activeDragId, enableRowDrag, useVirtual, virtualizer]);
|
|
723
|
+
const [invalidDropActive, setInvalidDropActive] = React.useState(false);
|
|
724
|
+
const invalidRef = React.useRef(false);
|
|
725
|
+
invalidRef.current = invalidDropActive;
|
|
726
|
+
const cellEl = (cell, _isLastInRow = false) => {
|
|
727
|
+
var _a2, _b2, _c2, _d, _e, _f;
|
|
728
|
+
if (enabled && cell.column.id === SELECT_COL_ID) {
|
|
729
|
+
const rowId = cell.row.id;
|
|
730
|
+
const rowOriginal = cell.row.original;
|
|
731
|
+
const isDisabled = isRowSelectable ? !isRowSelectable(rowOriginal) : false;
|
|
732
|
+
const ariaLabel = (getRowAriaLabel == null ? void 0 : getRowAriaLabel(rowOriginal)) ?? "Select row";
|
|
733
|
+
const checkboxSize = size === "lg" ? "lg" : "md";
|
|
734
|
+
const onCellClick = isDisabled ? void 0 : (e) => {
|
|
735
|
+
e.stopPropagation();
|
|
736
|
+
if (mode === "single") setSelection([rowId]);
|
|
737
|
+
else toggleRow(rowId, rowOriginal, { shiftKey: e.shiftKey });
|
|
738
|
+
};
|
|
739
|
+
return /* @__PURE__ */ jsx(
|
|
740
|
+
"div",
|
|
741
|
+
{
|
|
742
|
+
role: "cell",
|
|
743
|
+
"data-column-id": SELECT_COL_ID,
|
|
744
|
+
className: cn("flex items-center justify-center shrink-0", !isDisabled && "cursor-pointer"),
|
|
745
|
+
style: { ...columnSizeStyle(cell.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(cell.column.id) }), ...cellPadding },
|
|
746
|
+
onClick: onCellClick,
|
|
747
|
+
children: mode === "single" ? /* @__PURE__ */ jsx(
|
|
748
|
+
RadioGroupItem,
|
|
749
|
+
{
|
|
750
|
+
size: checkboxSize,
|
|
751
|
+
value: rowId,
|
|
752
|
+
disabled: isDisabled,
|
|
753
|
+
"aria-label": ariaLabel,
|
|
754
|
+
onClick: (e) => e.stopPropagation()
|
|
755
|
+
}
|
|
756
|
+
) : /* @__PURE__ */ jsx(
|
|
757
|
+
Checkbox,
|
|
758
|
+
{
|
|
759
|
+
size: checkboxSize,
|
|
760
|
+
checked: selectionSet.has(rowId),
|
|
761
|
+
disabled: isDisabled,
|
|
762
|
+
"aria-label": ariaLabel,
|
|
763
|
+
onClick: (e) => {
|
|
764
|
+
e.stopPropagation();
|
|
765
|
+
if (isDisabled) return;
|
|
766
|
+
e.preventDefault();
|
|
767
|
+
toggleRow(rowId, rowOriginal, { shiftKey: e.shiftKey });
|
|
768
|
+
},
|
|
769
|
+
onKeyDown: (e) => {
|
|
770
|
+
if (e.key === " " && !isDisabled) {
|
|
771
|
+
e.preventDefault();
|
|
772
|
+
toggleRow(rowId, rowOriginal, { shiftKey: e.shiftKey });
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
)
|
|
777
|
+
},
|
|
778
|
+
cell.id
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
const meta = cell.column.columnDef.meta;
|
|
782
|
+
const colType = meta == null ? void 0 : meta.type;
|
|
783
|
+
const align = (meta == null ? void 0 : meta.align) ?? (colType ? columnTypeDefaults[colType].align : void 0);
|
|
784
|
+
const cellRowId = cell.row.id;
|
|
785
|
+
const cellColId = cell.column.id;
|
|
786
|
+
const cellEditable = isCellEditable(meta, cell.row.original);
|
|
787
|
+
const cellDisabled = isCellDisabled(meta, cell.row.original);
|
|
788
|
+
const isEditingThisCell = editingCellId === cellEditId(cellRowId, cellColId);
|
|
789
|
+
const cellSpreadsheetId = `${cellRowId}:${cellColId}`;
|
|
790
|
+
const isSelectedCell = spreadsheetMode && selectedCellId === cellSpreadsheetId;
|
|
791
|
+
const onEditableCellClick = cellEditable && !cellDisabled && colType !== "boolean" && colType !== "url" && !isEditingThisCell ? (e) => {
|
|
792
|
+
if (spreadsheetMode) {
|
|
793
|
+
if (e.shiftKey && rangeAnchor != null) {
|
|
794
|
+
setRangeFocus(cellSpreadsheetId);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (isSelectedCell) {
|
|
798
|
+
setEditingCellId(cellEditId(cellRowId, cellColId));
|
|
799
|
+
setSelectedCellId(null);
|
|
800
|
+
setRangeAnchor(null);
|
|
801
|
+
setRangeFocus(null);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
setSelectedCellId(cellSpreadsheetId);
|
|
805
|
+
setRangeAnchor(cellSpreadsheetId);
|
|
806
|
+
setRangeFocus(null);
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
setEditingCellId(cellEditId(cellRowId, cellColId));
|
|
810
|
+
} : void 0;
|
|
811
|
+
const allCells = cell.row.getVisibleCells();
|
|
812
|
+
const firstContentCell = allCells.find((c) => c.column.id !== SELECT_COL_ID);
|
|
813
|
+
const isFirstContent = (firstContentCell == null ? void 0 : firstContentCell.id) === cell.id;
|
|
814
|
+
const depth = cell.row.depth ?? 0;
|
|
815
|
+
const canExpand = ((_b2 = (_a2 = cell.row).getCanExpand) == null ? void 0 : _b2.call(_a2)) ?? false;
|
|
816
|
+
const isExpanded = ((_d = (_c2 = cell.row).getIsExpanded) == null ? void 0 : _d.call(_c2)) ?? false;
|
|
817
|
+
const toggleExpand = (_f = (_e = cell.row).getToggleExpandedHandler) == null ? void 0 : _f.call(_e);
|
|
818
|
+
const showNestedPrefix = isFirstContent && (depth > 0 || canExpand);
|
|
819
|
+
const rawCellError = cellErrors == null ? void 0 : cellErrors[`${cellRowId}:${cellColId}`];
|
|
820
|
+
const cellErrorMessages = (() => {
|
|
821
|
+
if (isEditingThisCell) return null;
|
|
822
|
+
if (rawCellError == null) return null;
|
|
823
|
+
return Array.isArray(rawCellError) ? rawCellError : [rawCellError];
|
|
824
|
+
})();
|
|
825
|
+
const hasCellError = cellErrorMessages != null && cellErrorMessages.length > 0;
|
|
826
|
+
const cellErrorId = hasCellError ? `cell-err-${cellRowId}-${cellColId}` : void 0;
|
|
827
|
+
const rowHasAnyError = !!cellErrors && cell.row.getVisibleCells().some((c) => {
|
|
828
|
+
const v = cellErrors[`${cell.row.id}:${c.column.id}`];
|
|
829
|
+
return v != null && (Array.isArray(v) ? v.length > 0 : true);
|
|
830
|
+
});
|
|
831
|
+
const effectiveAutoRowForCell = autoRowHeight || rowHasAnyError;
|
|
832
|
+
return /* @__PURE__ */ jsx(
|
|
833
|
+
"div",
|
|
834
|
+
{
|
|
835
|
+
role: "cell",
|
|
836
|
+
"data-row-mode": effectiveAutoRowForCell ? "auto" : "fixed",
|
|
837
|
+
"data-column-id": cell.column.id,
|
|
838
|
+
"data-cell-id": `${cell.row.id}:${cell.column.id}`,
|
|
839
|
+
"data-range-cell": spreadsheetMode && rangeCellIdSet.has(`${cell.row.id}:${cell.column.id}`) ? "" : void 0,
|
|
840
|
+
"data-cell-disabled": cellDisabled ? "true" : void 0,
|
|
841
|
+
"aria-describedby": cellErrorId,
|
|
842
|
+
"aria-invalid": hasCellError || void 0,
|
|
843
|
+
className: cn(
|
|
844
|
+
// Cell box(2026-05-05 v6 — A4 canonical: Field frame seamlessly replaces cell border):
|
|
845
|
+
// - `self-stretch`: cell 永遠填 row 高
|
|
846
|
+
// - **vertical alignment by row-mode**: autoRow=items-start(top per spec) /
|
|
847
|
+
// fixed=items-center(centered per spec)。indicator + 非 Field 內容跟 cell 走。
|
|
848
|
+
// - **editing cell**: padding=0 + 無 right divider → Field naked(`!h-full !px-[cell-px]
|
|
849
|
+
// !py-[cell-py]`)邊框與 table divider 無縫接軌,seamlessly replace cell border。
|
|
850
|
+
// Adjacent cell padding+divider 仍在,只 editing cell 自己改觀。對齊 user reminder
|
|
851
|
+
// 「框框跟 cell 一樣大並取代 cell 的框且與 table 隔線無縫接軌」(2026-05-05)。
|
|
852
|
+
// - **沒有** cell 自己 box-shadow ring — focus / hover / open ring 由 Field naked 自帶
|
|
853
|
+
// state machine 提供(對齊 user「狀態樣式取決於原輸入框」reminder)
|
|
854
|
+
"group/cell flex text-foreground text-body font-normal shrink-0 relative self-stretch",
|
|
855
|
+
// Issue 9(2026-05-10):有 cell error → unset overflow-hidden 讓 error message
|
|
856
|
+
// wrap 撐 row 高。**H1(2026-05-10)升級**:overflow-visible 條件改 `rowHasAnyError` —
|
|
857
|
+
// row 內任一 cell 有 error 整 row 全 cells 都 overflow-visible(error 訊息可能多行
|
|
858
|
+
// 撐高 row,row 高同步 effectiveAutoRow auto)。
|
|
859
|
+
rowHasAnyError ? "overflow-visible" : "overflow-hidden",
|
|
860
|
+
effectiveAutoRowForCell ? "items-start" : "items-center",
|
|
861
|
+
align === "right" && "justify-end text-right",
|
|
862
|
+
align === "center" && "justify-center text-center",
|
|
863
|
+
// Phase 9 Issue 8 fix(2026-05-10 user 撞 + codex 重比稿 verdict ADOPT):
|
|
864
|
+
// 之前 `border-r border-divider` 只 right edge → hover overlay outline:-1px 只 right
|
|
865
|
+
// 邊壓 cell border,上左下 sub-pixel 不一致(user 抓「右 1px / 上左下 2px」bug)。
|
|
866
|
+
// 改 `dtCellGrid` (data-table.css:96-110)用 `box-shadow: inset` 4 邊 1px divider,
|
|
867
|
+
// 不佔 layout(per user verbatim「在 cell 內容起始位置不變」前提)→ 4 邊一致 grid line
|
|
868
|
+
// → overlay outline:-1px 4 邊都剛好壓 cell border line。
|
|
869
|
+
// Field naked edit border 仍 own(per Field SSOT)— 編輯時 Field 自帶 border 1px,
|
|
870
|
+
// 跟 cell 4 邊 inset divider 視覺相疊(同 pixel)= 1 line visual,不雙線。
|
|
871
|
+
inlineEdit && "dtCellGrid",
|
|
872
|
+
onEditableCellClick && ["cursor-pointer", nakedCellEditableDisplayHover],
|
|
873
|
+
// editable cell display hover affordance(對齊 Notion / Airtable hover-cell-shows-border canonical)
|
|
874
|
+
// 2026-05-13 Q3 cell disabled SSOT(per codex Q3 verdict + user 拍板「全部馬不停蹄做完」):
|
|
875
|
+
// bg `--bg-disabled` component-state token(color.spec.md:671 owner)+ cursor 抑制 click affordance。
|
|
876
|
+
cellDisabled && "bg-disabled cursor-not-allowed",
|
|
877
|
+
// z-10 raise inline-edit cell;portal mode 不需(layer z-3 already on top)。
|
|
878
|
+
isEditingThisCell && !experimentalActiveEditorController && "z-10"
|
|
879
|
+
),
|
|
880
|
+
style: {
|
|
881
|
+
...columnSizeStyle(cell.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(cell.column.id) }),
|
|
882
|
+
// Padding override 只在 inline-edit cell(naked Field 撐滿 cell);portal mode cell 走正常 display padding
|
|
883
|
+
...isEditingThisCell && !experimentalActiveEditorController ? {} : cellPadding,
|
|
884
|
+
// Slice D Step 2(2026-05-10):flag 開時 set CSS variable 抑制 Field naked hover outline,
|
|
885
|
+
// 讓 overlay layer 接管 hover ring paint(per RFC Contract 8 「one geometry owner, two paint owners」)。
|
|
886
|
+
// Backward-compat:flag 關時 unset → field-wrapper default `var(--border-hover)`(既有行為)。
|
|
887
|
+
...experimentalSpreadsheetOverlay && { "--cell-hover-outline-color": "transparent" }
|
|
888
|
+
},
|
|
889
|
+
onClick: onEditableCellClick,
|
|
890
|
+
children: hasCellError ? /* @__PURE__ */ jsxs("span", { className: "flex flex-col self-stretch w-full min-w-0 gap-1", children: [
|
|
891
|
+
/* @__PURE__ */ jsxs("span", { className: "flex flex-1 min-w-0", children: [
|
|
892
|
+
showNestedPrefix && /* @__PURE__ */ jsx(
|
|
893
|
+
"span",
|
|
894
|
+
{
|
|
895
|
+
className: "flex items-center shrink-0",
|
|
896
|
+
style: { paddingLeft: depth > 0 ? `calc(${depth} * var(--tree-indent-${size}, var(--tree-indent-md)))` : 0 },
|
|
897
|
+
children: canExpand ? /* @__PURE__ */ jsx(
|
|
898
|
+
"button",
|
|
899
|
+
{
|
|
900
|
+
type: "button",
|
|
901
|
+
"aria-label": isExpanded ? "收合" : "展開",
|
|
902
|
+
"aria-expanded": isExpanded,
|
|
903
|
+
className: "inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-foreground rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-transform",
|
|
904
|
+
style: { transform: isExpanded ? "rotate(90deg)" : void 0 },
|
|
905
|
+
onClick: (e) => {
|
|
906
|
+
e.stopPropagation();
|
|
907
|
+
toggleExpand == null ? void 0 : toggleExpand();
|
|
908
|
+
},
|
|
909
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, "aria-hidden": true, style: { transform: "rotate(-90deg)" } })
|
|
910
|
+
}
|
|
911
|
+
) : /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "shrink-0 w-4 h-4 mr-2" })
|
|
912
|
+
}
|
|
913
|
+
),
|
|
914
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
915
|
+
"flex-1 min-w-0 flex",
|
|
916
|
+
// 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓漏)— error-cell branch 也用 per-row state
|
|
917
|
+
// (`effectiveAutoRowForCell`)非 global `autoRowHeight`,跟 line 1559 non-error wrapper 同 SSOT。
|
|
918
|
+
// 前 Round 4 漏修此 branch → error 那格 row 內視覺仍走 global mode mismatch。
|
|
919
|
+
effectiveAutoRowForCell ? "items-start" : "items-center",
|
|
920
|
+
align === "right" && "justify-end"
|
|
921
|
+
), children: renderCellContent(cell) })
|
|
922
|
+
] }),
|
|
923
|
+
/* @__PURE__ */ jsx("span", { id: cellErrorId, className: "text-body text-error break-words", role: "alert", children: cellErrorMessages.length === 1 ? cellErrorMessages[0] : /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside flex flex-col gap-1", children: cellErrorMessages.map((m, i) => /* @__PURE__ */ jsx("li", { children: m }, i)) }) })
|
|
924
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
925
|
+
showNestedPrefix && /* @__PURE__ */ jsx(
|
|
926
|
+
"span",
|
|
927
|
+
{
|
|
928
|
+
className: "flex items-center shrink-0",
|
|
929
|
+
style: { paddingLeft: depth > 0 ? `calc(${depth} * var(--tree-indent-${size}, var(--tree-indent-md)))` : 0 },
|
|
930
|
+
children: canExpand ? /* @__PURE__ */ jsx(
|
|
931
|
+
"button",
|
|
932
|
+
{
|
|
933
|
+
type: "button",
|
|
934
|
+
"aria-label": isExpanded ? "收合" : "展開",
|
|
935
|
+
"aria-expanded": isExpanded,
|
|
936
|
+
className: "inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-foreground rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-transform",
|
|
937
|
+
style: { transform: isExpanded ? "rotate(90deg)" : void 0 },
|
|
938
|
+
onClick: (e) => {
|
|
939
|
+
e.stopPropagation();
|
|
940
|
+
toggleExpand == null ? void 0 : toggleExpand();
|
|
941
|
+
},
|
|
942
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, "aria-hidden": true, style: { transform: "rotate(-90deg)" } })
|
|
943
|
+
}
|
|
944
|
+
) : /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "shrink-0 w-4 h-4 mr-2" })
|
|
945
|
+
}
|
|
946
|
+
),
|
|
947
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
948
|
+
"flex-1 min-w-0 self-stretch flex",
|
|
949
|
+
// 2026-05-12 fix root invariant(M32 b):用 `effectiveAutoRowForCell` 而非 global
|
|
950
|
+
// `autoRowHeight` — per-row error 時 row 是 auto-height,該 row 內所有 cell 都該
|
|
951
|
+
// top-align(非僅 error cell)。前 v1 用 global autoRowHeight → 非 error cells in
|
|
952
|
+
// error row 走 items-center → 視覺垂直置中於 tall row(user 抓 image 3 bug)。
|
|
953
|
+
effectiveAutoRowForCell ? "items-start" : "items-center",
|
|
954
|
+
align === "right" && "justify-end"
|
|
955
|
+
), children: renderCellContent(cell) })
|
|
956
|
+
] })
|
|
957
|
+
},
|
|
958
|
+
cell.id
|
|
959
|
+
);
|
|
960
|
+
};
|
|
961
|
+
const visibleRowIdsKey = React.useMemo(() => rows.map((r) => r.id).join(","), [rows]);
|
|
962
|
+
const visibleRowIdsSet = React.useMemo(() => new Set(rows.map((r) => r.id)), [visibleRowIdsKey]);
|
|
963
|
+
React.useEffect(() => {
|
|
964
|
+
if (!enabled || preserveSelectionOnFilter) return;
|
|
965
|
+
setSelection((prev) => {
|
|
966
|
+
const filtered = prev.filter((id) => visibleRowIdsSet.has(id));
|
|
967
|
+
return filtered.length === prev.length ? prev : filtered;
|
|
968
|
+
});
|
|
969
|
+
}, [visibleRowIdsKey, enabled, preserveSelectionOnFilter, visibleRowIdsSet, setSelection]);
|
|
970
|
+
const selectableVisibleIds = React.useMemo(() => {
|
|
971
|
+
if (!enabled) return [];
|
|
972
|
+
return rows.filter((r) => !isRowSelectable || isRowSelectable(r.original)).map((r) => r.id);
|
|
973
|
+
}, [rows, enabled, isRowSelectable]);
|
|
974
|
+
const selectionSet = React.useMemo(() => new Set(selection), [selection]);
|
|
975
|
+
const visibleSelectedCount = selectableVisibleIds.filter((id) => selectionSet.has(id)).length;
|
|
976
|
+
const headerCheckedState = selectableVisibleIds.length === 0 ? false : visibleSelectedCount === 0 ? false : visibleSelectedCount === selectableVisibleIds.length ? true : "indeterminate";
|
|
977
|
+
const visibleIdToRow = React.useMemo(
|
|
978
|
+
() => new Map(rows.map((r) => [r.id, r])),
|
|
979
|
+
[rows]
|
|
980
|
+
);
|
|
981
|
+
const toggleHeaderCheckbox = React.useCallback(() => {
|
|
982
|
+
if (headerCheckedState === true) {
|
|
983
|
+
const visibleSet = new Set(selectableVisibleIds);
|
|
984
|
+
setSelection((prev) => prev.filter((id) => !visibleSet.has(id)));
|
|
985
|
+
} else {
|
|
986
|
+
setSelection((prev) => Array.from(/* @__PURE__ */ new Set([...prev, ...selectableVisibleIds])));
|
|
987
|
+
}
|
|
988
|
+
}, [headerCheckedState, selectableVisibleIds, setSelection]);
|
|
989
|
+
const toggleRow = React.useCallback((rowId, rowOriginal, opts) => {
|
|
990
|
+
if (isRowSelectable && !isRowSelectable(rowOriginal)) return;
|
|
991
|
+
if (mode === "single") {
|
|
992
|
+
setSelection(selectionSet.has(rowId) ? [] : [rowId]);
|
|
993
|
+
anchorRowIdRef.current = rowId;
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
const anchor = anchorRowIdRef.current;
|
|
997
|
+
if ((opts == null ? void 0 : opts.shiftKey) && anchor && anchor !== rowId) {
|
|
998
|
+
const visibleIds = rows.map((r) => r.id);
|
|
999
|
+
const a = visibleIds.indexOf(anchor);
|
|
1000
|
+
const b = visibleIds.indexOf(rowId);
|
|
1001
|
+
if (a !== -1 && b !== -1) {
|
|
1002
|
+
const [from, to] = a < b ? [a, b] : [b, a];
|
|
1003
|
+
const rangeIds = visibleIds.slice(from, to + 1).filter((id) => {
|
|
1004
|
+
const row = visibleIdToRow.get(id);
|
|
1005
|
+
return row && (!isRowSelectable || isRowSelectable(row.original));
|
|
1006
|
+
});
|
|
1007
|
+
const willCheck = !selectionSet.has(rowId);
|
|
1008
|
+
setSelection((prev) => {
|
|
1009
|
+
const set = new Set(prev);
|
|
1010
|
+
rangeIds.forEach((id) => willCheck ? set.add(id) : set.delete(id));
|
|
1011
|
+
return Array.from(set);
|
|
1012
|
+
});
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
setSelection((prev) => {
|
|
1017
|
+
const set = new Set(prev);
|
|
1018
|
+
if (set.has(rowId)) set.delete(rowId);
|
|
1019
|
+
else set.add(rowId);
|
|
1020
|
+
return Array.from(set);
|
|
1021
|
+
});
|
|
1022
|
+
anchorRowIdRef.current = rowId;
|
|
1023
|
+
}, [isRowSelectable, mode, selectionSet, rows, visibleIdToRow, setSelection]);
|
|
1024
|
+
const tableKeyboardHandler = React.useCallback(
|
|
1025
|
+
(e) => {
|
|
1026
|
+
var _a2;
|
|
1027
|
+
if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;
|
|
1028
|
+
if (spreadsheetMode && selectedCellId != null && editingCellId == null) {
|
|
1029
|
+
const navKeys = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Enter", "F2", "Escape"];
|
|
1030
|
+
if (!navKeys.includes(e.key)) return;
|
|
1031
|
+
const lastColon = selectedCellId.lastIndexOf(":");
|
|
1032
|
+
const curRowId = selectedCellId.slice(0, lastColon);
|
|
1033
|
+
const curColId = selectedCellId.slice(lastColon + 1);
|
|
1034
|
+
const allRows = table.getRowModel().rows.map((r) => r.id);
|
|
1035
|
+
const allCols = table.getVisibleLeafColumns().map((c) => c.id).filter((id) => id !== SELECT_COL_ID);
|
|
1036
|
+
const curRowIdx = allRows.indexOf(curRowId);
|
|
1037
|
+
const curColIdx = allCols.indexOf(curColId);
|
|
1038
|
+
if (curRowIdx < 0 || curColIdx < 0) return;
|
|
1039
|
+
let nextRowIdx = curRowIdx;
|
|
1040
|
+
let nextColIdx = curColIdx;
|
|
1041
|
+
if (e.key === "ArrowUp" && curRowIdx > 0) {
|
|
1042
|
+
nextRowIdx = curRowIdx - 1;
|
|
1043
|
+
} else if (e.key === "ArrowDown" && curRowIdx < allRows.length - 1) {
|
|
1044
|
+
nextRowIdx = curRowIdx + 1;
|
|
1045
|
+
} else if (e.key === "ArrowLeft" && curColIdx > 0) {
|
|
1046
|
+
nextColIdx = curColIdx - 1;
|
|
1047
|
+
} else if (e.key === "ArrowRight" && curColIdx < allCols.length - 1) {
|
|
1048
|
+
nextColIdx = curColIdx + 1;
|
|
1049
|
+
} else if (e.key === "Enter" || e.key === "F2") {
|
|
1050
|
+
const row = table.getRowModel().rowsById[curRowId];
|
|
1051
|
+
const colDef = table.getAllLeafColumns().find((c) => c.id === curColId);
|
|
1052
|
+
const meta = (_a2 = colDef == null ? void 0 : colDef.columnDef) == null ? void 0 : _a2.meta;
|
|
1053
|
+
if ((meta == null ? void 0 : meta.type) && meta.type !== "boolean" && meta.type !== "url" && row && canEditCell(meta, row.original)) {
|
|
1054
|
+
e.preventDefault();
|
|
1055
|
+
setEditingCellId(cellEditId(curRowId, curColId));
|
|
1056
|
+
setSelectedCellId(null);
|
|
1057
|
+
setRangeAnchor(null);
|
|
1058
|
+
setRangeFocus(null);
|
|
1059
|
+
}
|
|
1060
|
+
return;
|
|
1061
|
+
} else if (e.key === "Escape") {
|
|
1062
|
+
e.preventDefault();
|
|
1063
|
+
setSelectedCellId(null);
|
|
1064
|
+
setRangeAnchor(null);
|
|
1065
|
+
setRangeFocus(null);
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
if (nextRowIdx !== curRowIdx || nextColIdx !== curColIdx) {
|
|
1069
|
+
e.preventDefault();
|
|
1070
|
+
const nextCellId = `${allRows[nextRowIdx]}:${allCols[nextColIdx]}`;
|
|
1071
|
+
setSelectedCellId(nextCellId);
|
|
1072
|
+
setRangeAnchor(nextCellId);
|
|
1073
|
+
setRangeFocus(null);
|
|
1074
|
+
}
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
if (!enabled) return;
|
|
1078
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "a" && mode === "multi") {
|
|
1079
|
+
e.preventDefault();
|
|
1080
|
+
setSelection((prev) => Array.from(/* @__PURE__ */ new Set([...prev, ...selectableVisibleIds])));
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
if (e.key === "Escape" && selection.length > 0) {
|
|
1084
|
+
e.preventDefault();
|
|
1085
|
+
setSelection([]);
|
|
1086
|
+
anchorRowIdRef.current = null;
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
[
|
|
1091
|
+
enabled,
|
|
1092
|
+
mode,
|
|
1093
|
+
selection.length,
|
|
1094
|
+
selectableVisibleIds,
|
|
1095
|
+
setSelection,
|
|
1096
|
+
spreadsheetMode,
|
|
1097
|
+
selectedCellId,
|
|
1098
|
+
editingCellId,
|
|
1099
|
+
table,
|
|
1100
|
+
isCellEditable
|
|
1101
|
+
]
|
|
1102
|
+
);
|
|
1103
|
+
const headerCellEl = (header, showDivider) => {
|
|
1104
|
+
var _a2;
|
|
1105
|
+
if (enabled && header.column.id === SELECT_COL_ID) {
|
|
1106
|
+
const isHeaderDisabled = selectableVisibleIds.length === 0 || mode !== "multi";
|
|
1107
|
+
return /* @__PURE__ */ jsx(
|
|
1108
|
+
"div",
|
|
1109
|
+
{
|
|
1110
|
+
role: "columnheader",
|
|
1111
|
+
className: cn("flex items-center justify-center shrink-0 select-none", !isHeaderDisabled && "cursor-pointer"),
|
|
1112
|
+
style: { ...columnSizeStyle(header.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(header.column.id) }), ...cellPadding },
|
|
1113
|
+
onClick: isHeaderDisabled ? void 0 : (e) => {
|
|
1114
|
+
e.stopPropagation();
|
|
1115
|
+
toggleHeaderCheckbox();
|
|
1116
|
+
},
|
|
1117
|
+
children: mode === "multi" && /* @__PURE__ */ jsx(
|
|
1118
|
+
Checkbox,
|
|
1119
|
+
{
|
|
1120
|
+
size: size === "lg" ? "lg" : "md",
|
|
1121
|
+
checked: headerCheckedState,
|
|
1122
|
+
onClick: (e) => e.stopPropagation(),
|
|
1123
|
+
onCheckedChange: () => toggleHeaderCheckbox(),
|
|
1124
|
+
"aria-label": "Select all visible rows",
|
|
1125
|
+
disabled: selectableVisibleIds.length === 0
|
|
1126
|
+
}
|
|
1127
|
+
)
|
|
1128
|
+
},
|
|
1129
|
+
header.id
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
const meta = header.column.columnDef.meta;
|
|
1133
|
+
const colType = meta == null ? void 0 : meta.type;
|
|
1134
|
+
const align = (meta == null ? void 0 : meta.align) ?? (colType ? columnTypeDefaults[colType].align : void 0);
|
|
1135
|
+
const canSort = header.column.getCanSort();
|
|
1136
|
+
const sortDir = header.column.getIsSorted();
|
|
1137
|
+
const isMultiSort = (((_a2 = table.getState().sorting) == null ? void 0 : _a2.length) ?? 0) > 1;
|
|
1138
|
+
const SortIcon = sortDir === "asc" ? ArrowUp : ArrowDown;
|
|
1139
|
+
const sortHandler = canSort ? header.column.getToggleSortingHandler() : void 0;
|
|
1140
|
+
return /* @__PURE__ */ jsxs(
|
|
1141
|
+
"div",
|
|
1142
|
+
{
|
|
1143
|
+
role: "columnheader",
|
|
1144
|
+
"aria-sort": sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : "none",
|
|
1145
|
+
className: cn(
|
|
1146
|
+
// **Inline action canonical**(2026-05-05 v2):header 用 `flex items-center gap-2`
|
|
1147
|
+
// (= 8px,inline-action.spec.md SSOT),more action 為 inline shrink-0 sibling 而非
|
|
1148
|
+
// absolute → hover 顯時佔位 → label 自動讓出空間給 sort + more,**不再重疊**(對齊
|
|
1149
|
+
// user 圖示質疑 + Notion / Airtable header layout 共識)。
|
|
1150
|
+
// cell padding 12px 由外層 cellPadding style 提供 → more 距 cell 右邊 = 12px。
|
|
1151
|
+
"group relative flex items-center gap-2 text-fg-secondary text-body font-normal shrink-0 overflow-hidden select-none",
|
|
1152
|
+
align === "right" && "justify-end",
|
|
1153
|
+
align === "center" && "justify-center"
|
|
1154
|
+
),
|
|
1155
|
+
style: { ...columnSizeStyle(header.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(header.column.id) }), ...cellPadding },
|
|
1156
|
+
children: [
|
|
1157
|
+
/* @__PURE__ */ jsxs(
|
|
1158
|
+
"div",
|
|
1159
|
+
{
|
|
1160
|
+
role: canSort ? "button" : void 0,
|
|
1161
|
+
tabIndex: canSort ? 0 : void 0,
|
|
1162
|
+
onClick: sortHandler,
|
|
1163
|
+
onKeyDown: canSort ? (e) => {
|
|
1164
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1165
|
+
e.preventDefault();
|
|
1166
|
+
sortHandler == null ? void 0 : sortHandler(e);
|
|
1167
|
+
}
|
|
1168
|
+
} : void 0,
|
|
1169
|
+
className: cn(
|
|
1170
|
+
"flex items-center min-w-0 flex-1 gap-1 outline-none",
|
|
1171
|
+
canSort && "cursor-pointer hover:text-foreground transition-colors",
|
|
1172
|
+
canSort && "focus-visible:ring-2 focus-visible:ring-ring rounded-sm"
|
|
1173
|
+
),
|
|
1174
|
+
children: [
|
|
1175
|
+
/* @__PURE__ */ jsx(TruncateCell, { className: cn("min-w-0", align === "right" && "text-right", align === "center" && "text-center"), children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }),
|
|
1176
|
+
canSort && sortDir && !isMultiSort && // 2026-05-18 改 per user 拍板「DataTable sort 跟 row size 變」+「做完」approval:
|
|
1177
|
+
// 原固定 14 違反 uiSize.spec.md Icon Tier(sm/md→16, lg→20)。改 ICON_SIZE[size]
|
|
1178
|
+
// 隨 DataTable size prop 變。
|
|
1179
|
+
/* @__PURE__ */ jsx(SortIcon, { size: ICON_SIZE[size], "aria-hidden": true, className: "shrink-0 text-fg-secondary" })
|
|
1180
|
+
]
|
|
1181
|
+
}
|
|
1182
|
+
),
|
|
1183
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0 hidden group-hover:inline-flex group-focus-within:inline-flex has-[[data-state=open]]:inline-flex", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
1184
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1185
|
+
ItemInlineActionButton,
|
|
1186
|
+
{
|
|
1187
|
+
icon: ChevronDown,
|
|
1188
|
+
size: "md",
|
|
1189
|
+
"aria-label": `${typeof header.column.columnDef.header === "string" ? header.column.columnDef.header : header.column.id} 欄位選單`,
|
|
1190
|
+
overlayTrigger: true
|
|
1191
|
+
}
|
|
1192
|
+
) }),
|
|
1193
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
|
|
1194
|
+
canSort && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1195
|
+
/* @__PURE__ */ jsx(DropdownMenuItem, { startIcon: ArrowUp, onClick: () => header.column.toggleSorting(false, false), children: "升冪排序" }),
|
|
1196
|
+
/* @__PURE__ */ jsx(DropdownMenuItem, { startIcon: ArrowDown, onClick: () => header.column.toggleSorting(true, false), children: "降冪排序" }),
|
|
1197
|
+
sortDir && !isMultiSort && /* @__PURE__ */ jsx(DropdownMenuItem, { startIcon: X, onClick: () => header.column.clearSorting(), children: "取消排序" }),
|
|
1198
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {})
|
|
1199
|
+
] }),
|
|
1200
|
+
onColumnFilterTrigger && /* @__PURE__ */ jsx(DropdownMenuItem, { startIcon: Filter, onClick: () => onColumnFilterTrigger(header.column.id), children: "依此欄篩選…" }),
|
|
1201
|
+
header.column.getCanHide() && /* @__PURE__ */ jsx(DropdownMenuItem, { startIcon: EyeOff, onClick: () => header.column.toggleVisibility(false), children: "隱藏欄位" }),
|
|
1202
|
+
enableColumnResize && !isSystemColumn(header.column.id) && /* @__PURE__ */ jsx(
|
|
1203
|
+
DropdownMenuItem,
|
|
1204
|
+
{
|
|
1205
|
+
startIcon: ArrowUpDown,
|
|
1206
|
+
onClick: () => {
|
|
1207
|
+
var _a3, _b2;
|
|
1208
|
+
const cells = document.querySelectorAll(
|
|
1209
|
+
`[role="cell"][data-column-id="${header.column.id}"]`
|
|
1210
|
+
);
|
|
1211
|
+
let max = MIN_COLUMN_WIDTH;
|
|
1212
|
+
cells.forEach((c) => {
|
|
1213
|
+
const inner = c.firstElementChild;
|
|
1214
|
+
const w = ((inner == null ? void 0 : inner.scrollWidth) ?? c.scrollWidth) + 32;
|
|
1215
|
+
if (w > max) max = w;
|
|
1216
|
+
});
|
|
1217
|
+
(_b2 = (_a3 = header.column).resetSize) == null ? void 0 : _b2.call(_a3);
|
|
1218
|
+
table.setColumnSizing((prev) => ({ ...prev, [header.column.id]: max }));
|
|
1219
|
+
onColumnResize == null ? void 0 : onColumnResize(header.column.id, max);
|
|
1220
|
+
},
|
|
1221
|
+
children: "自動調整寬度"
|
|
1222
|
+
}
|
|
1223
|
+
)
|
|
1224
|
+
] })
|
|
1225
|
+
] }) }),
|
|
1226
|
+
(() => {
|
|
1227
|
+
var _a3, _b2;
|
|
1228
|
+
const colId = header.column.id;
|
|
1229
|
+
const colMeta = header.column.columnDef.meta;
|
|
1230
|
+
const colOptIn = (colMeta == null ? void 0 : colMeta.resizable) !== false;
|
|
1231
|
+
const isResizable = enableColumnResize && !isSystemColumn(colId) && colOptIn;
|
|
1232
|
+
const isResizing = (_b2 = (_a3 = header.column).getIsResizing) == null ? void 0 : _b2.call(_a3);
|
|
1233
|
+
if (!showDivider && !isResizable) return null;
|
|
1234
|
+
return /* @__PURE__ */ jsx(
|
|
1235
|
+
"span",
|
|
1236
|
+
{
|
|
1237
|
+
role: isResizable ? "separator" : void 0,
|
|
1238
|
+
"aria-orientation": isResizable ? "vertical" : void 0,
|
|
1239
|
+
"aria-label": isResizable ? "拖曳調整欄寬" : void 0,
|
|
1240
|
+
className: cn(
|
|
1241
|
+
"group/resize absolute top-0 bottom-0 right-0 -mr-[3px] w-[7px]",
|
|
1242
|
+
isResizable && "cursor-col-resize select-none"
|
|
1243
|
+
),
|
|
1244
|
+
onPointerDownCapture: isResizable ? (e) => {
|
|
1245
|
+
var _a4;
|
|
1246
|
+
e.stopPropagation();
|
|
1247
|
+
(_a4 = header.getResizeHandler) == null ? void 0 : _a4.call(header)(e.nativeEvent);
|
|
1248
|
+
} : void 0,
|
|
1249
|
+
onTouchStart: isResizable ? (e) => {
|
|
1250
|
+
var _a4;
|
|
1251
|
+
e.stopPropagation();
|
|
1252
|
+
(_a4 = header.getResizeHandler) == null ? void 0 : _a4.call(header)(e.nativeEvent);
|
|
1253
|
+
} : void 0,
|
|
1254
|
+
children: showDivider && /* @__PURE__ */ jsx(
|
|
1255
|
+
"span",
|
|
1256
|
+
{
|
|
1257
|
+
"aria-hidden": true,
|
|
1258
|
+
className: cn(
|
|
1259
|
+
"absolute right-[3px] w-px transition-colors",
|
|
1260
|
+
isResizing ? "bg-primary" : isResizable ? "bg-divider group-hover/resize:bg-[var(--border-hover)]" : "bg-divider"
|
|
1261
|
+
),
|
|
1262
|
+
style: { top: "var(--table-cell-py)", bottom: "var(--table-cell-py)" }
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
})()
|
|
1268
|
+
]
|
|
1269
|
+
},
|
|
1270
|
+
header.id
|
|
1271
|
+
);
|
|
1272
|
+
};
|
|
1273
|
+
const leftIds = React.useMemo(() => new Set(leftCols.map((c) => c.id)), [leftCols]);
|
|
1274
|
+
const centerIds = React.useMemo(() => new Set(centerCols.map((c) => c.id)), [centerCols]);
|
|
1275
|
+
const rightIds = React.useMemo(() => new Set(rightCols.map((c) => c.id)), [rightCols]);
|
|
1276
|
+
const colsToIds = (cols) => cols === leftCols ? leftIds : cols === rightCols ? rightIds : centerIds;
|
|
1277
|
+
const getRegionHeaders = (cols) => {
|
|
1278
|
+
var _a2;
|
|
1279
|
+
const ids = colsToIds(cols);
|
|
1280
|
+
return ((_a2 = table.getHeaderGroups()[0]) == null ? void 0 : _a2.headers.filter((h) => ids.has(h.id))) ?? [];
|
|
1281
|
+
};
|
|
1282
|
+
const getRegionCells = (row, cols) => {
|
|
1283
|
+
const ids = colsToIds(cols);
|
|
1284
|
+
return row.getVisibleCells().filter((c) => ids.has(c.column.id));
|
|
1285
|
+
};
|
|
1286
|
+
const [dropIndicator, setDropIndicator] = React.useState(null);
|
|
1287
|
+
const reorderableColumnIdsRef = React.useRef([]);
|
|
1288
|
+
const renderHeaderRow = (cols, isRight) => {
|
|
1289
|
+
const headers = getRegionHeaders(cols);
|
|
1290
|
+
const hasVisibleChildren = headers.length > 0;
|
|
1291
|
+
const RowTag = hasVisibleChildren ? "div" : "div";
|
|
1292
|
+
const rowRole = hasVisibleChildren ? "row" : void 0;
|
|
1293
|
+
return /* @__PURE__ */ jsxs(RowTag, { role: rowRole, className: cn("flex items-center border-b border-divider", rowHeight, HEADER_BG), children: [
|
|
1294
|
+
headers.map((h, i) => {
|
|
1295
|
+
const showDivider = i < headers.length - 1 && !(isRight && i === headers.length - 1);
|
|
1296
|
+
const colId = h.column.id;
|
|
1297
|
+
const meta = h.column.columnDef.meta;
|
|
1298
|
+
const isLocked = (meta == null ? void 0 : meta.locked) === true;
|
|
1299
|
+
const isSystem = isSystemColumn(colId);
|
|
1300
|
+
const isDraggable = enableColumnReorder && !isLocked && !isSystem;
|
|
1301
|
+
const indicatorSide = (dropIndicator == null ? void 0 : dropIndicator.type) === "column" && dropIndicator.id === colId ? dropIndicator.side : null;
|
|
1302
|
+
return /* @__PURE__ */ jsx(
|
|
1303
|
+
DraggableHeaderCell,
|
|
1304
|
+
{
|
|
1305
|
+
id: colId,
|
|
1306
|
+
disabled: !isDraggable,
|
|
1307
|
+
isLocked,
|
|
1308
|
+
dropIndicatorSide: indicatorSide,
|
|
1309
|
+
children: headerCellEl(h, showDivider)
|
|
1310
|
+
},
|
|
1311
|
+
h.id
|
|
1312
|
+
);
|
|
1313
|
+
}),
|
|
1314
|
+
isRight && hasRowActions && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end shrink-0 gap-2 invisible", "aria-hidden": "true", style: cellPadding, children: rows[0] && rowActions(rows[0].original) })
|
|
1315
|
+
] });
|
|
1316
|
+
};
|
|
1317
|
+
const renderBodyRows = (cols, isCenter, isRight, regionWidth) => {
|
|
1318
|
+
if (isEmpty && isCenter) {
|
|
1319
|
+
if (emptyState && typeof emptyState !== "string") return /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center py-12", children: emptyState });
|
|
1320
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(Empty, { description: typeof emptyState === "string" ? emptyState : "沒有資料" }) });
|
|
1321
|
+
}
|
|
1322
|
+
if (isEmpty) return null;
|
|
1323
|
+
const isPrimaryRegion = isCenter;
|
|
1324
|
+
const regionRole = isPrimaryRegion ? "primary" : "mirror";
|
|
1325
|
+
const rowEl = (row, idx, opts) => {
|
|
1326
|
+
const showBorder = bordered !== false ? !(opts == null ? void 0 : opts.isLast) : true;
|
|
1327
|
+
const isThisRowDragging = enableRowDrag && activeDragId === row.id;
|
|
1328
|
+
const useSortableWrap = enableRowDrag;
|
|
1329
|
+
const rowHasError = !!cellErrors && row.getVisibleCells().some((c) => {
|
|
1330
|
+
const key = `${row.id}:${c.column.id}`;
|
|
1331
|
+
const v = cellErrors[key];
|
|
1332
|
+
return v != null && (Array.isArray(v) ? v.length > 0 : true);
|
|
1333
|
+
});
|
|
1334
|
+
const effectiveAutoRow = autoRowHeight || rowHasError;
|
|
1335
|
+
const showDragHandle = enableRowDrag && (row.depth ?? 0) === 0 && isPrimaryRegion;
|
|
1336
|
+
const anyDragActive = activeDragId != null;
|
|
1337
|
+
const baseRowDiv = (extra) => /* @__PURE__ */ jsxs(
|
|
1338
|
+
"div",
|
|
1339
|
+
{
|
|
1340
|
+
ref: (el) => {
|
|
1341
|
+
var _a2;
|
|
1342
|
+
if (isCenter && (opts == null ? void 0 : opts.virtual) && el && !isThisRowDragging && activeDragId == null) {
|
|
1343
|
+
virtualizer.measureElement(el);
|
|
1344
|
+
}
|
|
1345
|
+
(_a2 = extra == null ? void 0 : extra.ref) == null ? void 0 : _a2.call(extra, el);
|
|
1346
|
+
},
|
|
1347
|
+
"data-index": isCenter && (opts == null ? void 0 : opts.virtual) ? idx : void 0,
|
|
1348
|
+
"data-row-index": idx,
|
|
1349
|
+
"data-sortable-row-id": enableRowDrag ? row.id : void 0,
|
|
1350
|
+
"data-row-drag-source": enableRowDrag && isPrimaryRegion ? "true" : void 0,
|
|
1351
|
+
role: "row",
|
|
1352
|
+
"aria-rowindex": idx + 2,
|
|
1353
|
+
className: cn(
|
|
1354
|
+
"group/row flex relative",
|
|
1355
|
+
// H1 fix(2026-05-10):effectiveAutoRow 覆 global autoRowHeight,per-row 若有 cell error
|
|
1356
|
+
// 自動 auto-height(撐 message)。Error 清 → 回 fixed。Other rows 不受影響。
|
|
1357
|
+
effectiveAutoRow ? "items-start" : "items-center",
|
|
1358
|
+
!effectiveAutoRow && rowHeight,
|
|
1359
|
+
!effectiveAutoRow && "overflow-hidden",
|
|
1360
|
+
(opts == null ? void 0 : opts.virtual) && "absolute w-full",
|
|
1361
|
+
showBorder && "border-b border-divider",
|
|
1362
|
+
// v15.3 hover bg canonical:hover class 永遠生效,但 onMouseOver delegate
|
|
1363
|
+
// 在 drag 期間只允許 source row 寫 data-hovered → 其他 row 自然不顯 bg。
|
|
1364
|
+
// (對齊 Linear / Jira:source 維持 active 視覺,其他 row 完全靜止)
|
|
1365
|
+
"transition-colors data-[hovered]:bg-neutral-hover",
|
|
1366
|
+
(extra == null ? void 0 : extra.isDragging) && "bg-neutral-hover"
|
|
1367
|
+
// **v15.3.1**:不變 cursor(對齊 Material / Carbon / Polaris / Notion canonical)。
|
|
1368
|
+
// 整列可拖的 affordance 由可見的 RowDragHandle Button 提供,不靠 cursor 暗示。
|
|
1369
|
+
// 之前 cursor-grab → drag 中 user 看到 cursor 變化反而干擾 indicator+ghost 的視覺焦點。
|
|
1370
|
+
),
|
|
1371
|
+
style: {
|
|
1372
|
+
...(opts == null ? void 0 : opts.virtual) ? { transform: `translateY(${opts.start}px)` } : {},
|
|
1373
|
+
...(extra == null ? void 0 : extra.style) ?? {}
|
|
1374
|
+
},
|
|
1375
|
+
...hoverProps(),
|
|
1376
|
+
...(extra == null ? void 0 : extra.attributes) ?? {},
|
|
1377
|
+
...(extra == null ? void 0 : extra.listeners) ?? {},
|
|
1378
|
+
children: [
|
|
1379
|
+
showDragHandle && /* @__PURE__ */ jsx(RowDragHandle, { disabled: dragDisabled, anyDragActive }),
|
|
1380
|
+
(dropIndicator == null ? void 0 : dropIndicator.type) === "row" && dropIndicator.id === row.id && dropIndicator.side === "before" && /* @__PURE__ */ jsx("div", { className: dropIndicatorRow.before, "aria-hidden": true }),
|
|
1381
|
+
getRegionCells(row, cols).map((cell, ci, arr) => cellEl(cell, ci === arr.length - 1 && !(isRight && hasRowActions))),
|
|
1382
|
+
isRight && hasRowActions && /* @__PURE__ */ jsx("div", { role: "cell", className: "flex items-center justify-end shrink-0 gap-2 flex-1", style: cellPadding, children: rowActions(row.original) }),
|
|
1383
|
+
(dropIndicator == null ? void 0 : dropIndicator.type) === "row" && dropIndicator.id === row.id && dropIndicator.side === "after" && /* @__PURE__ */ jsx("div", { className: dropIndicatorRow.after, "aria-hidden": true })
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
row.id
|
|
1387
|
+
);
|
|
1388
|
+
if (useSortableWrap) {
|
|
1389
|
+
const rowInvalidDrop = isThisRowDragging && invalidDropActive;
|
|
1390
|
+
return /* @__PURE__ */ jsx(SortableRowProvider, { id: row.id, disabled: dragDisabled, role: regionRole, invalidDrop: rowInvalidDrop, children: (ctx) => baseRowDiv({
|
|
1391
|
+
// mirror 也掛 setNodeRef — dnd-kit 內部以 hook instance 為單元,
|
|
1392
|
+
// 多 instance 同 id 時,measurement 走最後 mount 的;不影響 transform 一致性
|
|
1393
|
+
ref: ctx.setNodeRef,
|
|
1394
|
+
style: ctx.style,
|
|
1395
|
+
isDragging: ctx.isDragging,
|
|
1396
|
+
// v15.2 整列可拖:listeners + attributes spread 在 row div 上(只 primary,
|
|
1397
|
+
// mirror region 沒 listeners 避免 a11y 重複 announce / pointer 雙觸發)
|
|
1398
|
+
listeners: ctx.rowListeners,
|
|
1399
|
+
attributes: ctx.rowAttributes
|
|
1400
|
+
}) }, row.id);
|
|
1401
|
+
}
|
|
1402
|
+
return baseRowDiv();
|
|
1403
|
+
};
|
|
1404
|
+
const colsWidth = cols.reduce((a, c) => a + c.getSize(), 0);
|
|
1405
|
+
const containerWidth = regionWidth || colsWidth;
|
|
1406
|
+
if (useVirtual) {
|
|
1407
|
+
return /* @__PURE__ */ jsx(TableScrollProvider, { isScrolling: virtualizer.isScrolling, children: /* @__PURE__ */ jsx("div", { style: { height: virtualizer.getTotalSize(), position: "relative", minWidth: containerWidth }, children: virtualizer.getVirtualItems().map((vr) => rowEl(rows[vr.index], vr.index, { virtual: true, start: vr.start, isLast: vr.index === rows.length - 1 })) }) });
|
|
1408
|
+
}
|
|
1409
|
+
return /* @__PURE__ */ jsx("div", { style: { minWidth: containerWidth }, children: rows.map((row, i) => rowEl(row, i, { isLast: i === rows.length - 1 })) });
|
|
1410
|
+
};
|
|
1411
|
+
const tableContent = /* @__PURE__ */ jsxs(
|
|
1412
|
+
"div",
|
|
1413
|
+
{
|
|
1414
|
+
ref: (el) => {
|
|
1415
|
+
tableRef.current = el;
|
|
1416
|
+
if (typeof ref === "function") ref(el);
|
|
1417
|
+
else if (ref) ref.current = el;
|
|
1418
|
+
},
|
|
1419
|
+
"data-table-size": size,
|
|
1420
|
+
"data-data-table-outer": true,
|
|
1421
|
+
"data-active-editor-controller": experimentalActiveEditorController ? "enabled" : void 0,
|
|
1422
|
+
className: cn(dataTableVariants({ bordered }), isFillHeight && "flex flex-col", "outline-none focus:outline-none focus-visible:outline-none", className),
|
|
1423
|
+
style: isFillHeight ? { maxHeight: height } : void 0,
|
|
1424
|
+
role: "table",
|
|
1425
|
+
"aria-rowcount": rows.length + 1,
|
|
1426
|
+
tabIndex: enabled || spreadsheetMode ? 0 : void 0,
|
|
1427
|
+
onKeyDown: enabled || spreadsheetMode ? tableKeyboardHandler : void 0,
|
|
1428
|
+
onMouseOver: enterLeaveHandlers.onMouseOver,
|
|
1429
|
+
onMouseOut: enterLeaveHandlers.onMouseOut,
|
|
1430
|
+
...props,
|
|
1431
|
+
children: [
|
|
1432
|
+
/* @__PURE__ */ jsxs("div", { role: "rowgroup", className: "flex", children: [
|
|
1433
|
+
hasLeft && /* @__PURE__ */ jsx("div", { ref: leftHeaderRef, "data-datatable-header-panel": "left", className: "shrink-0 overflow-hidden dtPanelBoundaryRight", children: renderHeaderRow(leftCols, false) }),
|
|
1434
|
+
/* @__PURE__ */ jsx(
|
|
1435
|
+
"div",
|
|
1436
|
+
{
|
|
1437
|
+
ref: centerHeaderRef,
|
|
1438
|
+
"data-datatable-header-panel": "center",
|
|
1439
|
+
className: "flex-1 min-w-0 overflow-hidden",
|
|
1440
|
+
children: /* @__PURE__ */ jsx("div", { style: { minWidth: centerColsWidth }, children: renderHeaderRow(centerCols, false) })
|
|
1441
|
+
}
|
|
1442
|
+
),
|
|
1443
|
+
hasRight && /* @__PURE__ */ jsx("div", { ref: rightHeaderRef, "data-datatable-header-panel": "right", className: "shrink-0 overflow-hidden dtPanelBoundaryLeft", children: renderHeaderRow(rightCols, true) })
|
|
1444
|
+
] }),
|
|
1445
|
+
/* @__PURE__ */ jsxs("div", { ref: bodyRef, className: cn("flex items-start", isFillHeight && "min-h-0 min-w-0"), children: [
|
|
1446
|
+
hasLeft && /* @__PURE__ */ jsx(
|
|
1447
|
+
"div",
|
|
1448
|
+
{
|
|
1449
|
+
ref: leftBodyRef,
|
|
1450
|
+
"data-datatable-panel": "left",
|
|
1451
|
+
className: "shrink-0 overflow-hidden dtPanelBoundaryRight",
|
|
1452
|
+
style: {
|
|
1453
|
+
width: leftWidth || void 0,
|
|
1454
|
+
// isFillHeight 用 JS 算的 px;固定 px(300px 等)直接套
|
|
1455
|
+
...isFillHeight && bodyMaxHeight != null ? { maxHeight: bodyMaxHeight } : hasHeightConstraint ? { maxHeight: height } : {}
|
|
1456
|
+
},
|
|
1457
|
+
children: renderBodyRows(leftCols, false, false, leftWidth)
|
|
1458
|
+
}
|
|
1459
|
+
),
|
|
1460
|
+
/* @__PURE__ */ jsx(
|
|
1461
|
+
"div",
|
|
1462
|
+
{
|
|
1463
|
+
ref: centerBodyRef,
|
|
1464
|
+
"data-datatable-hscroll": true,
|
|
1465
|
+
"data-datatable-panel": "center",
|
|
1466
|
+
className: "flex-1 min-w-0 overflow-x-auto overflow-y-auto",
|
|
1467
|
+
style: isFillHeight && bodyMaxHeight != null ? { maxHeight: bodyMaxHeight } : hasHeightConstraint ? { maxHeight: height } : void 0,
|
|
1468
|
+
onScroll: onCenterBodyScroll,
|
|
1469
|
+
children: /* @__PURE__ */ jsx("div", { style: { minWidth: centerColsWidth }, children: renderBodyRows(centerCols, true, false) })
|
|
1470
|
+
}
|
|
1471
|
+
),
|
|
1472
|
+
hasRight && /* @__PURE__ */ jsx(
|
|
1473
|
+
"div",
|
|
1474
|
+
{
|
|
1475
|
+
ref: rightBodyRef,
|
|
1476
|
+
"data-datatable-panel": "right",
|
|
1477
|
+
className: "shrink-0 overflow-hidden dtPanelBoundaryLeft",
|
|
1478
|
+
style: {
|
|
1479
|
+
width: rightWidth || void 0,
|
|
1480
|
+
...isFillHeight && bodyMaxHeight != null ? { maxHeight: bodyMaxHeight } : hasHeightConstraint ? { maxHeight: height } : {}
|
|
1481
|
+
},
|
|
1482
|
+
children: renderBodyRows(rightCols, false, true, rightWidth)
|
|
1483
|
+
}
|
|
1484
|
+
)
|
|
1485
|
+
] }),
|
|
1486
|
+
/* @__PURE__ */ jsx(
|
|
1487
|
+
DataTableInteractionLayer,
|
|
1488
|
+
{
|
|
1489
|
+
enabled: experimentalSpreadsheetOverlay || spreadsheetMode,
|
|
1490
|
+
containerRef: tableRef,
|
|
1491
|
+
activeEditorCellId: editingCellId ? editingCellId.replace("__", ":") : null,
|
|
1492
|
+
activeEditorEnabled: experimentalActiveEditorController,
|
|
1493
|
+
activeEditorRender: experimentalActiveEditorController ? (cellId) => {
|
|
1494
|
+
var _a2;
|
|
1495
|
+
const lastColon = cellId.lastIndexOf(":");
|
|
1496
|
+
if (lastColon < 0) return null;
|
|
1497
|
+
const rowId = cellId.slice(0, lastColon);
|
|
1498
|
+
const colId = cellId.slice(lastColon + 1);
|
|
1499
|
+
const colDef = table.getAllLeafColumns().find((c) => c.id === colId);
|
|
1500
|
+
const meta = (_a2 = colDef == null ? void 0 : colDef.columnDef) == null ? void 0 : _a2.meta;
|
|
1501
|
+
if (!(meta == null ? void 0 : meta.type)) return null;
|
|
1502
|
+
const colType = meta.type;
|
|
1503
|
+
const Cell = resolveCellComponent(colType);
|
|
1504
|
+
const row = table.getRowModel().rowsById[rowId];
|
|
1505
|
+
if (!row) return null;
|
|
1506
|
+
const cellEditable = isCellEditable(meta, row.original);
|
|
1507
|
+
const rowValue = row.original[colId];
|
|
1508
|
+
const value = editingDraft !== void 0 ? editingDraft : rowValue;
|
|
1509
|
+
const handleEditTab = (e) => {
|
|
1510
|
+
var _a3;
|
|
1511
|
+
if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;
|
|
1512
|
+
if (e.key !== "Tab") return;
|
|
1513
|
+
e.preventDefault();
|
|
1514
|
+
e.stopPropagation();
|
|
1515
|
+
const direction = e.shiftKey ? "prev" : "next";
|
|
1516
|
+
const allRows = table.getRowModel().rows.map((r) => r.id);
|
|
1517
|
+
const allCols = table.getVisibleLeafColumns().map((c) => c.id).filter((id) => id !== SELECT_COL_ID);
|
|
1518
|
+
const curRowIdx = allRows.indexOf(rowId);
|
|
1519
|
+
const curColIdx = allCols.indexOf(colId);
|
|
1520
|
+
if (curRowIdx < 0 || curColIdx < 0) return;
|
|
1521
|
+
const NON_EDIT_TYPES = ["boolean", "url"];
|
|
1522
|
+
let nextRowIdx = curRowIdx;
|
|
1523
|
+
let nextColIdx = curColIdx;
|
|
1524
|
+
const totalCells = allRows.length * allCols.length;
|
|
1525
|
+
let safety = 0;
|
|
1526
|
+
while (safety < totalCells) {
|
|
1527
|
+
safety++;
|
|
1528
|
+
if (direction === "next") {
|
|
1529
|
+
nextColIdx++;
|
|
1530
|
+
if (nextColIdx >= allCols.length) {
|
|
1531
|
+
nextColIdx = 0;
|
|
1532
|
+
nextRowIdx++;
|
|
1533
|
+
}
|
|
1534
|
+
if (nextRowIdx >= allRows.length) return;
|
|
1535
|
+
} else {
|
|
1536
|
+
nextColIdx--;
|
|
1537
|
+
if (nextColIdx < 0) {
|
|
1538
|
+
nextColIdx = allCols.length - 1;
|
|
1539
|
+
nextRowIdx--;
|
|
1540
|
+
}
|
|
1541
|
+
if (nextRowIdx < 0) return;
|
|
1542
|
+
}
|
|
1543
|
+
const nextRow = table.getRowModel().rowsById[allRows[nextRowIdx]];
|
|
1544
|
+
const nextColDef = table.getAllLeafColumns().find((c) => c.id === allCols[nextColIdx]);
|
|
1545
|
+
const nextMeta = (_a3 = nextColDef == null ? void 0 : nextColDef.columnDef) == null ? void 0 : _a3.meta;
|
|
1546
|
+
if (!(nextMeta == null ? void 0 : nextMeta.type) || NON_EDIT_TYPES.includes(nextMeta.type)) continue;
|
|
1547
|
+
if (!nextRow || !canEditCell(nextMeta, nextRow.original)) continue;
|
|
1548
|
+
setEditingCellId(cellEditId(allRows[nextRowIdx], allCols[nextColIdx]));
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
return /* @__PURE__ */ jsx("div", { onKeyDownCapture: handleEditTab, style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
1553
|
+
Cell,
|
|
1554
|
+
{
|
|
1555
|
+
value,
|
|
1556
|
+
meta,
|
|
1557
|
+
mode: "edit",
|
|
1558
|
+
size,
|
|
1559
|
+
autoRowHeight: false,
|
|
1560
|
+
isEditable: cellEditable,
|
|
1561
|
+
onCommit: (next) => commitCell(rowId, colId, next),
|
|
1562
|
+
onCommitLive: (next) => onCellCommit == null ? void 0 : onCellCommit(rowId, colId, next),
|
|
1563
|
+
onCancel: exitEdit,
|
|
1564
|
+
onDraft: setEditingDraft
|
|
1565
|
+
}
|
|
1566
|
+
) });
|
|
1567
|
+
} : void 0,
|
|
1568
|
+
selectedCellId: spreadsheetMode ? selectedCellId : null,
|
|
1569
|
+
rangeCellIds,
|
|
1570
|
+
cellClickEntersEdit: (cellId) => {
|
|
1571
|
+
var _a2;
|
|
1572
|
+
const lastColonIdx = cellId.lastIndexOf(":");
|
|
1573
|
+
if (lastColonIdx < 0) return false;
|
|
1574
|
+
const rowId = cellId.slice(0, lastColonIdx);
|
|
1575
|
+
const colId = cellId.slice(lastColonIdx + 1);
|
|
1576
|
+
const colDef = table.getAllLeafColumns().find((c) => c.id === colId);
|
|
1577
|
+
const meta = (_a2 = colDef == null ? void 0 : colDef.columnDef) == null ? void 0 : _a2.meta;
|
|
1578
|
+
if (!meta) return false;
|
|
1579
|
+
const EDITABLE_CLICK_TYPES = ["string", "number", "currency", "date", "time", "select", "multiSelect", "person", "multiPerson", "combobox"];
|
|
1580
|
+
if (!EDITABLE_CLICK_TYPES.includes(meta.type)) return false;
|
|
1581
|
+
const row = table.getRowModel().rowsById[rowId];
|
|
1582
|
+
if (!row) return false;
|
|
1583
|
+
return canEditCell(meta, row.original);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
)
|
|
1587
|
+
]
|
|
1588
|
+
}
|
|
1589
|
+
);
|
|
1590
|
+
const dndSensors = useSensors(
|
|
1591
|
+
useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
|
|
1592
|
+
useSensor(KeyboardSensor)
|
|
1593
|
+
);
|
|
1594
|
+
const sameParentCollisionDetection = React.useCallback((args) => {
|
|
1595
|
+
var _a2, _b2;
|
|
1596
|
+
const activeId = ((_a2 = args.active) == null ? void 0 : _a2.id) != null ? String(args.active.id) : null;
|
|
1597
|
+
if (!activeId) {
|
|
1598
|
+
const pointer2 = pointerWithin(args);
|
|
1599
|
+
return pointer2.length > 0 ? pointer2 : rectIntersection(args);
|
|
1600
|
+
}
|
|
1601
|
+
const activeRect = (_b2 = args.active) == null ? void 0 : _b2.rect.current.initial;
|
|
1602
|
+
const cursor = args.pointerCoordinates;
|
|
1603
|
+
if (cursor && activeRect && cursor.y >= activeRect.top && cursor.y <= activeRect.bottom) {
|
|
1604
|
+
return [];
|
|
1605
|
+
}
|
|
1606
|
+
const activeParent = parentMap.get(activeId);
|
|
1607
|
+
const filtered = args.droppableContainers.filter((c) => {
|
|
1608
|
+
const cid = String(c.id);
|
|
1609
|
+
if (cid === activeId) return false;
|
|
1610
|
+
const cParent = parentMap.get(cid);
|
|
1611
|
+
if (cParent === void 0) return false;
|
|
1612
|
+
return cParent === activeParent;
|
|
1613
|
+
});
|
|
1614
|
+
const filteredArgs = { ...args, droppableContainers: filtered };
|
|
1615
|
+
const pointer = pointerWithin(filteredArgs);
|
|
1616
|
+
if (pointer.length > 0) return pointer;
|
|
1617
|
+
if (cursor) {
|
|
1618
|
+
const tableScope = tableRef.current ?? document;
|
|
1619
|
+
const liveRows = Array.from(tableScope.querySelectorAll('[role="row"][data-sortable-row-id]')).filter((el) => el.dataset.sortableRowId !== activeId).filter((el) => {
|
|
1620
|
+
const cParent = parentMap.get(el.dataset.sortableRowId ?? "");
|
|
1621
|
+
return cParent === activeParent;
|
|
1622
|
+
});
|
|
1623
|
+
for (const el of liveRows) {
|
|
1624
|
+
const r = el.getBoundingClientRect();
|
|
1625
|
+
if (cursor.y >= r.top && cursor.y <= r.bottom && cursor.x >= r.left && cursor.x <= r.right) {
|
|
1626
|
+
const rowId = el.dataset.sortableRowId;
|
|
1627
|
+
const cont = filtered.find((c) => String(c.id) === rowId);
|
|
1628
|
+
if (cont) return [{ id: cont.id, data: { droppableContainer: cont, value: 0 } }];
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return rectIntersection(filteredArgs);
|
|
1633
|
+
}, [parentMap]);
|
|
1634
|
+
const [dragOverlayHtml, setDragOverlayHtml] = React.useState(null);
|
|
1635
|
+
const [dragOverlayWidth, setDragOverlayWidth] = React.useState(null);
|
|
1636
|
+
const [, setActiveDragColId] = React.useState(null);
|
|
1637
|
+
const handleDragStart = React.useCallback((e) => {
|
|
1638
|
+
var _a2, _b2, _c2, _d, _e, _f;
|
|
1639
|
+
const id = String(e.active.id);
|
|
1640
|
+
const type = ((_b2 = (_a2 = e.active.data) == null ? void 0 : _a2.current) == null ? void 0 : _b2.type) ?? "row";
|
|
1641
|
+
setInvalidDropActive(false);
|
|
1642
|
+
if (type === "row") {
|
|
1643
|
+
(_c2 = tableRef.current) == null ? void 0 : _c2.querySelectorAll("[data-hovered]").forEach((el) => {
|
|
1644
|
+
const rowId = el.dataset.sortableRowId;
|
|
1645
|
+
if (rowId !== id) delete el.dataset.hovered;
|
|
1646
|
+
});
|
|
1647
|
+
} else {
|
|
1648
|
+
(_d = tableRef.current) == null ? void 0 : _d.querySelectorAll("[data-hovered]").forEach((el) => delete el.dataset.hovered);
|
|
1649
|
+
}
|
|
1650
|
+
if (type === "column") {
|
|
1651
|
+
const colId = ((_f = (_e = e.active.data) == null ? void 0 : _e.current) == null ? void 0 : _f.columnId) ?? id;
|
|
1652
|
+
setActiveDragColId(colId);
|
|
1653
|
+
const headerEl = document.querySelector(`[role="columnheader"][data-column-id="${colId}"]`);
|
|
1654
|
+
if (headerEl) {
|
|
1655
|
+
const clone = headerEl.cloneNode(true);
|
|
1656
|
+
clone.style.position = "static";
|
|
1657
|
+
clone.style.transform = "none";
|
|
1658
|
+
clone.style.transition = "none";
|
|
1659
|
+
clone.style.opacity = "1";
|
|
1660
|
+
clone.style.zIndex = "";
|
|
1661
|
+
clone.style.width = `${headerEl.offsetWidth}px`;
|
|
1662
|
+
clone.querySelectorAll('[role="separator"][aria-orientation="vertical"]').forEach((n) => n.remove());
|
|
1663
|
+
setDragOverlayHtml(clone.outerHTML);
|
|
1664
|
+
setDragOverlayWidth(headerEl.offsetWidth);
|
|
1665
|
+
}
|
|
1666
|
+
} else {
|
|
1667
|
+
setActiveDragId(id);
|
|
1668
|
+
const ghost = reconstructFullRowGhost(id, tableRef.current);
|
|
1669
|
+
if (ghost) {
|
|
1670
|
+
setDragOverlayHtml(ghost.html);
|
|
1671
|
+
setDragOverlayWidth(ghost.width);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}, []);
|
|
1675
|
+
const handleDragOver = React.useCallback((e) => {
|
|
1676
|
+
var _a2, _b2;
|
|
1677
|
+
const { active, over } = e;
|
|
1678
|
+
if (!active) return;
|
|
1679
|
+
if (!over) {
|
|
1680
|
+
if (!invalidRef.current) setInvalidDropActive(true);
|
|
1681
|
+
setDropIndicator(null);
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (invalidRef.current) setInvalidDropActive(false);
|
|
1685
|
+
if (active.id === over.id) {
|
|
1686
|
+
setDropIndicator(null);
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
const dragType = ((_b2 = (_a2 = active.data) == null ? void 0 : _a2.current) == null ? void 0 : _b2.type) ?? "row";
|
|
1690
|
+
if (dragType === "column") {
|
|
1691
|
+
const activeIdx = reorderableColumnIdsRef.current.indexOf(String(active.id));
|
|
1692
|
+
const overIdx = reorderableColumnIdsRef.current.indexOf(String(over.id));
|
|
1693
|
+
if (activeIdx === -1 || overIdx === -1) {
|
|
1694
|
+
setDropIndicator(null);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
const side = activeIdx < overIdx ? "after" : "before";
|
|
1698
|
+
if (isReorderNoop(activeIdx, overIdx, side)) {
|
|
1699
|
+
setDropIndicator(null);
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
setDropIndicator({ id: String(over.id), side, type: "column" });
|
|
1703
|
+
} else {
|
|
1704
|
+
const activeIdx = allRowIds.indexOf(String(active.id));
|
|
1705
|
+
const overIdx = allRowIds.indexOf(String(over.id));
|
|
1706
|
+
if (activeIdx === -1 || overIdx === -1) {
|
|
1707
|
+
setDropIndicator(null);
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
const side = activeIdx < overIdx ? "after" : "before";
|
|
1711
|
+
if (isReorderNoop(activeIdx, overIdx, side)) {
|
|
1712
|
+
setDropIndicator(null);
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
setDropIndicator({ id: String(over.id), side, type: "row" });
|
|
1716
|
+
}
|
|
1717
|
+
}, [allRowIds, isReorderNoop]);
|
|
1718
|
+
const handleDragCancel = React.useCallback(() => {
|
|
1719
|
+
setActiveDragId(null);
|
|
1720
|
+
setActiveDragColId(null);
|
|
1721
|
+
setInvalidDropActive(false);
|
|
1722
|
+
setDragOverlayHtml(null);
|
|
1723
|
+
setDragOverlayWidth(null);
|
|
1724
|
+
setDropIndicator(null);
|
|
1725
|
+
}, []);
|
|
1726
|
+
const reorderableColumnIds = React.useMemo(() => {
|
|
1727
|
+
return table.getVisibleLeafColumns().map((c) => c.id).filter((id) => id && !isSystemColumn(id)).filter((id) => {
|
|
1728
|
+
var _a2;
|
|
1729
|
+
const meta = (_a2 = table.getColumn(id)) == null ? void 0 : _a2.columnDef.meta;
|
|
1730
|
+
return !(meta == null ? void 0 : meta.locked);
|
|
1731
|
+
});
|
|
1732
|
+
}, [table, columnsWithSelection, (_c = tableOptions == null ? void 0 : tableOptions.state) == null ? void 0 : _c.columnOrder]);
|
|
1733
|
+
React.useEffect(() => {
|
|
1734
|
+
reorderableColumnIdsRef.current = reorderableColumnIds;
|
|
1735
|
+
}, [reorderableColumnIds]);
|
|
1736
|
+
const handleDragEnd = React.useCallback((e) => {
|
|
1737
|
+
var _a2, _b2;
|
|
1738
|
+
const { active, over } = e;
|
|
1739
|
+
const type = ((_b2 = (_a2 = active.data) == null ? void 0 : _a2.current) == null ? void 0 : _b2.type) ?? "row";
|
|
1740
|
+
setActiveDragId(null);
|
|
1741
|
+
setActiveDragColId(null);
|
|
1742
|
+
setInvalidDropActive(false);
|
|
1743
|
+
setDragOverlayHtml(null);
|
|
1744
|
+
setDragOverlayWidth(null);
|
|
1745
|
+
setDropIndicator(null);
|
|
1746
|
+
if (!over || active.id === over.id) return;
|
|
1747
|
+
const sourceId = String(active.id);
|
|
1748
|
+
const targetId = String(over.id);
|
|
1749
|
+
if (type === "column") {
|
|
1750
|
+
const oldIdx2 = reorderableColumnIds.indexOf(sourceId);
|
|
1751
|
+
const newIdx2 = reorderableColumnIds.indexOf(targetId);
|
|
1752
|
+
if (oldIdx2 === -1 || newIdx2 === -1) return;
|
|
1753
|
+
const position2 = oldIdx2 < newIdx2 ? "after" : "before";
|
|
1754
|
+
if (isReorderNoop(oldIdx2, newIdx2, position2)) return;
|
|
1755
|
+
const activeRect = active.rect.current.translated ?? active.rect.current.initial;
|
|
1756
|
+
const overRect = over.rect;
|
|
1757
|
+
if (activeRect && overRect) {
|
|
1758
|
+
const ghostCenter = activeRect.left + activeRect.width / 2;
|
|
1759
|
+
const targetCenter = overRect.left + overRect.width / 2;
|
|
1760
|
+
if (oldIdx2 < newIdx2 && ghostCenter < targetCenter) return;
|
|
1761
|
+
if (oldIdx2 > newIdx2 && ghostCenter > targetCenter) return;
|
|
1762
|
+
}
|
|
1763
|
+
onColumnReorder == null ? void 0 : onColumnReorder(sourceId, targetId, position2);
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
if (parentMap.get(sourceId) !== parentMap.get(targetId)) return;
|
|
1767
|
+
const parentId = parentMap.get(sourceId);
|
|
1768
|
+
const siblings = allRowIds.filter((id) => parentMap.get(id) === parentId);
|
|
1769
|
+
const oldIdx = siblings.indexOf(sourceId);
|
|
1770
|
+
const newIdx = siblings.indexOf(targetId);
|
|
1771
|
+
if (oldIdx === -1 || newIdx === -1) return;
|
|
1772
|
+
const position = oldIdx < newIdx ? "after" : "before";
|
|
1773
|
+
if (isReorderNoop(oldIdx, newIdx, position)) return;
|
|
1774
|
+
onRowReorder == null ? void 0 : onRowReorder(sourceId, targetId, position);
|
|
1775
|
+
}, [allRowIds, parentMap, onRowReorder, onColumnReorder, reorderableColumnIds, isReorderNoop]);
|
|
1776
|
+
const dndCollisionDetection = React.useCallback((args) => {
|
|
1777
|
+
var _a2, _b2;
|
|
1778
|
+
const activeData = (_b2 = (_a2 = args.active) == null ? void 0 : _a2.data) == null ? void 0 : _b2.current;
|
|
1779
|
+
if ((activeData == null ? void 0 : activeData.type) === "column") {
|
|
1780
|
+
const filtered = args.droppableContainers.filter((c) => {
|
|
1781
|
+
var _a3, _b3;
|
|
1782
|
+
const cData = (_a3 = c.data) == null ? void 0 : _a3.current;
|
|
1783
|
+
return (cData == null ? void 0 : cData.type) === "column" && c.id !== ((_b3 = args.active) == null ? void 0 : _b3.id);
|
|
1784
|
+
});
|
|
1785
|
+
const filteredArgs = { ...args, droppableContainers: filtered };
|
|
1786
|
+
const pointer = pointerWithin(filteredArgs);
|
|
1787
|
+
return pointer.length > 0 ? pointer : rectIntersection(filteredArgs);
|
|
1788
|
+
}
|
|
1789
|
+
return sameParentCollisionDetection(args);
|
|
1790
|
+
}, [sameParentCollisionDetection]);
|
|
1791
|
+
const wrapWithDnd = (node) => {
|
|
1792
|
+
if (!enableRowDrag && !enableColumnReorder) return node;
|
|
1793
|
+
return /* @__PURE__ */ jsxs(
|
|
1794
|
+
DndContext,
|
|
1795
|
+
{
|
|
1796
|
+
sensors: dndSensors,
|
|
1797
|
+
measuring: { droppable: { strategy: MeasuringStrategy.Always } },
|
|
1798
|
+
collisionDetection: dndCollisionDetection,
|
|
1799
|
+
modifiers: [snapToCursorModifier],
|
|
1800
|
+
onDragStart: handleDragStart,
|
|
1801
|
+
onDragOver: handleDragOver,
|
|
1802
|
+
onDragCancel: handleDragCancel,
|
|
1803
|
+
onDragEnd: handleDragEnd,
|
|
1804
|
+
children: [
|
|
1805
|
+
node,
|
|
1806
|
+
/* @__PURE__ */ jsx(DragOverlay, { dropAnimation: null, children: dragOverlayHtml ? /* @__PURE__ */ jsx(
|
|
1807
|
+
"div",
|
|
1808
|
+
{
|
|
1809
|
+
style: { width: dragOverlayWidth ?? void 0 },
|
|
1810
|
+
className: "bg-surface-raised shadow-[var(--elevation-200)] rounded-md border border-border pointer-events-none",
|
|
1811
|
+
dangerouslySetInnerHTML: { __html: dragOverlayHtml }
|
|
1812
|
+
}
|
|
1813
|
+
) : null })
|
|
1814
|
+
]
|
|
1815
|
+
}
|
|
1816
|
+
);
|
|
1817
|
+
};
|
|
1818
|
+
if (enabled && mode === "single") {
|
|
1819
|
+
return /* @__PURE__ */ jsx(
|
|
1820
|
+
RadioGroupPrimitive.Root,
|
|
1821
|
+
{
|
|
1822
|
+
value: selection[0] ?? "",
|
|
1823
|
+
onValueChange: (v) => v && setSelection([v]),
|
|
1824
|
+
children: wrapWithDnd(tableContent)
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
return wrapWithDnd(tableContent);
|
|
1829
|
+
}
|
|
1830
|
+
const DataTable = React.forwardRef(DataTableInner);
|
|
1831
|
+
DataTable.displayName = "DataTable";
|
|
1832
|
+
const dataTableMeta = {
|
|
1833
|
+
component: "DataTable",
|
|
1834
|
+
family: null,
|
|
1835
|
+
// non-family composite / overlay / layout
|
|
1836
|
+
variants: {},
|
|
1837
|
+
sizes: {},
|
|
1838
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
1839
|
+
tokens: {
|
|
1840
|
+
bg: ["bg-muted", "bg-neutral-hover", "bg-surface"],
|
|
1841
|
+
fg: ["text-fg-muted", "text-fg-secondary", "text-foreground"],
|
|
1842
|
+
ring: []
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
export {
|
|
1846
|
+
DataTable,
|
|
1847
|
+
MIN_COLUMN_WIDTH,
|
|
1848
|
+
dataTableMeta,
|
|
1849
|
+
dataTableVariants
|
|
1850
|
+
};
|
|
1851
|
+
//# sourceMappingURL=data-table.js.map
|