@qijenchen/design-system 0.1.0-beta.13 → 0.1.0-beta.131
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/AGENTS.md +8 -0
- package/CLAUDE.md +3 -199
- package/README.md +6 -4
- package/cli-init.mjs +30 -2
- package/dist/components/Accordion/accordion.d.ts +3 -3
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js +6 -3
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Accordion/index.d.ts +2 -0
- package/dist/components/Accordion/index.d.ts.map +1 -0
- package/dist/components/Accordion/index.js +9 -0
- package/dist/components/Accordion/index.js.map +1 -0
- package/dist/components/AccountMenu/account-menu.d.ts +93 -0
- package/dist/components/AccountMenu/account-menu.d.ts.map +1 -0
- package/dist/components/AccountMenu/account-menu.js +73 -0
- package/dist/components/AccountMenu/account-menu.js.map +1 -0
- package/dist/components/AccountMenu/index.d.ts +2 -0
- package/dist/components/AccountMenu/index.d.ts.map +1 -0
- package/dist/components/AccountMenu/index.js +6 -0
- package/dist/components/AccountMenu/index.js.map +1 -0
- package/dist/components/AgentPanel/agent-fab.d.ts +24 -0
- package/dist/components/AgentPanel/agent-fab.d.ts.map +1 -0
- package/dist/components/AgentPanel/agent-logo.d.ts +75 -0
- package/dist/components/AgentPanel/agent-logo.d.ts.map +1 -0
- package/dist/components/AgentPanel/agent-logo.js +371 -0
- package/dist/components/AgentPanel/agent-logo.js.map +1 -0
- package/dist/components/AgentPanel/agent-panel.d.ts +183 -0
- package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -0
- package/dist/components/AgentPanel/agent-panel.js +900 -0
- package/dist/components/AgentPanel/agent-panel.js.map +1 -0
- package/dist/components/AgentPanel/index.d.ts +2 -0
- package/dist/components/AgentPanel/index.d.ts.map +1 -0
- package/dist/components/AgentPanel/index.js +16 -0
- package/dist/components/AgentPanel/index.js.map +1 -0
- package/dist/components/Alert/alert.d.ts +7 -2
- package/dist/components/Alert/alert.d.ts.map +1 -1
- package/dist/components/Alert/alert.js +12 -8
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/Alert/index.d.ts +2 -0
- package/dist/components/Alert/index.d.ts.map +1 -0
- package/dist/components/Alert/index.js +7 -0
- package/dist/components/Alert/index.js.map +1 -0
- package/dist/components/AppShell/_demo-helpers.d.ts +3 -1
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +19 -4
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +48 -11
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/AppShell/index.d.ts +2 -0
- package/dist/components/AppShell/index.d.ts.map +1 -0
- package/dist/components/AppShell/index.js +8 -0
- package/dist/components/AppShell/index.js.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts +3 -2
- package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -1
- package/dist/components/AspectRatio/aspect-ratio.js +4 -2
- package/dist/components/AspectRatio/aspect-ratio.js.map +1 -1
- package/dist/components/AspectRatio/index.d.ts +2 -0
- package/dist/components/AspectRatio/index.d.ts.map +1 -0
- package/dist/components/AspectRatio/index.js +6 -0
- package/dist/components/AspectRatio/index.js.map +1 -0
- package/dist/components/Avatar/avatar.d.ts +14 -7
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +24 -30
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Avatar/index.d.ts.map +1 -0
- package/dist/components/Avatar/index.js +6 -0
- package/dist/components/Avatar/index.js.map +1 -0
- package/dist/components/Badge/badge.d.ts +21 -9
- package/dist/components/Badge/badge.d.ts.map +1 -1
- package/dist/components/Badge/badge.js +9 -6
- package/dist/components/Badge/badge.js.map +1 -1
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Badge/index.d.ts.map +1 -0
- package/dist/components/Badge/index.js +7 -0
- package/dist/components/Badge/index.js.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts +16 -3
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +21 -53
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/Breadcrumb/index.d.ts +2 -0
- package/dist/components/Breadcrumb/index.d.ts.map +1 -0
- package/dist/components/Breadcrumb/index.js +12 -0
- package/dist/components/Breadcrumb/index.js.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +7 -4
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +8 -8
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/BulkActionBar/index.d.ts +2 -0
- package/dist/components/BulkActionBar/index.d.ts.map +1 -0
- package/dist/components/BulkActionBar/index.js +7 -0
- package/dist/components/BulkActionBar/index.js.map +1 -0
- package/dist/components/Button/button-group.d.ts +31 -5
- package/dist/components/Button/button-group.d.ts.map +1 -1
- package/dist/components/Button/button-group.js +31 -14
- package/dist/components/Button/button-group.js.map +1 -1
- package/dist/components/Button/button.d.ts +15 -14
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +94 -52
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Button/index.js +11 -0
- package/dist/components/Button/index.js.map +1 -0
- package/dist/components/Calendar/calendar.d.ts +22 -19
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +180 -135
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Calendar/index.d.ts +2 -0
- package/dist/components/Calendar/index.d.ts.map +1 -0
- package/dist/components/Calendar/index.js +6 -0
- package/dist/components/Calendar/index.js.map +1 -0
- package/dist/components/Carousel/carousel.d.ts +15 -9
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +91 -50
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Carousel/index.d.ts +2 -0
- package/dist/components/Carousel/index.d.ts.map +1 -0
- package/dist/components/Carousel/index.js +11 -0
- package/dist/components/Carousel/index.js.map +1 -0
- package/dist/components/Chart/chart.d.ts +2 -2
- package/dist/components/Chart/chart.d.ts.map +1 -1
- package/dist/components/Chart/chart.js +5 -2
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Chart/index.d.ts +2 -0
- package/dist/components/Chart/index.d.ts.map +1 -0
- package/dist/components/Chart/index.js +11 -0
- package/dist/components/Chart/index.js.map +1 -0
- package/dist/components/Checkbox/checkbox-group.d.ts +2 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js +21 -14
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +20 -11
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +117 -18
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Checkbox/index.d.ts +3 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -0
- package/dist/components/Checkbox/index.js +10 -0
- package/dist/components/Checkbox/index.js.map +1 -0
- package/dist/components/Chip/chip.d.ts +30 -11
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js +83 -33
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Chip/index.d.ts +2 -0
- package/dist/components/Chip/index.d.ts.map +1 -0
- package/dist/components/Chip/index.js +8 -0
- package/dist/components/Chip/index.js.map +1 -0
- package/dist/components/CircularProgress/circular-progress.d.ts +2 -3
- package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -1
- package/dist/components/CircularProgress/circular-progress.js +5 -4
- package/dist/components/CircularProgress/circular-progress.js.map +1 -1
- package/dist/components/CircularProgress/index.d.ts +2 -0
- package/dist/components/CircularProgress/index.d.ts.map +1 -0
- package/dist/components/CircularProgress/index.js +6 -0
- package/dist/components/CircularProgress/index.js.map +1 -0
- package/dist/components/Coachmark/coachmark-story-helpers.d.ts +22 -0
- package/dist/components/Coachmark/coachmark-story-helpers.d.ts.map +1 -0
- package/dist/components/Coachmark/coachmark.d.ts +15 -6
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
- package/dist/components/Coachmark/coachmark.js +12 -4
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Coachmark/index.d.ts +2 -0
- package/dist/components/Coachmark/index.d.ts.map +1 -0
- package/dist/components/Coachmark/index.js +6 -0
- package/dist/components/Coachmark/index.js.map +1 -0
- package/dist/components/Combobox/combobox.d.ts +39 -15
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +169 -65
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Combobox/index.d.ts +2 -0
- package/dist/components/Combobox/index.d.ts.map +1 -0
- package/dist/components/Combobox/index.js +6 -0
- package/dist/components/Combobox/index.js.map +1 -0
- package/dist/components/Command/command.d.ts +7 -3
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +23 -10
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/Command/index.d.ts +2 -0
- package/dist/components/Command/index.d.ts.map +1 -0
- package/dist/components/Command/index.js +14 -0
- package/dist/components/Command/index.js.map +1 -0
- package/dist/components/DataTable/active-editor-controller.d.ts +4 -3
- package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts +5 -5
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +89 -95
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +11 -21
- package/dist/components/DataTable/column-types.d.ts.map +1 -1
- package/dist/components/DataTable/column-types.js.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +4 -3
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +193 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts +51 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.js +159 -0
- package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-labels.d.ts +44 -0
- package/dist/components/DataTable/data-table-filter-labels.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-labels.js +55 -0
- package/dist/components/DataTable/data-table-filter-labels.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts +12 -3
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +316 -0
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts +32 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js +205 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +17 -20
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.d.ts +5 -5
- package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +150 -0
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +66 -15
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +367 -185
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DataTable/filter-operators.d.ts +1 -1
- package/dist/components/DataTable/filter-operators.js +140 -0
- package/dist/components/DataTable/filter-operators.js.map +1 -0
- package/dist/components/DataTable/filter-tree.d.ts +6 -1
- package/dist/components/DataTable/filter-tree.d.ts.map +1 -1
- package/dist/components/DataTable/filter-tree.js +318 -0
- package/dist/components/DataTable/filter-tree.js.map +1 -0
- package/dist/components/DataTable/index.d.ts +5 -0
- package/dist/components/DataTable/index.d.ts.map +1 -0
- package/dist/components/DataTable/index.js +21 -0
- package/dist/components/DataTable/index.js.map +1 -0
- package/dist/components/DataTable/lib/column-meta.js +25 -0
- package/dist/components/DataTable/lib/column-meta.js.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts +23 -19
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +60 -12
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DateGrid/index.d.ts +2 -0
- package/dist/components/DateGrid/index.d.ts.map +1 -0
- package/dist/components/DateGrid/index.js +6 -0
- package/dist/components/DateGrid/index.js.map +1 -0
- package/dist/components/DatePicker/date-picker.d.ts +12 -12
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +418 -309
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/DatePicker/index.d.ts.map +1 -0
- package/dist/components/DatePicker/index.js +8 -0
- package/dist/components/DatePicker/index.js.map +1 -0
- package/dist/components/DescriptionList/description-list.d.ts +6 -6
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
- package/dist/components/DescriptionList/description-list.js +11 -10
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/DescriptionList/index.d.ts +2 -0
- package/dist/components/DescriptionList/index.d.ts.map +1 -0
- package/dist/components/DescriptionList/index.js +7 -0
- package/dist/components/DescriptionList/index.js.map +1 -0
- package/dist/components/Dialog/dialog.d.ts +22 -5
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +44 -23
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/Dialog/index.d.ts +2 -0
- package/dist/components/Dialog/index.d.ts.map +1 -0
- package/dist/components/Dialog/index.js +16 -0
- package/dist/components/Dialog/index.js.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +19 -10
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +79 -28
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/DropdownMenu/index.d.ts +2 -0
- package/dist/components/DropdownMenu/index.d.ts.map +1 -0
- package/dist/components/DropdownMenu/index.js +21 -0
- package/dist/components/DropdownMenu/index.js.map +1 -0
- package/dist/components/Empty/empty.d.ts +14 -6
- package/dist/components/Empty/empty.d.ts.map +1 -1
- package/dist/components/Empty/empty.js +7 -7
- package/dist/components/Empty/empty.js.map +1 -1
- package/dist/components/Empty/index.d.ts +2 -0
- package/dist/components/Empty/index.d.ts.map +1 -0
- package/dist/components/Empty/index.js +6 -0
- package/dist/components/Empty/index.js.map +1 -0
- package/dist/components/Field/field-context.d.ts +111 -4
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +70 -0
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-edit-keys.d.ts +21 -0
- package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
- package/dist/components/Field/field-edit-keys.js +19 -0
- package/dist/components/Field/field-edit-keys.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +22 -3
- package/dist/components/Field/field-types.d.ts.map +1 -1
- package/dist/components/Field/field-types.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +24 -6
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +98 -74
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +7 -4
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +39 -6
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/index.d.ts +3 -0
- package/dist/components/Field/index.d.ts.map +1 -0
- package/dist/components/Field/index.js +14 -0
- package/dist/components/Field/index.js.map +1 -0
- package/dist/components/Field/use-form-validation.d.ts +92 -0
- package/dist/components/Field/use-form-validation.d.ts.map +1 -0
- package/dist/components/Field/use-form-validation.js +137 -0
- package/dist/components/Field/use-form-validation.js.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts +8 -11
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js +2 -2
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FieldControlGroup/index.d.ts +2 -0
- package/dist/components/FieldControlGroup/index.d.ts.map +1 -0
- package/dist/components/FieldControlGroup/index.js +6 -0
- package/dist/components/FieldControlGroup/index.js.map +1 -0
- package/dist/components/FileItem/file-item.d.ts +14 -2
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +45 -16
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileItem/index.d.ts +2 -0
- package/dist/components/FileItem/index.d.ts.map +1 -0
- package/dist/components/FileItem/index.js +6 -0
- package/dist/components/FileItem/index.js.map +1 -0
- package/dist/components/FileUpload/file-upload.d.ts +39 -19
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +102 -32
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileUpload/index.d.ts +2 -0
- package/dist/components/FileUpload/index.d.ts.map +1 -0
- package/dist/components/FileUpload/index.js +6 -0
- package/dist/components/FileUpload/index.js.map +1 -0
- package/dist/components/FileViewer/can-render-image.d.ts +6 -0
- package/dist/components/FileViewer/can-render-image.d.ts.map +1 -0
- package/dist/components/FileViewer/can-render-image.js +11 -0
- package/dist/components/FileViewer/can-render-image.js.map +1 -0
- package/dist/components/FileViewer/file-viewer.d.ts +4 -4
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +88 -50
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/FileViewer/image-renderer.d.ts +0 -5
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
- package/dist/components/FileViewer/image-renderer.js +23 -10
- package/dist/components/FileViewer/image-renderer.js.map +1 -1
- package/dist/components/FileViewer/index.d.ts +2 -0
- package/dist/components/FileViewer/index.d.ts.map +1 -0
- package/dist/components/FileViewer/index.js +7 -0
- package/dist/components/FileViewer/index.js.map +1 -0
- package/dist/components/HoverCard/hover-card.d.ts +9 -5
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +12 -5
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/HoverCard/index.d.ts +2 -0
- package/dist/components/HoverCard/index.d.ts.map +1 -0
- package/dist/components/HoverCard/index.js +8 -0
- package/dist/components/HoverCard/index.js.map +1 -0
- package/dist/components/InlineEdit/index.d.ts +2 -0
- package/dist/components/InlineEdit/index.d.ts.map +1 -0
- package/dist/components/InlineEdit/index.js +6 -0
- package/dist/components/InlineEdit/index.js.map +1 -0
- package/dist/components/InlineEdit/inline-edit.d.ts +86 -0
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
- package/dist/components/InlineEdit/inline-edit.js +254 -0
- package/dist/components/InlineEdit/inline-edit.js.map +1 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/Input/index.d.ts.map +1 -0
- package/dist/components/Input/index.js +6 -0
- package/dist/components/Input/index.js.map +1 -0
- package/dist/components/Input/input.d.ts +31 -10
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +67 -30
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/index.d.ts +2 -0
- package/dist/components/LinkInput/index.d.ts.map +1 -0
- package/dist/components/LinkInput/index.js +6 -0
- package/dist/components/LinkInput/index.js.map +1 -0
- package/dist/components/LinkInput/link-input.d.ts +9 -9
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +40 -37
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Menu/index.d.ts +2 -0
- package/dist/components/Menu/index.d.ts.map +1 -0
- package/dist/components/Menu/index.js +9 -0
- package/dist/components/Menu/index.js.map +1 -0
- package/dist/components/Menu/menu-item.d.ts +20 -4
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js +37 -9
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/Notice/index.d.ts +2 -0
- package/dist/components/Notice/index.d.ts.map +1 -0
- package/dist/components/Notice/index.js +8 -0
- package/dist/components/Notice/index.js.map +1 -0
- package/dist/components/Notice/notice.d.ts +35 -7
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +34 -10
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/index.d.ts +2 -0
- package/dist/components/NumberInput/index.d.ts.map +1 -0
- package/dist/components/NumberInput/index.js +7 -0
- package/dist/components/NumberInput/index.js.map +1 -0
- package/dist/components/NumberInput/number-input.d.ts +5 -5
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +40 -18
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/index.d.ts +2 -0
- package/dist/components/OverflowIndicator/index.d.ts.map +1 -0
- package/dist/components/OverflowIndicator/index.js +6 -0
- package/dist/components/OverflowIndicator/index.js.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +6 -2
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +11 -7
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/index.d.ts +2 -0
- package/dist/components/Pagination/index.d.ts.map +1 -0
- package/dist/components/Pagination/index.js +6 -0
- package/dist/components/Pagination/index.js.map +1 -0
- package/dist/components/Pagination/pagination.d.ts +49 -0
- package/dist/components/Pagination/pagination.d.ts.map +1 -0
- package/dist/components/Pagination/pagination.js +182 -0
- package/dist/components/Pagination/pagination.js.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
- package/dist/components/PeoplePicker/index.d.ts +2 -0
- package/dist/components/PeoplePicker/index.d.ts.map +1 -0
- package/dist/components/PeoplePicker/index.js +15 -0
- package/dist/components/PeoplePicker/index.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker-helpers.js +2 -2
- package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +26 -10
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +97 -65
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +19 -11
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +39 -23
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/Popover/index.d.ts.map +1 -0
- package/dist/components/Popover/index.js +14 -0
- package/dist/components/Popover/index.js.map +1 -0
- package/dist/components/Popover/popover.d.ts +2 -2
- package/dist/components/Popover/popover.d.ts.map +1 -1
- package/dist/components/Popover/popover.js +72 -42
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/index.d.ts +2 -0
- package/dist/components/ProfileCard/index.d.ts.map +1 -0
- package/dist/components/ProfileCard/index.js +8 -0
- package/dist/components/ProfileCard/index.js.map +1 -0
- package/dist/components/{NameCard/name-card.d.ts → ProfileCard/profile-card.d.ts} +34 -20
- package/dist/components/ProfileCard/profile-card.d.ts.map +1 -0
- package/dist/components/{NameCard/name-card.js → ProfileCard/profile-card.js} +27 -16
- package/dist/components/ProfileCard/profile-card.js.map +1 -0
- package/dist/components/ProgressBar/index.d.ts +2 -0
- package/dist/components/ProgressBar/index.d.ts.map +1 -0
- package/dist/components/ProgressBar/index.js +6 -0
- package/dist/components/ProgressBar/index.js.map +1 -0
- package/dist/components/ProgressBar/progress-bar.d.ts +2 -14
- package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -1
- package/dist/components/ProgressBar/progress-bar.js +5 -9
- package/dist/components/ProgressBar/progress-bar.js.map +1 -1
- package/dist/components/RadioGroup/index.d.ts +2 -0
- package/dist/components/RadioGroup/index.d.ts.map +1 -0
- package/dist/components/RadioGroup/index.js +8 -0
- package/dist/components/RadioGroup/index.js.map +1 -0
- package/dist/components/RadioGroup/radio-group.d.ts +18 -12
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +131 -40
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/index.d.ts +2 -0
- package/dist/components/Rating/index.d.ts.map +1 -0
- package/dist/components/Rating/index.js +6 -0
- package/dist/components/Rating/index.js.map +1 -0
- package/dist/components/Rating/rating.d.ts +6 -2
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +17 -10
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/index.d.ts +2 -0
- package/dist/components/ScrollArea/index.d.ts.map +1 -0
- package/dist/components/ScrollArea/index.js +7 -0
- package/dist/components/ScrollArea/index.js.map +1 -0
- package/dist/components/ScrollArea/scroll-area.d.ts +16 -4
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +9 -6
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/index.d.ts +2 -0
- package/dist/components/SegmentedControl/index.d.ts.map +1 -0
- package/dist/components/SegmentedControl/index.js +9 -0
- package/dist/components/SegmentedControl/index.js.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts +8 -7
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js +31 -20
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.d.ts.map +1 -0
- package/dist/components/Select/index.js +6 -0
- package/dist/components/Select/index.js.map +1 -0
- package/dist/components/Select/select.d.ts +70 -13
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +271 -83
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/index.d.ts +2 -0
- package/dist/components/SelectMenu/index.d.ts.map +1 -0
- package/dist/components/SelectMenu/index.js +8 -0
- package/dist/components/SelectMenu/index.js.map +1 -0
- package/dist/components/SelectMenu/select-menu.d.ts +61 -10
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +216 -93
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
- package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
- package/dist/components/SelectionControl/boolean-value.js +23 -0
- package/dist/components/SelectionControl/boolean-value.js.map +1 -0
- package/dist/components/SelectionControl/index.d.ts +3 -0
- package/dist/components/SelectionControl/index.d.ts.map +1 -0
- package/dist/components/SelectionControl/index.js +9 -0
- package/dist/components/SelectionControl/index.js.map +1 -0
- package/dist/components/SelectionControl/selection-item.d.ts +5 -1
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
- package/dist/components/SelectionControl/selection-item.js +3 -1
- package/dist/components/SelectionControl/selection-item.js.map +1 -1
- package/dist/components/Separator/index.d.ts +2 -0
- package/dist/components/Separator/index.d.ts.map +1 -0
- package/dist/components/Separator/index.js +6 -0
- package/dist/components/Separator/index.js.map +1 -0
- package/dist/components/Separator/separator.d.ts +2 -2
- package/dist/components/Separator/separator.js +4 -3
- package/dist/components/Separator/separator.js.map +1 -1
- package/dist/components/Sheet/index.d.ts +2 -0
- package/dist/components/Sheet/index.d.ts.map +1 -0
- package/dist/components/Sheet/index.js +18 -0
- package/dist/components/Sheet/index.js.map +1 -0
- package/dist/components/Sheet/sheet.d.ts +15 -8
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js +9 -5
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/index.d.ts +2 -0
- package/dist/components/Sidebar/index.d.ts.map +1 -0
- package/dist/components/Sidebar/index.js +24 -0
- package/dist/components/Sidebar/index.js.map +1 -0
- package/dist/components/Sidebar/sidebar.d.ts +17 -11
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +78 -35
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Skeleton/index.d.ts.map +1 -0
- package/dist/components/Skeleton/index.js +6 -0
- package/dist/components/Skeleton/index.js.map +1 -0
- package/dist/components/Skeleton/skeleton.d.ts +2 -2
- package/dist/components/Skeleton/skeleton.js +4 -3
- package/dist/components/Skeleton/skeleton.js.map +1 -1
- package/dist/components/Slider/index.d.ts +2 -0
- package/dist/components/Slider/index.d.ts.map +1 -0
- package/dist/components/Slider/index.js +7 -0
- package/dist/components/Slider/index.js.map +1 -0
- package/dist/components/Slider/slider.d.ts +7 -7
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +39 -17
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/index.d.ts +2 -0
- package/dist/components/Steps/index.d.ts.map +1 -0
- package/dist/components/Steps/index.js +12 -0
- package/dist/components/Steps/index.js.map +1 -0
- package/dist/components/Steps/steps.d.ts +8 -6
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +74 -32
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Switch/index.d.ts.map +1 -0
- package/dist/components/Switch/index.js +7 -0
- package/dist/components/Switch/index.js.map +1 -0
- package/dist/components/Switch/switch.d.ts +20 -18
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +133 -26
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/index.d.ts +2 -0
- package/dist/components/Tabs/index.d.ts.map +1 -0
- package/dist/components/Tabs/index.js +10 -0
- package/dist/components/Tabs/index.js.map +1 -0
- package/dist/components/Tabs/tabs-inline-action-geometry.d.ts +31 -0
- package/dist/components/Tabs/tabs-inline-action-geometry.d.ts.map +1 -0
- package/dist/components/Tabs/tabs-inline-action-geometry.js +43 -0
- package/dist/components/Tabs/tabs-inline-action-geometry.js.map +1 -0
- package/dist/components/Tabs/tabs.d.ts +14 -11
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +184 -69
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/index.d.ts +2 -0
- package/dist/components/Tag/index.d.ts.map +1 -0
- package/dist/components/Tag/index.js +7 -0
- package/dist/components/Tag/index.js.map +1 -0
- package/dist/components/Tag/tag.d.ts +39 -23
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +71 -63
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Textarea/index.d.ts.map +1 -0
- package/dist/components/Textarea/index.js +7 -0
- package/dist/components/Textarea/index.js.map +1 -0
- package/dist/components/Textarea/textarea.d.ts +24 -17
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +110 -72
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/index.d.ts +2 -0
- package/dist/components/TimePicker/index.d.ts.map +1 -0
- package/dist/components/TimePicker/index.js +6 -0
- package/dist/components/TimePicker/index.js.map +1 -0
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
- package/dist/components/TimePicker/time-columns.js +44 -36
- package/dist/components/TimePicker/time-columns.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +8 -7
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +71 -53
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Toast/index.d.ts +2 -0
- package/dist/components/Toast/index.d.ts.map +1 -0
- package/dist/components/Toast/index.js +7 -0
- package/dist/components/Toast/index.js.map +1 -0
- package/dist/components/Toast/toast.d.ts +2 -2
- package/dist/components/Toast/toast.d.ts.map +1 -1
- package/dist/components/Toast/toast.js +82 -20
- package/dist/components/Toast/toast.js.map +1 -1
- package/dist/components/Tooltip/index.d.ts +2 -0
- package/dist/components/Tooltip/index.d.ts.map +1 -0
- package/dist/components/Tooltip/index.js +9 -0
- package/dist/components/Tooltip/index.js.map +1 -0
- package/dist/components/Tooltip/tooltip.d.ts +2 -2
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +57 -25
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/index.d.ts +2 -0
- package/dist/components/TreeView/index.d.ts.map +1 -0
- package/dist/components/TreeView/index.js +8 -0
- package/dist/components/TreeView/index.js.map +1 -0
- package/dist/components/TreeView/tree-view.d.ts +71 -14
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +313 -34
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/hooks/use-controllable.d.ts.map +1 -1
- package/dist/hooks/use-controllable.js +4 -2
- package/dist/hooks/use-controllable.js.map +1 -1
- package/dist/hooks/use-is-touch-device.d.ts.map +1 -1
- package/dist/hooks/use-is-touch-device.js +3 -1
- package/dist/hooks/use-is-touch-device.js.map +1 -1
- package/dist/hooks/use-overflow-items.d.ts +10 -6
- package/dist/hooks/use-overflow-items.d.ts.map +1 -1
- package/dist/hooks/use-overflow-items.js.map +1 -1
- package/dist/hooks/use-truncated.d.ts +27 -0
- package/dist/hooks/use-truncated.d.ts.map +1 -0
- package/dist/hooks/use-truncated.js +57 -0
- package/dist/hooks/use-truncated.js.map +1 -0
- package/dist/{react-day-picker.css → index.css} +59 -0
- package/dist/index.d.ts +121 -67
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +143 -160
- package/dist/index.js.map +1 -1
- package/dist/lib/drag-visual.d.ts +2 -2
- package/dist/lib/drag-visual.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +24 -2
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/index.d.ts +3 -0
- package/dist/patterns/element-anatomy/index.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/index.js +22 -0
- package/dist/patterns/element-anatomy/index.js.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +32 -16
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +83 -35
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/patterns/element-anatomy/truncated-text.d.ts +27 -0
- package/dist/patterns/element-anatomy/truncated-text.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/truncated-text.js +16 -0
- package/dist/patterns/element-anatomy/truncated-text.js.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts +20 -4
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -1
- package/dist/patterns/header-canonical/chrome-header.js +4 -2
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -1
- package/dist/patterns/header-canonical/index.d.ts +2 -0
- package/dist/patterns/header-canonical/index.d.ts.map +1 -0
- package/dist/patterns/header-canonical/index.js +6 -0
- package/dist/patterns/header-canonical/index.js.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +1 -1
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
- package/dist/patterns/horizontal-overflow/index.d.ts +2 -0
- package/dist/patterns/horizontal-overflow/index.d.ts.map +1 -0
- package/dist/patterns/horizontal-overflow/index.js +14 -0
- package/dist/patterns/horizontal-overflow/index.js.map +1 -0
- package/dist/patterns/overlay-surface/index.d.ts +2 -0
- package/dist/patterns/overlay-surface/index.d.ts.map +1 -0
- package/dist/patterns/overlay-surface/index.js +8 -0
- package/dist/patterns/overlay-surface/index.js.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +12 -2
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.js +6 -2
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
- package/dist/patterns/resize-handle/index.d.ts +2 -0
- package/dist/patterns/resize-handle/index.d.ts.map +1 -0
- package/dist/patterns/resize-handle/index.js +5 -0
- package/dist/patterns/resize-handle/index.js.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts +9 -11
- package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -1
- package/dist/patterns/resize-handle/resize-handle.js +3 -6
- package/dist/patterns/resize-handle/resize-handle.js.map +1 -1
- package/dist/story-governance/category-matrix.d.ts +35 -0
- package/dist/story-governance/category-matrix.d.ts.map +1 -0
- package/dist/tokens/categorical-color.d.ts +60 -0
- package/dist/tokens/categorical-color.d.ts.map +1 -0
- package/dist/tokens/categorical-color.js +125 -0
- package/dist/tokens/categorical-color.js.map +1 -0
- package/dist/tokens/motion/motion.d.ts +8 -7
- package/dist/tokens/motion/motion.d.ts.map +1 -1
- package/dist/tokens/motion/motion.js +6 -6
- package/dist/tokens/motion/motion.js.map +1 -1
- package/dist/tokens/motion/overlay-motion.d.ts +19 -0
- package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
- package/dist/tokens/motion/overlay-motion.js +9 -0
- package/dist/tokens/motion/overlay-motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.d.ts +3 -4
- package/dist/tokens/uiSize/icon-size.d.ts.map +1 -1
- package/dist/tokens/uiSize/icon-size.js +5 -0
- package/dist/tokens/uiSize/icon-size.js.map +1 -0
- package/ds-canonical/adapters/claude/agents/README.md +58 -0
- package/ds-canonical/adapters/claude/agents/canonical-reviewer.md +14 -0
- package/ds-canonical/adapters/claude-root-instructions.md +24 -0
- package/ds-canonical/adapters/claude-settings-base.json +169 -0
- package/ds-canonical/commands/README.md +9 -14
- package/ds-canonical/fork/AGENTS.md +110 -0
- package/ds-canonical/fork/CLAUDE.md +54 -0
- package/ds-canonical/fork/codex/agents/skills/bug-fix-rhythm/SKILL.md +207 -0
- package/ds-canonical/fork/codex/agents/skills/code-quality-audit/SKILL.md +71 -0
- package/ds-canonical/fork/codex/agents/skills/delivery-handoff/SKILL.md +244 -0
- package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/fork/codex/agents/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +43 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/agents/openai.yaml +4 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/references/evidence-contract.md +23 -0
- package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +114 -0
- package/ds-canonical/fork/codex/agents/skills/product-ui-audit/SKILL.md +252 -0
- package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/audit-checks.md +250 -0
- package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/fork/codex/agents/skills/product-ui-audit/references/report-template.md +163 -0
- package/ds-canonical/fork/codex/agents/skills/propose-options/SKILL.md +190 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/SKILL.md +246 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/audit-checks.md +39 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/checkpoints.md +200 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/evaluation-matrix.md +142 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/fork/codex/agents/skills/prototype/references/proposal-template.md +230 -0
- package/ds-canonical/fork/codex/agents/skills/scan-similar-bugs/SKILL.md +203 -0
- package/ds-canonical/fork/codex/agents/skills/ux-audit/SKILL.md +135 -0
- package/ds-canonical/fork/codex/agents/skills/visual-audit/SKILL.md +258 -0
- package/ds-canonical/fork/codex/agents/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/fork/codex/agents/skills/visual-audit/references/audit-architecture.md +101 -0
- package/ds-canonical/fork/codex/agents/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/fork/codex/agents/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/ds-canonical/fork/codex/hooks.json +57 -0
- package/ds-canonical/fork/common/closed-tool-execution.mjs +1005 -0
- package/ds-canonical/fork/common/instruction.md +110 -0
- package/ds-canonical/fork/consumer/governance-check.mjs +3163 -0
- package/ds-canonical/fork/consumer/lib/closed-tool-execution.mjs +1005 -0
- package/ds-canonical/fork/consumer/lock.json +189 -0
- package/ds-canonical/fork/consumer/lock.schema.json +338 -0
- package/ds-canonical/fork/consumer/managed-files/0235cf6b3fd402a3717881dc205b5bf77aed7632e7d7d6f1811a40e3033bd816.blob +145 -0
- package/ds-canonical/fork/consumer/managed-files/145aab4b4fc470fc9ba7679b4a1d87d4f6a6d604940bd40f8d675c8af696498f.blob +53 -0
- package/ds-canonical/fork/consumer/managed-files/189e551431181e4a88783c02130d2787b801ef731c86e35bcde89a7313aa020e.blob +149 -0
- package/ds-canonical/fork/consumer/managed-files/24ad71c8613ddcf6fd23818cb3bb477a1fb6d83af4550b0bad43099813088686.blob +28 -0
- package/ds-canonical/fork/consumer/managed-files/2d1ef5617a5ce3c39ad9aae1c42af7d199f9270c0a0ccb490b63d62dbc6913db.blob +1005 -0
- package/ds-canonical/fork/consumer/managed-files/3625e02235cf166a50649a4d704cfb68fead69d0e168c481df013ebae9f6be25.blob +1412 -0
- package/ds-canonical/fork/consumer/managed-files/3ddedc67b464bdfe3dde9803a2d917920c96d633678b802eee638a44cd47366a.blob +8 -0
- package/ds-canonical/fork/consumer/managed-files/423729840acdd43c812f17c245b871716c6b60f76e4d3e94864d0e34a815bf8d.blob +348 -0
- package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +549 -0
- package/ds-canonical/fork/consumer/managed-files/475fba657eaeb8abd88f60635f3eadab27a9d0d3114ba4fffc65f43a2a0fe6e2.blob +124 -0
- package/ds-canonical/fork/consumer/managed-files/5aeda1df235815f40dd755951f2b868d4e02035653d4536a8dde209cdc75b493.blob +268 -0
- package/ds-canonical/fork/consumer/managed-files/61c6aca6d7f04bedbf556eaa9d3043681fe48cbe0e93a8ccb1d69a7c5e23fdcf.blob +113 -0
- package/ds-canonical/fork/consumer/managed-files/63061e05969667005020166ea2ae7df3c96663f7a928e7dd3eebc1471022df56.blob +2454 -0
- package/ds-canonical/fork/consumer/managed-files/65410b66e8799a560e07b71779c186fed2a0ef50575ac44745df7a0938a9c2b4.blob +321 -0
- package/ds-canonical/fork/consumer/managed-files/6b746628ac11fcccbe277ef6fea94cc2a7b90ea2822e83536eae80d5ee4b3fa5.blob +167 -0
- package/ds-canonical/fork/consumer/managed-files/76d485470d30ff014afacf7ce643763de9f4f956d9fc8128dbc1814774cf2e63.blob +671 -0
- package/ds-canonical/fork/consumer/managed-files/7937321877e5c34c27dae36c0d507d21cd42fa3f46a8f11a284b8b4a52b6faa4.blob +84 -0
- package/ds-canonical/fork/consumer/managed-files/794bb911ba8ebef58ab0d44a55b9968a19d2c62bcfb310b1ee3a84166f087f21.blob +924 -0
- package/ds-canonical/fork/consumer/managed-files/7ab15a8aeca39485d7b9b57234bbc4a69e0b9e70b4a851dfe10f6447127cee78.blob +51 -0
- package/ds-canonical/fork/consumer/managed-files/7b17835d0ceb17cdcdcaf930540a3e5d0943a34a747ac43c12ca8cd485c11581.blob +44 -0
- package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +900 -0
- package/ds-canonical/fork/consumer/managed-files/81037efa5b3b9f4a875704005fb268acdc9233bb901f44902e4e37e1da92b8e3.blob +46 -0
- package/ds-canonical/fork/consumer/managed-files/884721550b56308812b20917adac7a12f36fdb4ecda6b02460a7f5a219c0c966.blob +82 -0
- package/ds-canonical/fork/consumer/managed-files/91f414b9462ddc1e4be1d4c6ca4ac7a7340a6eec9e98ee109cbc049d3b354b6a.blob +36 -0
- package/ds-canonical/fork/consumer/managed-files/92e4828cdcb96ff0d01daa16f6885f24045a8e72820665650f2a1890dc3a446c.blob +121 -0
- package/ds-canonical/fork/consumer/managed-files/93a89f16f6717d1e4e4e27ec20ef916e3355c7aa890ca74cd9b12db30d8a899f.blob +36 -0
- package/ds-canonical/fork/consumer/managed-files/974521d6b8fe796ea4c58b3c78b0c2b8a1be262b97100d77aaf4cc9c7724bcab.blob +45 -0
- package/ds-canonical/fork/consumer/managed-files/9791c85388d2e2e2bd564e2550fadc3351c4c960a47ce838098afcba7544eb90.blob +973 -0
- package/ds-canonical/fork/consumer/managed-files/a448d2222133335c30e6fda5116e26a40db3283a19d62ccc0663c30d272262a7.blob +174 -0
- package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +2639 -0
- package/ds-canonical/fork/consumer/managed-files/bc44cabad181f766611dab6a8f52d81100afadd50ac59799015e8ba7bf46d9eb.blob +620 -0
- package/ds-canonical/fork/consumer/managed-files/c4aa767f11714467de0038a2149cf78074baddc17fc6a9e074b6aed7544c6f3c.blob +80 -0
- package/ds-canonical/fork/consumer/managed-files/c893e9b734b162f4c631fef871128c16a9ab565f796a0e76d7f320f821f220f5.blob +41 -0
- package/ds-canonical/fork/consumer/managed-files/cd9c61f8ff24fb9bcc3663e346e2cfa419cfb84e02aae18d3dc66dd192681696.blob +9 -0
- package/ds-canonical/fork/consumer/managed-files/da2ad2737315d25a5300905ddefd62f1695056a8a1af155c5b34170ad9923bce.blob +38 -0
- package/ds-canonical/fork/consumer/managed-files/e26057408661597aac4a57cdf7e30e2f9d0afb1b9a2dbbb692c3805cd9028ca5.blob +250 -0
- package/ds-canonical/fork/consumer/managed-files/e68ae1915965d8e17d4b2441c00c2b97fe062ea308ae8535c9eebb2fc16fa245.blob +20 -0
- package/ds-canonical/fork/consumer/managed-files/e71c65f45c6af7ce12b6b3c0d8028f185da5b719e2050c9b2a6b243d41ae4878.blob +182 -0
- package/ds-canonical/fork/consumer/managed-files/e813096d69c49812e40e00be9ac8fa14d77f0ec1f97ab4c45cb096b3bedd35de.blob +3 -0
- package/ds-canonical/fork/consumer/managed-files/e930ebca6fd8eeb30802aac0930efae7bcc44cc0996f24de07c11ca6a081fedf.blob +277 -0
- package/ds-canonical/fork/consumer/managed-files/ea94e914d5c8acb84ad7660e5bda0f01b6ccc8cf96b0f6b1ce048f8938d0f5b5.blob +47 -0
- package/ds-canonical/fork/consumer/managed-files/f4db6e616d5229aa7e700c6a3ace022cb9d90baae74e38ca65fce617f18e0d9b.blob +110 -0
- package/ds-canonical/fork/consumer/managed-files/faa128c26102415dc5345e68698efbbd28a395c35ee278dceae044cf430692b2.blob +11 -0
- package/ds-canonical/fork/governance.lock +1696 -0
- package/ds-canonical/fork/hooks/_log-fire.sh +143 -0
- package/ds-canonical/fork/hooks/block_prototype_imports.py +241 -0
- package/ds-canonical/fork/hooks/check_chrome_header_avatar_canonical.sh +106 -0
- package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +731 -0
- package/ds-canonical/fork/hooks/check_consumer_code_quality.sh +173 -0
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +219 -0
- package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +57 -0
- package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +213 -0
- package/ds-canonical/fork/hooks/check_field_family_invariants.sh +376 -0
- package/ds-canonical/fork/hooks/check_fork_product_quality.sh +38 -0
- package/ds-canonical/fork/hooks/check_item_list_gap.sh +56 -0
- package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +160 -0
- package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +319 -0
- package/ds-canonical/fork/hooks/check_pattern_invariants.sh +339 -0
- package/ds-canonical/fork/hooks/check_sidebar_menu_button_implicit_wrap.sh +99 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +39 -0
- package/ds-canonical/fork/hooks/check_story_invariants.sh +400 -0
- package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +241 -0
- package/ds-canonical/fork/hooks/check_tailwind_wildcard_in_docs.sh +86 -0
- package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +333 -0
- package/ds-canonical/fork/hooks/lib/_hook_integrity.sh +158 -0
- package/ds-canonical/fork/hooks/lib/_micro_geometry.sh +291 -0
- package/ds-canonical/fork/hooks/lib/_provider_paths.sh +162 -0
- package/ds-canonical/fork/launchers/approval-evidence.mjs +1321 -0
- package/ds-canonical/fork/launchers/authority-decision-evidence.mjs +413 -0
- package/ds-canonical/fork/launchers/canonical-order.mjs +8 -0
- package/ds-canonical/fork/launchers/fork-governance-dispatcher.sh +154 -0
- package/ds-canonical/fork/launchers/format-provider-hook-output.mjs +25 -0
- package/ds-canonical/fork/launchers/independent-review.mjs +490 -0
- package/ds-canonical/fork/launchers/inject_fork_governance_preamble.sh +99 -0
- package/ds-canonical/fork/launchers/normalize-provider-event.mjs +355 -0
- package/ds-canonical/fork/launchers/product-hook-dispatch-runtime.mjs +1067 -0
- package/ds-canonical/fork/launchers/provider-hook-normalization.mjs +1640 -0
- package/ds-canonical/fork/launchers/provider-hook-output-transport.mjs +540 -0
- package/ds-canonical/fork/launchers/settings-hooks.json +35 -0
- package/ds-canonical/fork/manifest.json +1984 -0
- package/ds-canonical/fork/providers/claude/hook-config.json +327 -0
- package/ds-canonical/fork/providers/claude/instruction.md +54 -0
- package/ds-canonical/fork/providers/claude/skills/bug-fix-rhythm/SKILL.md +207 -0
- package/ds-canonical/fork/providers/claude/skills/code-quality-audit/SKILL.md +71 -0
- package/ds-canonical/fork/providers/claude/skills/delivery-handoff/SKILL.md +244 -0
- package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/fork/providers/claude/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/fork/providers/claude/skills/independent-review/SKILL.md +43 -0
- package/ds-canonical/fork/providers/claude/skills/independent-review/agents/openai.yaml +4 -0
- package/ds-canonical/fork/providers/claude/skills/independent-review/references/evidence-contract.md +23 -0
- package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +114 -0
- package/ds-canonical/fork/providers/claude/skills/product-ui-audit/SKILL.md +252 -0
- package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/audit-checks.md +250 -0
- package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/fork/providers/claude/skills/product-ui-audit/references/report-template.md +163 -0
- package/ds-canonical/fork/providers/claude/skills/propose-options/SKILL.md +190 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/SKILL.md +246 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/audit-checks.md +39 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/checkpoints.md +200 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/evaluation-matrix.md +142 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/fork/providers/claude/skills/prototype/references/proposal-template.md +230 -0
- package/ds-canonical/fork/providers/claude/skills/scan-similar-bugs/SKILL.md +203 -0
- package/ds-canonical/fork/providers/claude/skills/ux-audit/SKILL.md +135 -0
- package/ds-canonical/fork/providers/claude/skills/visual-audit/SKILL.md +258 -0
- package/ds-canonical/fork/providers/claude/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/fork/providers/claude/skills/visual-audit/references/audit-architecture.md +101 -0
- package/ds-canonical/fork/providers/claude/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/fork/providers/claude/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/ds-canonical/fork/providers/codex/hook-config.json +57 -0
- package/ds-canonical/fork/providers/codex/skills/bug-fix-rhythm/SKILL.md +207 -0
- package/ds-canonical/fork/providers/codex/skills/code-quality-audit/SKILL.md +71 -0
- package/ds-canonical/fork/providers/codex/skills/delivery-handoff/SKILL.md +244 -0
- package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/fork/providers/codex/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/fork/providers/codex/skills/independent-review/SKILL.md +43 -0
- package/ds-canonical/fork/providers/codex/skills/independent-review/agents/openai.yaml +4 -0
- package/ds-canonical/fork/providers/codex/skills/independent-review/references/evidence-contract.md +23 -0
- package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +114 -0
- package/ds-canonical/fork/providers/codex/skills/product-ui-audit/SKILL.md +252 -0
- package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/audit-checks.md +250 -0
- package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/fork/providers/codex/skills/product-ui-audit/references/report-template.md +163 -0
- package/ds-canonical/fork/providers/codex/skills/propose-options/SKILL.md +190 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/SKILL.md +246 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/audit-checks.md +39 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/checkpoints.md +200 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/evaluation-matrix.md +142 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/fork/providers/codex/skills/prototype/references/proposal-template.md +230 -0
- package/ds-canonical/fork/providers/codex/skills/scan-similar-bugs/SKILL.md +203 -0
- package/ds-canonical/fork/providers/codex/skills/ux-audit/SKILL.md +135 -0
- package/ds-canonical/fork/providers/codex/skills/visual-audit/SKILL.md +258 -0
- package/ds-canonical/fork/providers/codex/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/fork/providers/codex/skills/visual-audit/references/audit-architecture.md +101 -0
- package/ds-canonical/fork/providers/codex/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/fork/providers/codex/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/ds-canonical/fork/references/story-baseline-registry.json +123 -0
- package/ds-canonical/fork/references/story-baseline-registry.schema.json +145 -0
- package/ds-canonical/fork/references/utility-registry.json +426 -0
- package/ds-canonical/fork/references/utility-registry.schema.json +409 -0
- package/ds-canonical/fork/review/canonical-order.mjs +8 -0
- package/ds-canonical/fork/review/provider-review-binding.mjs +2377 -0
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +196 -0
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +69 -0
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +242 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/fork/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/fork/skills/independent-review/SKILL.md +37 -0
- package/ds-canonical/fork/skills/independent-review/agents/openai.yaml +4 -0
- package/ds-canonical/fork/skills/independent-review/references/evidence-contract.md +23 -0
- package/ds-canonical/fork/skills/performance-audit/SKILL.md +112 -0
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +250 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/audit-checks.md +250 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/fork/skills/product-ui-audit/references/report-template.md +163 -0
- package/ds-canonical/fork/skills/propose-options/SKILL.md +179 -0
- package/ds-canonical/fork/skills/prototype/SKILL.md +244 -0
- package/ds-canonical/fork/skills/prototype/references/audit-checks.md +39 -0
- package/ds-canonical/fork/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/fork/skills/prototype/references/checkpoints.md +200 -0
- package/ds-canonical/fork/skills/prototype/references/evaluation-matrix.md +142 -0
- package/ds-canonical/fork/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/fork/skills/prototype/references/proposal-template.md +230 -0
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +201 -0
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +133 -0
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +248 -0
- package/ds-canonical/fork/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/fork/skills/visual-audit/references/audit-architecture.md +101 -0
- package/ds-canonical/fork/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/fork/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/ds-canonical/hooks/README.md +39 -25
- package/ds-canonical/hooks/_log-fire.sh +111 -12
- package/ds-canonical/hooks/auto_regen_ds_barrel.sh +90 -0
- package/ds-canonical/hooks/block_prototype_imports.py +156 -26
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +328 -32
- package/ds-canonical/hooks/check_audit_sample_escape.sh +10 -7
- package/ds-canonical/hooks/check_benchmark_citation.sh +41 -8
- package/ds-canonical/hooks/check_canonical_propagation.sh +85 -24
- package/ds-canonical/hooks/check_chrome_header_avatar_canonical.sh +106 -0
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +138 -29
- package/ds-canonical/hooks/check_codex_collab_5step.sh +31 -25
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +731 -0
- package/ds-canonical/hooks/check_consumer_code_quality.sh +173 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +173 -29
- package/ds-canonical/hooks/check_dim_count_drift.sh +8 -7
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +219 -0
- package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +57 -0
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +213 -0
- package/ds-canonical/hooks/check_field_controls_contracts.sh +37 -8
- package/ds-canonical/hooks/check_field_family_invariants.sh +195 -24
- package/ds-canonical/hooks/check_file_size_budget.sh +32 -14
- package/ds-canonical/hooks/check_full_story_visual_interaction_sweep.sh +111 -0
- package/ds-canonical/hooks/check_item_list_gap.sh +56 -0
- package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +160 -0
- package/ds-canonical/hooks/check_main_branch_workbench.sh +27 -68
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +21 -10
- package/ds-canonical/hooks/check_opacity_token_usage.sh +238 -68
- package/ds-canonical/hooks/check_orphan_ds_css.sh +96 -0
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +110 -0
- package/ds-canonical/hooks/check_pattern_invariants.sh +160 -15
- package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +4 -4
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +6 -4
- package/ds-canonical/hooks/check_plugin_fork_health.sh +282 -0
- package/ds-canonical/hooks/check_propose_discipline.sh +255 -0
- package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +6 -4
- package/ds-canonical/hooks/check_propose_without_benchmark.sh +71 -0
- package/ds-canonical/hooks/check_select_all_canonical.sh +1 -1
- package/ds-canonical/hooks/check_sidebar_menu_button_implicit_wrap.sh +99 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +62 -168
- package/ds-canonical/hooks/check_spec_class_drift.sh +33 -19
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +56 -0
- package/ds-canonical/hooks/check_story_determinism.sh +39 -0
- package/ds-canonical/hooks/check_story_invariants.sh +722 -222
- package/ds-canonical/hooks/check_storybook_addon_packaging.sh +201 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +143 -64
- package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +241 -0
- package/ds-canonical/hooks/check_tailwind_wildcard_in_docs.sh +86 -0
- package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +15 -12
- package/ds-canonical/hooks/chrome_header_dispatcher.sh +105 -0
- package/ds-canonical/hooks/enforce_home_charter.sh +31 -10
- package/ds-canonical/hooks/governance_control_plane.sh +15 -0
- package/ds-canonical/hooks/inject_deploy_url_after_push.sh +333 -0
- package/ds-canonical/hooks/inject_pending_self_audit.sh +68 -21
- package/ds-canonical/hooks/lib/_app_shell_primary_header_consistency.sh +148 -0
- package/ds-canonical/hooks/lib/_chrome_header_handcraft.sh +121 -0
- package/ds-canonical/hooks/lib/_code_quality.sh +9 -9
- package/ds-canonical/hooks/lib/_cva_default_sync.sh +11 -13
- package/ds-canonical/hooks/lib/_governance_coverage_check.sh +48 -21
- package/ds-canonical/hooks/lib/_hardcoded_strings.sh +18 -10
- package/ds-canonical/hooks/lib/_header_with_tabs_border.sh +107 -0
- package/ds-canonical/hooks/lib/_hook_integrity.sh +158 -0
- package/ds-canonical/hooks/lib/_layout_space_canonical.sh +5 -5
- package/ds-canonical/hooks/lib/_micro_geometry.sh +291 -0
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +42 -23
- package/ds-canonical/hooks/lib/_person_data_richness.sh +5 -5
- package/ds-canonical/hooks/lib/_provider_paths.sh +162 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +5 -5
- package/ds-canonical/hooks/lib/_tab_lg_chrome_header_equal.sh +290 -0
- package/ds-canonical/hooks/lib/_token_hygiene.sh +55 -20
- package/ds-canonical/hooks/lib/approval-evidence.mjs +1321 -0
- package/ds-canonical/hooks/lib/audit-report-validator.mjs +122 -0
- package/ds-canonical/hooks/lib/provider-marker-regex.mjs +23 -0
- package/ds-canonical/hooks/lib/tsx-governance-analysis.mjs +410 -0
- package/ds-canonical/hooks/log_governance_fires.sh +45 -13
- package/ds-canonical/hooks/log_skill_invokes.sh +8 -7
- package/ds-canonical/hooks/post_edit_dispatcher.sh +106 -28
- package/ds-canonical/hooks/registrations.json +488 -0
- package/ds-canonical/hooks/registrations.schema.json +58 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_addon_subdir_ship.sh +76 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_app_story_title.sh +81 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_ds_primitive_misuse.sh +120 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_no_ds_catalog.sh +101 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_consumer_story_baseline.sh +76 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_data_table_size_num_to_meta_width.sh +68 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_fork_user_plugin_install.sh +79 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_plugin_freshness.sh +68 -0
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_propose_cite_required.sh +88 -0
- package/ds-canonical/hooks/{check_propose_plain_chinese.sh → retired/2026-06-11-prune-merge/check_propose_plain_chinese.sh} +2 -2
- package/ds-canonical/hooks/retired/2026-06-11-prune-merge/check_storybook_addon_preset_cjs.sh +87 -0
- package/ds-canonical/hooks/{lib/_approval_re.sh → retired/_approval_re.sh.retired-2026-08-18} +6 -7
- package/ds-canonical/hooks/retired/check_container_breathing.sh +1 -1
- package/ds-canonical/hooks/retired/check_governance_compliance.sh +1 -1
- package/ds-canonical/hooks/session_start_governance_check.sh +157 -69
- package/ds-canonical/hooks/stop_audit_content_quality.sh +20 -0
- package/ds-canonical/hooks/stop_extract_canonical_rules.sh +20 -0
- package/ds-canonical/hooks/stop_passive_logging.sh +133 -59
- package/ds-canonical/hooks/stop_self_audit.sh +472 -178
- package/ds-canonical/hooks/tests/fixtures/transcripts/claude-transcript-jsonl-v1.jsonl +3 -0
- package/ds-canonical/hooks/tests/fixtures/transcripts/claude-transcript-jsonl-v2.jsonl +3 -0
- package/ds-canonical/hooks/tests/registration-output-contracts.mjs +151 -0
- package/ds-canonical/hooks/tests/run-all.sh +35 -5
- package/ds-canonical/hooks/tests/test_auto_regen_ds_barrel.sh +224 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +181 -9
- package/ds-canonical/hooks/tests/test_check_addon_subdir_ship.sh +171 -0
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +275 -81
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +292 -14
- package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +0 -0
- package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +41 -9
- package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +56 -5
- package/ds-canonical/hooks/tests/test_check_chrome_header_avatar_canonical.sh +198 -0
- package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +197 -81
- package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +375 -0
- package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +49 -5
- package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +140 -0
- package/ds-canonical/hooks/tests/test_check_consumer_app_story_title.sh +164 -0
- package/ds-canonical/hooks/tests/test_check_consumer_code_quality.sh +86 -0
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +417 -0
- package/ds-canonical/hooks/tests/test_check_consumer_no_ds_catalog.sh +214 -0
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +209 -0
- package/ds-canonical/hooks/tests/test_check_data_table_size_num_to_meta_width.sh +71 -0
- package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +126 -12
- package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +13 -8
- package/ds-canonical/hooks/tests/test_check_ds_anchor_preflight.sh +150 -0
- package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
- package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +278 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +108 -18
- package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +67 -5
- package/ds-canonical/hooks/tests/test_check_fork_user_plugin_install.sh +151 -0
- package/ds-canonical/hooks/tests/test_check_full_story_visual_interaction_sweep.sh +200 -0
- package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +178 -68
- package/ds-canonical/hooks/tests/test_check_item_list_gap.sh +44 -0
- package/ds-canonical/hooks/tests/test_check_layout_space_magic_numbers.sh +264 -0
- package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +45 -110
- package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +19 -2
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +151 -6
- package/ds-canonical/hooks/tests/test_check_orphan_ds_css.sh +228 -0
- package/ds-canonical/hooks/tests/test_check_overlay_open_focus_escape_probe.sh +191 -0
- package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +103 -7
- package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +132 -0
- package/ds-canonical/hooks/tests/test_check_propose_cite_required.sh +181 -0
- package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +69 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +10 -7
- package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +5 -5
- package/ds-canonical/hooks/tests/test_check_propose_without_benchmark.sh +100 -0
- package/ds-canonical/hooks/tests/test_check_sidebar_menu_button_implicit_wrap.sh +224 -0
- package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +86 -105
- package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +35 -7
- package/ds-canonical/hooks/tests/test_check_ssot_header_declaration.sh +72 -0
- package/ds-canonical/hooks/tests/{test_check_story_anatomy.sh.broken → test_check_story_anatomy.sh} +73 -4
- package/ds-canonical/hooks/tests/test_check_story_category.sh +411 -0
- package/ds-canonical/hooks/tests/test_check_story_determinism.sh +39 -0
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +734 -43
- package/ds-canonical/hooks/tests/{test_check_story_name_jargon.sh.broken → test_check_story_name_jargon.sh} +22 -1
- package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +89 -0
- package/ds-canonical/hooks/tests/test_check_storybook_addon_preset_cjs.sh +200 -0
- package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +672 -28
- package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +182 -97
- package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
- package/ds-canonical/hooks/tests/test_check_tailwind_wildcard_in_docs.sh +182 -0
- package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +63 -15
- package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +12 -6
- package/ds-canonical/hooks/tests/test_chrome_header_dispatcher.sh +125 -0
- package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +58 -4
- package/ds-canonical/hooks/tests/test_governance_control_plane.sh +66 -0
- package/ds-canonical/hooks/tests/test_governance_coverage_check.sh +88 -0
- package/ds-canonical/hooks/tests/test_hook_integrity_classification.sh +217 -0
- package/ds-canonical/hooks/tests/test_inject_deploy_url_after_push.sh +276 -0
- package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +116 -11
- package/ds-canonical/hooks/tests/test_log_governance_fires.sh +117 -1
- package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +74 -5
- package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +234 -77
- package/ds-canonical/hooks/tests/test_provider_peer_symmetry.sh +76 -0
- package/ds-canonical/hooks/tests/test_registration_output_contracts.sh +20 -0
- package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +145 -22
- package/ds-canonical/hooks/tests/test_stop_audit_content_quality.sh +75 -0
- package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +101 -23
- package/ds-canonical/hooks/tests/test_stop_extract_canonical_rules.sh +75 -0
- package/ds-canonical/hooks/tests/{test_stop_governance_drift_check.sh.broken → test_stop_governance_drift_check.sh} +22 -12
- package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +102 -1
- package/ds-canonical/hooks/tests/test_stop_repository_command_context.sh +38 -0
- package/ds-canonical/hooks/tests/test_stop_self_audit.sh +427 -13
- package/ds-canonical/references/README.md +19 -11
- package/ds-canonical/references/build-ui-canonicals.md +23 -6
- package/ds-canonical/references/certified-surfaces.md +46 -0
- package/ds-canonical/references/composition-fidelity.md +47 -0
- package/ds-canonical/references/cva-patterns.md +2 -2
- package/ds-canonical/references/drag-canonical.md +67 -311
- package/ds-canonical/references/failure-class-registry.json +160 -0
- package/ds-canonical/references/governance-audit-coverage.md +34 -0
- package/ds-canonical/references/item-anatomy-recipe.md +3 -3
- package/ds-canonical/references/naming-conventions.md +2 -1
- package/ds-canonical/references/principle-dim-map.json +136 -9
- package/ds-canonical/references/props-naming.md +18 -3
- package/ds-canonical/references/repository-hygiene-policy.json +143 -0
- package/ds-canonical/references/repository-hygiene.md +106 -0
- package/ds-canonical/references/runtime-evidence-retention.md +88 -0
- package/ds-canonical/references/scenario-definition.md +146 -0
- package/ds-canonical/references/spec-rules.md +1 -1
- package/ds-canonical/references/ssot-consultation.md +5 -5
- package/ds-canonical/references/ssot-index.md +11 -10
- package/ds-canonical/references/story-baseline-registry.json +55 -11
- package/ds-canonical/references/story-baseline-registry.schema.json +145 -0
- package/ds-canonical/references/structural-token-retention.md +7 -10
- package/ds-canonical/references/tailwind-gotchas.md +4 -4
- package/ds-canonical/references/ui-dev-rules.md +22 -1
- package/ds-canonical/rules/README.md +15 -10
- package/ds-canonical/rules/meta-patterns.md +30 -30
- package/ds-canonical/rules/self-verify.md +22 -12
- package/ds-canonical/rules/spec-rules.md +2 -2
- package/ds-canonical/rules/story-rules.md +36 -9
- package/ds-canonical/rules/ui-development.md +23 -15
- package/ds-canonical/skills/README.md +29 -17
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +26 -13
- package/ds-canonical/skills/canonical-reviewer/SKILL.md +29 -0
- package/ds-canonical/skills/code-quality-audit/SKILL.md +15 -11
- package/ds-canonical/skills/codex-collab/SKILL.md +22 -235
- package/ds-canonical/skills/codex-collab/references/brief-template.md +37 -43
- package/ds-canonical/skills/codex-collab/references/transport.md +38 -57
- package/ds-canonical/skills/codify-corrections/SKILL.md +37 -36
- package/ds-canonical/skills/codify-principle/SKILL.md +35 -34
- package/ds-canonical/skills/component-quality-gate/SKILL.md +17 -17
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +8 -8
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +47 -224
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +36 -102
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +33 -147
- package/ds-canonical/skills/deep-audit-cross-codex/references/skill-relationships-antipatterns-benchmarks.md +28 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +15 -80
- package/ds-canonical/skills/deep-audit-cross-codex/references/upstream-directives-r-mapping.md +34 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +19 -8
- package/ds-canonical/skills/design-system-audit/SKILL.md +130 -76
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +207 -105
- package/ds-canonical/skills/design-system-audit/references/checkpoints.md +59 -50
- package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +33 -9
- package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +51 -32
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +57 -53
- package/ds-canonical/skills/ensure-canonical/SKILL.md +37 -35
- package/ds-canonical/skills/governance-health/SKILL.md +31 -25
- package/ds-canonical/skills/governance-status/SKILL.md +30 -0
- package/ds-canonical/skills/independent-review/SKILL.md +37 -0
- package/ds-canonical/skills/independent-review/agents/openai.yaml +4 -0
- package/ds-canonical/skills/independent-review/references/evidence-contract.md +23 -0
- package/ds-canonical/skills/knowledge-prune/SKILL.md +57 -114
- package/ds-canonical/skills/knowledge-prune/references/phase-z-cross-repo-ssot-propagation.md +15 -0
- package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +57 -0
- package/ds-canonical/skills/knowledge-prune/references/world-class-prune-alignment.md +7 -0
- package/ds-canonical/skills/new-component/SKILL.md +33 -25
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +12 -11
- package/ds-canonical/skills/performance-audit/SKILL.md +15 -12
- package/ds-canonical/skills/product-ui-audit/SKILL.md +52 -34
- package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +10 -7
- package/ds-canonical/skills/product-ui-audit/references/report-template.md +30 -26
- package/ds-canonical/skills/propose-options/SKILL.md +23 -23
- package/ds-canonical/skills/prototype/SKILL.md +19 -21
- package/ds-canonical/skills/prototype/references/audit-checks.md +6 -5
- package/ds-canonical/skills/prototype/references/checkpoints.md +26 -17
- package/ds-canonical/skills/prototype/references/evaluation-matrix.md +2 -2
- package/ds-canonical/skills/prototype/references/ooux-template.md +1 -1
- package/ds-canonical/skills/prototype/references/proposal-template.md +5 -5
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +29 -28
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +26 -25
- package/ds-canonical/skills/story-writing/SKILL.md +25 -14
- package/ds-canonical/skills/story-writing/references/anatomy-standard.md +2 -2
- package/ds-canonical/skills/story-writing/references/category-templates.md +15 -15
- package/ds-canonical/skills/ux-audit/SKILL.md +13 -10
- package/ds-canonical/skills/visual-audit/SKILL.md +47 -46
- package/ds-canonical/skills/visual-audit/references/audit-architecture.md +7 -7
- package/ds-canonical/skills/visual-audit/references/visual-checklist.md +14 -14
- package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +3 -3
- package/ds-canonical/templates/_README.md +22 -0
- package/ds-canonical/templates/consumer-governance.md +82 -0
- package/ds-canonical/templates/dashboard-app.tsx +186 -0
- package/ds-canonical/templates/product-launchers/fork-governance-dispatcher.sh +154 -0
- package/ds-canonical/templates/product-launchers/format-provider-hook-output.mjs +25 -0
- package/ds-canonical/templates/product-launchers/independent-review.mjs +490 -0
- package/ds-canonical/templates/product-launchers/inject_fork_governance_preamble.sh +99 -0
- package/ds-canonical/templates/product-launchers/normalize-provider-event.mjs +355 -0
- package/ds-canonical/templates/product-launchers/product-hook-dispatch-runtime.mjs +1067 -0
- package/ds-canonical/templates/product-provider-wiring.json +82 -0
- package/ds-canonical/templates/product-provider-wiring.schema.json +153 -0
- package/ds-story-manifest.json +1791 -0
- package/llms-full.txt +450 -0
- package/llms.txt +74 -0
- package/package.json +43 -10
- package/src/README.md +1 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +496 -0
- package/src/components/Accordion/accordion.principles.stories.tsx +365 -0
- package/src/components/Accordion/accordion.spec.md +31 -5
- package/src/components/Accordion/accordion.stories.tsx +192 -0
- package/src/components/Accordion/accordion.tsx +13 -5
- package/src/components/Accordion/index.ts +5 -0
- package/src/components/AccountMenu/account-menu.anatomy.stories.tsx +117 -0
- package/src/components/AccountMenu/account-menu.principles.stories.tsx +99 -0
- package/src/components/AccountMenu/account-menu.spec.md +127 -0
- package/src/components/AccountMenu/account-menu.stories.tsx +65 -0
- package/src/components/AccountMenu/account-menu.tsx +194 -0
- package/src/components/AccountMenu/index.ts +5 -0
- package/src/components/AgentPanel/agent-fab.tsx +126 -0
- package/src/components/AgentPanel/agent-logo.tsx +491 -0
- package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +127 -0
- package/src/components/AgentPanel/agent-panel.css +59 -0
- package/src/components/AgentPanel/agent-panel.principles.stories.tsx +57 -0
- package/src/components/AgentPanel/agent-panel.spec.md +319 -0
- package/src/components/AgentPanel/agent-panel.stories.tsx +360 -0
- package/src/components/AgentPanel/agent-panel.tsx +1241 -0
- package/src/components/AgentPanel/index.ts +5 -0
- package/src/components/Alert/alert.anatomy.stories.tsx +241 -0
- package/src/components/Alert/alert.principles.stories.tsx +214 -0
- package/src/components/Alert/alert.spec.md +28 -26
- package/src/components/Alert/alert.stories.tsx +136 -0
- package/src/components/Alert/alert.tsx +19 -8
- package/src/components/Alert/index.ts +5 -0
- package/src/components/AppShell/_demo-helpers.tsx +107 -28
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +185 -0
- package/src/components/AppShell/app-shell.principles.stories.tsx +140 -0
- package/src/components/AppShell/app-shell.spec.md +84 -48
- package/src/components/AppShell/app-shell.stories.tsx +445 -0
- package/src/components/AppShell/app-shell.tsx +77 -24
- package/src/components/AppShell/index.ts +5 -0
- package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +208 -0
- package/src/components/AspectRatio/aspect-ratio.principles.stories.tsx +303 -0
- package/src/components/AspectRatio/aspect-ratio.spec.md +24 -12
- package/src/components/AspectRatio/aspect-ratio.stories.tsx +91 -0
- package/src/components/AspectRatio/aspect-ratio.tsx +6 -3
- package/src/components/AspectRatio/index.ts +5 -0
- package/src/components/Avatar/avatar.anatomy.stories.tsx +705 -0
- package/src/components/Avatar/avatar.principles.stories.tsx +249 -0
- package/src/components/Avatar/avatar.spec.md +66 -103
- package/src/components/Avatar/avatar.stories.tsx +156 -0
- package/src/components/Avatar/avatar.tsx +85 -64
- package/src/components/Avatar/index.ts +5 -0
- package/src/components/Badge/badge.anatomy.stories.tsx +591 -0
- package/src/components/Badge/badge.principles.stories.tsx +391 -0
- package/src/components/Badge/badge.spec.md +43 -23
- package/src/components/Badge/badge.stories.tsx +82 -0
- package/src/components/Badge/badge.tsx +38 -14
- package/src/components/Badge/index.ts +5 -0
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +462 -0
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +353 -0
- package/src/components/Breadcrumb/breadcrumb.spec.md +55 -43
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +381 -0
- package/src/components/Breadcrumb/breadcrumb.tsx +43 -86
- package/src/components/Breadcrumb/index.ts +5 -0
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +225 -0
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +255 -0
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +64 -36
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +124 -0
- package/src/components/BulkActionBar/bulk-action-bar.tsx +26 -18
- package/src/components/BulkActionBar/index.ts +5 -0
- package/src/components/Button/button-group.tsx +64 -21
- package/src/components/Button/button.anatomy.stories.tsx +729 -0
- package/src/components/Button/button.principles.stories.tsx +369 -0
- package/src/components/Button/button.spec.md +42 -39
- package/src/components/Button/button.stories.tsx +368 -0
- package/src/components/Button/button.tsx +109 -55
- package/src/components/Button/index.ts +6 -0
- package/src/components/Calendar/calendar.anatomy.stories.tsx +237 -0
- package/src/components/Calendar/calendar.principles.stories.tsx +152 -0
- package/src/components/Calendar/calendar.spec.md +80 -55
- package/src/components/Calendar/calendar.stories.tsx +108 -0
- package/src/components/Calendar/calendar.tsx +200 -134
- package/src/components/Calendar/index.ts +5 -0
- package/src/components/Carousel/carousel.anatomy.stories.tsx +517 -0
- package/src/components/Carousel/carousel.principles.stories.tsx +334 -0
- package/src/components/Carousel/carousel.spec.md +51 -15
- package/src/components/Carousel/carousel.stories.tsx +125 -0
- package/src/components/Carousel/carousel.tsx +139 -56
- package/src/components/Carousel/index.ts +5 -0
- package/src/components/Chart/chart.anatomy.stories.tsx +310 -0
- package/src/components/Chart/chart.principles.stories.tsx +437 -0
- package/src/components/Chart/chart.spec.md +24 -5
- package/src/components/Chart/chart.stories.tsx +263 -0
- package/src/components/Chart/chart.tsx +10 -3
- package/src/components/Chart/index.ts +5 -0
- package/src/components/Checkbox/checkbox-group.tsx +28 -16
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +614 -0
- package/src/components/Checkbox/checkbox.principles.stories.tsx +216 -0
- package/src/components/Checkbox/checkbox.spec.md +65 -42
- package/src/components/Checkbox/checkbox.stories.tsx +119 -0
- package/src/components/Checkbox/checkbox.tsx +189 -32
- package/src/components/Checkbox/index.ts +6 -0
- package/src/components/Chip/chip.anatomy.stories.tsx +442 -0
- package/src/components/Chip/chip.principles.stories.tsx +228 -0
- package/src/components/Chip/chip.spec.md +52 -40
- package/src/components/Chip/chip.stories.tsx +111 -0
- package/src/components/Chip/chip.tsx +130 -45
- package/src/components/Chip/index.ts +5 -0
- package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +177 -0
- package/src/components/CircularProgress/circular-progress.principles.stories.tsx +265 -0
- package/src/components/CircularProgress/circular-progress.spec.md +32 -32
- package/src/components/CircularProgress/circular-progress.stories.tsx +149 -0
- package/src/components/CircularProgress/circular-progress.tsx +5 -6
- package/src/components/CircularProgress/index.ts +5 -0
- package/src/components/Coachmark/coachmark-story-helpers.tsx +39 -0
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +356 -0
- package/src/components/Coachmark/coachmark.principles.stories.tsx +356 -0
- package/src/components/Coachmark/coachmark.spec.md +36 -29
- package/src/components/Coachmark/coachmark.stories.tsx +220 -0
- package/src/components/Coachmark/coachmark.tsx +36 -10
- package/src/components/Coachmark/index.ts +5 -0
- package/src/components/Combobox/combobox.anatomy.stories.tsx +926 -0
- package/src/components/Combobox/combobox.principles.stories.tsx +238 -0
- package/src/components/Combobox/combobox.spec.md +45 -16
- package/src/components/Combobox/combobox.stories.tsx +194 -0
- package/src/components/Combobox/combobox.tsx +278 -97
- package/src/components/Combobox/index.ts +5 -0
- package/src/components/Command/command.anatomy.stories.tsx +107 -0
- package/src/components/Command/command.principles.stories.tsx +86 -0
- package/src/components/Command/command.spec.md +33 -23
- package/src/components/Command/command.stories.tsx +312 -0
- package/src/components/Command/command.tsx +28 -12
- package/src/components/Command/index.ts +5 -0
- package/src/components/DataTable/active-editor-controller.ts +4 -3
- package/src/components/DataTable/cell-registry.tsx +161 -120
- package/src/components/DataTable/column-types.ts +14 -18
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +28 -12
- package/src/components/DataTable/data-table-filter-group.tsx +248 -0
- package/src/components/DataTable/data-table-filter-labels.ts +100 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +85 -448
- package/src/components/DataTable/data-table-filter-value-picker.tsx +254 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +26 -29
- package/src/components/DataTable/data-table-sort-manager.tsx +19 -11
- package/src/components/DataTable/data-table.anatomy.stories.tsx +522 -0
- package/src/components/DataTable/data-table.css +34 -8
- package/src/components/DataTable/data-table.principles.stories.tsx +270 -0
- package/src/components/DataTable/data-table.spec.md +186 -172
- package/src/components/DataTable/data-table.stories.tsx +2311 -0
- package/src/components/DataTable/data-table.tsx +678 -278
- package/src/components/DataTable/filter-operators.spec.md +269 -0
- package/src/components/DataTable/filter-operators.ts +1 -1
- package/src/components/DataTable/filter-tree.ts +194 -44
- package/src/components/DataTable/index.ts +8 -0
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +587 -0
- package/src/components/DateGrid/date-grid.principles.stories.tsx +344 -0
- package/src/components/DateGrid/date-grid.spec.md +46 -41
- package/src/components/DateGrid/date-grid.stories.tsx +204 -0
- package/src/components/DateGrid/date-grid.tsx +89 -28
- package/src/components/DateGrid/index.ts +5 -0
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +946 -0
- package/src/components/DatePicker/date-picker.principles.stories.tsx +205 -0
- package/src/components/DatePicker/date-picker.spec.md +61 -57
- package/src/components/DatePicker/date-picker.stories.tsx +364 -0
- package/src/components/DatePicker/date-picker.tsx +382 -198
- package/src/components/DatePicker/index.ts +5 -0
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +254 -0
- package/src/components/DescriptionList/description-list.principles.stories.tsx +309 -0
- package/src/components/DescriptionList/description-list.spec.md +35 -30
- package/src/components/DescriptionList/description-list.stories.tsx +113 -0
- package/src/components/DescriptionList/description-list.tsx +16 -14
- package/src/components/DescriptionList/index.ts +5 -0
- package/src/components/Dialog/dialog.anatomy.stories.tsx +485 -0
- package/src/components/Dialog/dialog.principles.stories.tsx +261 -0
- package/src/components/Dialog/dialog.spec.md +58 -32
- package/src/components/Dialog/dialog.stories.tsx +548 -0
- package/src/components/Dialog/dialog.tsx +81 -36
- package/src/components/Dialog/index.ts +5 -0
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +971 -0
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +341 -0
- package/src/components/DropdownMenu/dropdown-menu.spec.md +40 -22
- package/src/components/DropdownMenu/dropdown-menu.stories.tsx +276 -0
- package/src/components/DropdownMenu/dropdown-menu.tsx +153 -40
- package/src/components/DropdownMenu/index.ts +5 -0
- package/src/components/Empty/empty.anatomy.stories.tsx +275 -0
- package/src/components/Empty/empty.principles.stories.tsx +314 -0
- package/src/components/Empty/empty.spec.md +42 -42
- package/src/components/Empty/empty.stories.tsx +69 -0
- package/src/components/Empty/empty.tsx +23 -11
- package/src/components/Empty/index.ts +5 -0
- package/src/components/Field/field-context.ts +196 -4
- package/src/components/Field/field-controls.spec.md +161 -54
- package/src/components/Field/field-edit-keys.ts +66 -0
- package/src/components/Field/field-types.ts +71 -20
- package/src/components/Field/field-wrapper.tsx +139 -89
- package/src/components/Field/field.anatomy.stories.tsx +547 -0
- package/src/components/Field/field.principles.stories.tsx +255 -0
- package/src/components/Field/field.spec.md +76 -34
- package/src/components/Field/field.stories.tsx +751 -0
- package/src/components/Field/field.tsx +65 -12
- package/src/components/Field/form-validation.spec.md +60 -34
- package/src/components/Field/index.ts +6 -0
- package/src/components/Field/use-form-validation.ts +270 -0
- package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +119 -0
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +121 -0
- package/src/components/FieldControlGroup/field-control-group.spec.md +41 -19
- package/src/components/FieldControlGroup/field-control-group.stories.tsx +162 -0
- package/src/components/FieldControlGroup/field-control-group.tsx +13 -15
- package/src/components/FieldControlGroup/index.ts +5 -0
- package/src/components/FileItem/file-item.anatomy.stories.tsx +346 -0
- package/src/components/FileItem/file-item.principles.stories.tsx +245 -0
- package/src/components/FileItem/file-item.spec.md +133 -104
- package/src/components/FileItem/file-item.stories.tsx +289 -0
- package/src/components/FileItem/file-item.tsx +85 -39
- package/src/components/FileItem/index.ts +5 -0
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +446 -0
- package/src/components/FileUpload/file-upload.principles.stories.tsx +312 -0
- package/src/components/FileUpload/file-upload.spec.md +66 -24
- package/src/components/FileUpload/file-upload.stories.tsx +219 -0
- package/src/components/FileUpload/file-upload.tsx +138 -43
- package/src/components/FileUpload/index.ts +5 -0
- package/src/components/FileViewer/can-render-image.ts +15 -0
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1130 -0
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +636 -0
- package/src/components/FileViewer/file-viewer.spec.md +70 -58
- package/src/components/FileViewer/file-viewer.stories.tsx +417 -0
- package/src/components/FileViewer/file-viewer.tsx +157 -72
- package/src/components/FileViewer/image-renderer.tsx +38 -15
- package/src/components/FileViewer/index.ts +5 -0
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +151 -0
- package/src/components/HoverCard/hover-card.principles.stories.tsx +211 -0
- package/src/components/HoverCard/hover-card.spec.md +38 -28
- package/src/components/HoverCard/hover-card.stories.tsx +304 -0
- package/src/components/HoverCard/hover-card.tsx +23 -6
- package/src/components/HoverCard/index.ts +5 -0
- package/src/components/InlineEdit/index.ts +5 -0
- package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +250 -0
- package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
- package/src/components/InlineEdit/inline-edit.spec.md +186 -0
- package/src/components/InlineEdit/inline-edit.stories.tsx +261 -0
- package/src/components/InlineEdit/inline-edit.tsx +455 -0
- package/src/components/Input/index.ts +5 -0
- package/src/components/Input/input.anatomy.stories.tsx +780 -0
- package/src/components/Input/input.principles.stories.tsx +260 -0
- package/src/components/Input/input.spec.md +34 -26
- package/src/components/Input/input.stories.tsx +150 -0
- package/src/components/Input/input.tsx +102 -45
- package/src/components/LinkInput/index.ts +5 -0
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +748 -0
- package/src/components/LinkInput/link-input.principles.stories.tsx +182 -0
- package/src/components/LinkInput/link-input.spec.md +25 -7
- package/src/components/LinkInput/link-input.stories.tsx +133 -0
- package/src/components/LinkInput/link-input.tsx +89 -66
- package/src/components/Menu/index.ts +5 -0
- package/src/components/Menu/menu-item.anatomy.stories.tsx +780 -0
- package/src/components/Menu/menu-item.principles.stories.tsx +81 -0
- package/src/components/Menu/menu-item.spec.md +55 -32
- package/src/components/Menu/menu-item.stories.tsx +242 -0
- package/src/components/Menu/menu-item.tsx +71 -12
- package/src/components/Notice/index.ts +5 -0
- package/src/components/Notice/notice.anatomy.stories.tsx +614 -0
- package/src/components/Notice/notice.principles.stories.tsx +102 -0
- package/src/components/Notice/notice.spec.md +39 -18
- package/src/components/Notice/notice.stories.tsx +257 -0
- package/src/components/Notice/notice.tsx +62 -16
- package/src/components/NumberInput/index.ts +5 -0
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +822 -0
- package/src/components/NumberInput/number-input.principles.stories.tsx +206 -0
- package/src/components/NumberInput/number-input.spec.md +35 -16
- package/src/components/NumberInput/number-input.stories.tsx +167 -0
- package/src/components/NumberInput/number-input.tsx +65 -31
- package/src/components/OverflowIndicator/index.ts +5 -0
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +550 -0
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +76 -0
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +36 -26
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +222 -0
- package/src/components/OverflowIndicator/overflow-indicator.tsx +22 -7
- package/src/components/Pagination/index.ts +5 -0
- package/src/components/Pagination/pagination.anatomy.stories.tsx +144 -0
- package/src/components/Pagination/pagination.principles.stories.tsx +81 -0
- package/src/components/Pagination/pagination.spec.md +150 -0
- package/src/components/Pagination/pagination.stories.tsx +97 -0
- package/src/components/Pagination/pagination.tsx +263 -0
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
- package/src/components/PeoplePicker/index.ts +5 -0
- package/src/components/PeoplePicker/people-picker-helpers.ts +5 -5
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +437 -0
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +196 -0
- package/src/components/PeoplePicker/people-picker.spec.md +97 -40
- package/src/components/PeoplePicker/people-picker.stories.tsx +245 -0
- package/src/components/PeoplePicker/people-picker.tsx +225 -108
- package/src/components/PeoplePicker/person-display.tsx +83 -47
- package/src/components/Popover/index.ts +5 -0
- package/src/components/Popover/popover.anatomy.stories.tsx +282 -0
- package/src/components/Popover/popover.principles.stories.tsx +316 -0
- package/src/components/Popover/popover.spec.md +41 -31
- package/src/components/Popover/popover.stories.tsx +120 -0
- package/src/components/Popover/popover.tsx +106 -47
- package/src/components/ProfileCard/index.ts +5 -0
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +493 -0
- package/src/components/ProfileCard/profile-card.principles.stories.tsx +225 -0
- package/src/components/ProfileCard/profile-card.spec.md +189 -0
- package/src/components/ProfileCard/profile-card.stories.tsx +57 -0
- package/src/components/{NameCard/name-card.tsx → ProfileCard/profile-card.tsx} +66 -39
- package/src/components/ProgressBar/index.ts +5 -0
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +441 -0
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +326 -0
- package/src/components/ProgressBar/progress-bar.spec.md +25 -21
- package/src/components/ProgressBar/progress-bar.stories.tsx +133 -0
- package/src/components/ProgressBar/progress-bar.tsx +6 -23
- package/src/components/README.md +5 -4
- package/src/components/RadioGroup/index.ts +5 -0
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +672 -0
- package/src/components/RadioGroup/radio-group.principles.stories.tsx +163 -0
- package/src/components/RadioGroup/radio-group.spec.md +15 -9
- package/src/components/RadioGroup/radio-group.stories.tsx +204 -0
- package/src/components/RadioGroup/radio-group.tsx +219 -67
- package/src/components/Rating/index.ts +5 -0
- package/src/components/Rating/rating.anatomy.stories.tsx +498 -0
- package/src/components/Rating/rating.principles.stories.tsx +296 -0
- package/src/components/Rating/rating.spec.md +41 -29
- package/src/components/Rating/rating.stories.tsx +119 -0
- package/src/components/Rating/rating.tsx +37 -18
- package/src/components/ScrollArea/index.ts +5 -0
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +451 -0
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +331 -0
- package/src/components/ScrollArea/scroll-area.spec.md +24 -22
- package/src/components/ScrollArea/scroll-area.stories.tsx +247 -0
- package/src/components/ScrollArea/scroll-area.tsx +24 -7
- package/src/components/SegmentedControl/index.ts +5 -0
- package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +295 -0
- package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +284 -0
- package/src/components/SegmentedControl/segmented-control.spec.md +38 -39
- package/src/components/SegmentedControl/segmented-control.stories.tsx +37 -0
- package/src/components/SegmentedControl/segmented-control.tsx +44 -24
- package/src/components/Select/index.ts +5 -0
- package/src/components/Select/select.anatomy.stories.tsx +834 -0
- package/src/components/Select/select.principles.stories.tsx +312 -0
- package/src/components/Select/select.spec.md +99 -39
- package/src/components/Select/select.stories.tsx +273 -0
- package/src/components/Select/select.tsx +389 -97
- package/src/components/SelectMenu/index.ts +5 -0
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +830 -0
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +106 -0
- package/src/components/SelectMenu/select-menu.spec.md +51 -32
- package/src/components/SelectMenu/select-menu.stories.tsx +143 -0
- package/src/components/SelectMenu/select-menu.tsx +276 -33
- package/src/components/SelectionControl/boolean-value.tsx +39 -0
- package/src/components/SelectionControl/index.ts +6 -0
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +580 -0
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +77 -0
- package/src/components/SelectionControl/selection-item.spec.md +30 -16
- package/src/components/SelectionControl/selection-item.stories.tsx +137 -0
- package/src/components/SelectionControl/selection-item.tsx +8 -2
- package/src/components/Separator/index.ts +5 -0
- package/src/components/Separator/separator.anatomy.stories.tsx +125 -0
- package/src/components/Separator/separator.principles.stories.tsx +141 -0
- package/src/components/Separator/separator.spec.md +15 -9
- package/src/components/Separator/separator.stories.tsx +106 -0
- package/src/components/Separator/separator.tsx +2 -2
- package/src/components/Sheet/index.ts +5 -0
- package/src/components/Sheet/sheet.anatomy.stories.tsx +269 -0
- package/src/components/Sheet/sheet.principles.stories.tsx +353 -0
- package/src/components/Sheet/sheet.spec.md +16 -17
- package/src/components/Sheet/sheet.stories.tsx +172 -0
- package/src/components/Sheet/sheet.tsx +24 -14
- package/src/components/Sidebar/index.ts +5 -0
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +776 -0
- package/src/components/Sidebar/sidebar.principles.stories.tsx +507 -0
- package/src/components/Sidebar/sidebar.spec.md +65 -62
- package/src/components/Sidebar/sidebar.stories.tsx +535 -0
- package/src/components/Sidebar/sidebar.tsx +134 -57
- package/src/components/Skeleton/index.ts +5 -0
- package/src/components/Skeleton/skeleton.anatomy.stories.tsx +145 -0
- package/src/components/Skeleton/skeleton.principles.stories.tsx +234 -0
- package/src/components/Skeleton/skeleton.spec.md +15 -14
- package/src/components/Skeleton/skeleton.stories.tsx +134 -0
- package/src/components/Skeleton/skeleton.tsx +2 -2
- package/src/components/Slider/index.ts +5 -0
- package/src/components/Slider/slider.anatomy.stories.tsx +237 -0
- package/src/components/Slider/slider.principles.stories.tsx +250 -0
- package/src/components/Slider/slider.spec.md +66 -118
- package/src/components/Slider/slider.stories.tsx +115 -0
- package/src/components/Slider/slider.tsx +83 -26
- package/src/components/Steps/index.ts +5 -0
- package/src/components/Steps/steps.anatomy.stories.tsx +448 -0
- package/src/components/Steps/steps.principles.stories.tsx +300 -0
- package/src/components/Steps/steps.spec.md +91 -74
- package/src/components/Steps/steps.stories.tsx +306 -0
- package/src/components/Steps/steps.tsx +99 -37
- package/src/components/Switch/index.ts +5 -0
- package/src/components/Switch/switch.anatomy.stories.tsx +227 -0
- package/src/components/Switch/switch.principles.stories.tsx +177 -0
- package/src/components/Switch/switch.spec.md +53 -24
- package/src/components/Switch/switch.stories.tsx +95 -0
- package/src/components/Switch/switch.tsx +176 -43
- package/src/components/Tabs/index.ts +5 -0
- package/src/components/Tabs/tabs-inline-action-geometry.ts +94 -0
- package/src/components/Tabs/tabs.anatomy.stories.tsx +424 -0
- package/src/components/Tabs/tabs.principles.stories.tsx +291 -0
- package/src/components/Tabs/tabs.spec.md +58 -69
- package/src/components/Tabs/tabs.stories.tsx +257 -0
- package/src/components/Tabs/tabs.tsx +262 -82
- package/src/components/Tag/index.ts +5 -0
- package/src/components/Tag/tag.anatomy.stories.tsx +667 -0
- package/src/components/Tag/tag.principles.stories.tsx +270 -0
- package/src/components/Tag/tag.spec.md +112 -100
- package/src/components/Tag/tag.stories.tsx +88 -0
- package/src/components/Tag/tag.tsx +120 -80
- package/src/components/Textarea/index.ts +5 -0
- package/src/components/Textarea/textarea.anatomy.stories.tsx +310 -0
- package/src/components/Textarea/textarea.principles.stories.tsx +192 -0
- package/src/components/Textarea/textarea.spec.md +35 -16
- package/src/components/Textarea/textarea.stories.tsx +57 -0
- package/src/components/Textarea/textarea.tsx +154 -83
- package/src/components/TimePicker/index.ts +5 -0
- package/src/components/TimePicker/time-columns.tsx +15 -3
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +283 -0
- package/src/components/TimePicker/time-picker.principles.stories.tsx +133 -0
- package/src/components/TimePicker/time-picker.spec.md +58 -52
- package/src/components/TimePicker/time-picker.stories.tsx +193 -0
- package/src/components/TimePicker/time-picker.tsx +119 -60
- package/src/components/Toast/index.ts +5 -0
- package/src/components/Toast/toast.anatomy.stories.tsx +328 -0
- package/src/components/Toast/toast.principles.stories.tsx +216 -0
- package/src/components/Toast/toast.spec.md +26 -16
- package/src/components/Toast/toast.stories.tsx +241 -0
- package/src/components/Toast/toast.tsx +101 -23
- package/src/components/Tooltip/index.ts +5 -0
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +422 -0
- package/src/components/Tooltip/tooltip.principles.stories.tsx +204 -0
- package/src/components/Tooltip/tooltip.spec.md +37 -23
- package/src/components/Tooltip/tooltip.stories.tsx +82 -0
- package/src/components/Tooltip/tooltip.tsx +58 -12
- package/src/components/TreeView/index.ts +5 -0
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +436 -0
- package/src/components/TreeView/tree-view.principles.stories.tsx +223 -0
- package/src/components/TreeView/tree-view.spec.md +103 -54
- package/src/components/TreeView/tree-view.stories.tsx +365 -0
- package/src/components/TreeView/tree-view.tsx +501 -58
- package/src/hooks/use-controllable.ts +7 -2
- package/src/hooks/use-is-touch-device.ts +8 -1
- package/src/hooks/use-overflow-items.ts +10 -6
- package/src/hooks/use-truncated.ts +111 -0
- package/src/index.ts +651 -71
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +21 -1
- package/src/patterns/README.md +20 -16
- package/src/patterns/action-bar/action-bar.spec.md +63 -45
- package/src/patterns/action-bar/action-bar.stories.tsx +619 -0
- package/src/patterns/element-anatomy/element-anatomy.spec.md +17 -13
- package/src/patterns/element-anatomy/index.ts +6 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +33 -22
- package/src/patterns/element-anatomy/item-anatomy.spec.md +108 -79
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +1648 -0
- package/src/patterns/element-anatomy/item-anatomy.tsx +147 -56
- package/src/patterns/element-anatomy/truncated-text.spec.md +68 -0
- package/src/patterns/element-anatomy/truncated-text.tsx +61 -0
- package/src/patterns/header-canonical/chrome-header.tsx +26 -6
- package/src/patterns/header-canonical/header-canonical.css +3 -4
- package/src/patterns/header-canonical/header-canonical.spec.md +96 -42
- package/src/patterns/header-canonical/header-canonical.stories.tsx +257 -0
- package/src/patterns/header-canonical/index.ts +5 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +36 -15
- package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +139 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +1 -1
- package/src/patterns/horizontal-overflow/index.ts +5 -0
- package/src/patterns/overlay-surface/index.ts +5 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +94 -58
- package/src/patterns/overlay-surface/overlay-surface.stories.tsx +132 -0
- package/src/patterns/overlay-surface/overlay-surface.tsx +37 -18
- package/src/patterns/resize-handle/index.ts +5 -0
- package/src/patterns/resize-handle/resize-handle.spec.md +22 -13
- package/src/patterns/resize-handle/resize-handle.stories.tsx +73 -0
- package/src/patterns/resize-handle/resize-handle.tsx +13 -18
- package/src/story-governance/category-matrix.json +132 -0
- package/src/story-governance/category-matrix.ts +55 -0
- package/src/styles/base.css +99 -0
- package/src/styles/tokens.css +14 -0
- package/src/tokens/README.md +10 -5
- package/src/tokens/categorical-color.ts +164 -0
- package/src/tokens/color/color.spec.md +95 -72
- package/src/tokens/color/color.stories.tsx +403 -0
- package/src/tokens/color/primitives.css +23 -7
- package/src/tokens/color/semantic.css +75 -21
- package/src/tokens/density/density.spec.md +33 -30
- package/src/tokens/density/density.stories.tsx +254 -0
- package/src/tokens/elevation/elevation.spec.md +11 -14
- package/src/tokens/elevation/elevation.stories.tsx +99 -0
- package/src/tokens/layoutSpace/layoutSpace.css +1 -1
- package/src/tokens/layoutSpace/layoutSpace.spec.md +44 -31
- package/src/tokens/layoutSpace/layoutSpace.stories.tsx +76 -0
- package/src/tokens/motion/motion.css +49 -20
- package/src/tokens/motion/motion.spec.md +45 -21
- package/src/tokens/motion/motion.stories.tsx +196 -0
- package/src/tokens/motion/motion.ts +8 -7
- package/src/tokens/motion/overlay-motion.ts +26 -0
- package/src/tokens/opacity/opacity.spec.md +15 -20
- package/src/tokens/opacity/opacity.stories.tsx +66 -0
- package/src/tokens/orphan-tokens.spec.md +22 -11
- package/src/tokens/radius/radius.spec.md +14 -11
- package/src/tokens/radius/radius.stories.tsx +87 -0
- package/src/tokens/token-system.spec.md +241 -0
- package/src/tokens/typography/typography.css +1 -1
- package/src/tokens/typography/typography.spec.md +12 -8
- package/src/tokens/typography/typography.stories.tsx +134 -0
- package/src/tokens/uiSize/icon-size.ts +3 -4
- package/src/tokens/uiSize/uiSize.css +60 -1
- package/src/tokens/uiSize/uiSize.spec.md +61 -32
- package/src/tokens/uiSize/uiSize.stories.tsx +106 -0
- package/src/tokens/utility-registry.json +426 -0
- package/src/tokens/utility-registry.schema.json +409 -0
- package/tools/README.md +9 -0
- package/tools/codemods/cli.mjs +93 -0
- package/tools/codemods/index.mjs +582 -0
- package/tools/shared/safe-filesystem.mjs +371 -0
- package/tools/visual-baseline/cli.mjs +97 -0
- package/tools/visual-baseline/index.mjs +522 -0
- package/dist/components/NameCard/name-card.d.ts.map +0 -1
- package/dist/components/NameCard/name-card.js.map +0 -1
- package/ds-canonical/commands/gov-status.md +0 -79
- package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +0 -68
- package/ds-canonical/hooks/check_chrome_header_handcraft.sh +0 -70
- package/ds-canonical/hooks/check_header_with_tabs_border.sh +0 -87
- package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +0 -66
- package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +0 -15
- package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +0 -187
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +0 -74
- package/ds-canonical/skills/design-system-audit/references/spec-template.md +0 -66
- package/src/components/NameCard/name-card.spec.md +0 -171
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
2
|
// code-quality-allow: file-size — foundational composite — 拆檔會複雜化 context / ref / state 同步
|
|
3
|
+
//
|
|
4
|
+
// ── 檔案結構(2026-05-03 split matrix;2026-06-11 自 data-table.spec.md 遷入,Level 4 code home)──
|
|
5
|
+
// 每個檔過 M21 / M17 / Rule-of-3 三 test:
|
|
6
|
+
// - data-table.tsx(主,foundational)
|
|
7
|
+
// - data-table-filter-panel.tsx + data-table-sort-manager.tsx + data-table-column-visibility-panel.tsx(panel state 隔離)
|
|
8
|
+
// - data-table-filter-group.tsx + data-table-filter-value-picker.tsx(@internal;2026-07-14 filter panel
|
|
9
|
+
// 過 800 hard cap 拆檔 — row/nested-group renderer + ValueShape picker,只被 panel 消費)
|
|
10
|
+
// - cell-registry.tsx(column type → cell view / edit 解析 SSOT)
|
|
11
|
+
// - data-table-interaction-layer.tsx + active-editor-controller.ts(spreadsheet overlay + portal editor)
|
|
12
|
+
// - column-types.ts + filter-operators.ts(✓ Rule-of-3 SSOT,3+ consumer)
|
|
13
|
+
// - filter-tree.ts(pure data + eval,test isolation)
|
|
14
|
+
// - lib/column-meta.ts(Internal SSOT,消 5 處 `(col as any)`)
|
|
15
|
+
// - + stories / spec / css
|
|
16
|
+
// M21 retract:filter-value-picker.tsx 1 consumer → 2026-05-03 inline 回 panel(上列 2026-07-14
|
|
17
|
+
// @internal 拆檔非 M21 迴轉:非 public 抽象,file-size hard cap 驅動,consumer 仍只見 panel)。
|
|
3
18
|
import * as React from 'react'
|
|
4
19
|
import { createPortal } from 'react-dom'
|
|
5
20
|
import { Empty } from '@/design-system/components/Empty/empty'
|
|
21
|
+
// L5 分頁(2026-07-06):Pagination = 分頁完整功能 SSOT(頁碼 + showTotal + 每頁筆數選單
|
|
22
|
+
// 全 own 在 Pagination;共用模式,Ant Table 消費 Pagination 同派)—— DataTable 只轉發 config
|
|
23
|
+
import { Pagination } from '@/design-system/components/Pagination/pagination'
|
|
6
24
|
import {
|
|
7
25
|
useReactTable,
|
|
8
26
|
getCoreRowModel,
|
|
9
27
|
getSortedRowModel,
|
|
10
28
|
getExpandedRowModel,
|
|
29
|
+
getPaginationRowModel,
|
|
11
30
|
flexRender,
|
|
12
31
|
type ColumnDef,
|
|
13
32
|
type SortingState,
|
|
@@ -24,12 +43,13 @@ import { DndContext, DragOverlay, useDraggable, useDroppable, useDndContext, poi
|
|
|
24
43
|
import { cn } from '@/lib/utils'
|
|
25
44
|
import { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'
|
|
26
45
|
import { dragSourceStyle, dropIndicatorRow, dropIndicatorColumn, dragActiveCursor, isReorderNoop, reconstructFullRowGhost, snapToCursorModifier } from '@/design-system/lib/drag-visual'
|
|
27
|
-
import { nakedCellEditableDisplayHover } from '@/design-system/components/Field/field-wrapper'
|
|
46
|
+
import { nakedCellEditableDisplayHover, fieldDisplayTextClass } from '@/design-system/components/Field/field-wrapper'
|
|
28
47
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/design-system/components/Tooltip/tooltip'
|
|
48
|
+
import { TruncatedText } from '@/design-system/patterns/element-anatomy/truncated-text'
|
|
29
49
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '@/design-system/components/DropdownMenu/dropdown-menu'
|
|
30
50
|
import { ItemInlineActionButton } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
31
51
|
import { columnTypeDefaults, type ColumnType } from './column-types'
|
|
32
|
-
import { resolveCellComponent } from './cell-registry'
|
|
52
|
+
import { resolveCellComponent, type CellComponentProps } from './cell-registry'
|
|
33
53
|
import { DataTableInteractionLayer } from './data-table-interaction-layer'
|
|
34
54
|
import { Checkbox } from '@/design-system/components/Checkbox/checkbox'
|
|
35
55
|
import { RadioGroupItem } from '@/design-system/components/RadioGroup/radio-group'
|
|
@@ -56,10 +76,17 @@ type TableSize = 'sm' | 'md' | 'lg'
|
|
|
56
76
|
export interface DataTableProps<TData>
|
|
57
77
|
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>,
|
|
58
78
|
VariantProps<typeof dataTableVariants> {
|
|
79
|
+
// any-allow: TanStack ColumnDef TValue idiom(per-column value 型別異質,官方範例同)— 對齊本 module 既有 escape 紀律
|
|
59
80
|
columns: ColumnDef<TData, any>[]
|
|
60
81
|
data: TData[]
|
|
61
82
|
size?: TableSize
|
|
62
83
|
autoRowHeight?: boolean
|
|
84
|
+
/**
|
|
85
|
+
* 容器高度。預設 '400px'(body 內捲動);'auto' = 自然高度(hug rows);'100%' = fill parent。
|
|
86
|
+
* L5 分頁(2026-07-06):啟用 `pagination` 且未顯式傳 height 時預設改 'auto' —— 分頁的
|
|
87
|
+
* 導覽通道是頁碼,再疊 body 內捲動 = 雙重導覽(一頁 20 筆只露 10 筆);對齊 Ant Table
|
|
88
|
+
* 無預設高度罩、`scroll.y` 顯式選配的慣例。顯式傳 height 照舊尊重(分頁 + 頁內捲動可並用)。
|
|
89
|
+
*/
|
|
63
90
|
height?: string
|
|
64
91
|
overscan?: number
|
|
65
92
|
emptyState?: React.ReactNode
|
|
@@ -70,7 +97,7 @@ export interface DataTableProps<TData>
|
|
|
70
97
|
/**
|
|
71
98
|
* Issue 9 cell error system(2026-05-10)。
|
|
72
99
|
*
|
|
73
|
-
* Map of `${rowId}:${colId}` → error message(string | string[])。Cell
|
|
100
|
+
* Map of `${rowId}:${colId}` → error message(string | string[])。Cell view mode 在 content
|
|
74
101
|
* 下方渲 `text-body text-error` 訊息,gap-1 spacing。Multi-error 用 array → ul / li 分行渲。
|
|
75
102
|
*
|
|
76
103
|
* **使用建議**:
|
|
@@ -92,7 +119,8 @@ export interface DataTableProps<TData>
|
|
|
92
119
|
* Slice D Step 1B(2026-05-10):啟用 spreadsheet-grade interaction overlay。
|
|
93
120
|
* Default false(backward-compat)。Enable 後 hover/editor/selected/range 由
|
|
94
121
|
* `DataTableInteractionLayer` overlay 統一畫,per `.claude/planning/datatable-spreadsheet-rfc.md`。
|
|
95
|
-
*
|
|
122
|
+
* 現況:hover ring + selection ring + active editor host 三個 sub-layer
|
|
123
|
+
* (詳 `data-table-interaction-layer.tsx` 檔頭)。
|
|
96
124
|
*/
|
|
97
125
|
experimentalSpreadsheetOverlay?: boolean
|
|
98
126
|
/**
|
|
@@ -108,32 +136,33 @@ export interface DataTableProps<TData>
|
|
|
108
136
|
* Slice D Step 4(spreadsheet semantics,2026-05-10 user 拍板 + codex Layer B Q2.1 confirm):
|
|
109
137
|
* Excel-like cell selection:click 1=select / click 2=edit / Shift+click=range。
|
|
110
138
|
* Default false opt-in(per codex「DataTable is not a spreadsheet」既有原則 +
|
|
111
|
-
* data-table.principles.stories.tsx
|
|
139
|
+
* data-table.principles.stories.tsx「不是試算表」principle story)。
|
|
112
140
|
* Enable 後 inlineEdit cell click 行為:
|
|
113
141
|
* - Plain click → setSelectedCellId,**不**進 edit mode
|
|
114
142
|
* - Click on already-selected → enter edit
|
|
115
143
|
* - Shift+click → extend range from anchor
|
|
116
144
|
* - Double-click / Enter / F2 / printable(deferred) → enter edit on selected
|
|
117
145
|
* - Click empty area → clear selection
|
|
118
|
-
* 視覺:
|
|
119
|
-
*
|
|
146
|
+
* 視覺:selection ring 1px `--primary`(layer `CELL_RING_STYLES.selected`);range 視覺
|
|
147
|
+
* = cell-bg `--primary-subtle`(`[data-range-cell]` CSS),outer ring 已 2026-05-10 retire
|
|
148
|
+
* — per user「不要 dash 直接實的就好」+ codex Q2.2 token。
|
|
120
149
|
*/
|
|
121
150
|
spreadsheetMode?: boolean
|
|
122
151
|
|
|
123
152
|
// ── L2 Selection(see data-table.spec.md「L2 選取」)──
|
|
124
|
-
/**
|
|
125
|
-
selection?: string[]
|
|
126
|
-
/** 預設選取(uncontrolled) */
|
|
127
|
-
defaultSelection?: string[]
|
|
128
|
-
/** Selection 變更 callback */
|
|
129
|
-
onSelectionChange?: (next:
|
|
153
|
+
/** 已選列(controlled)。傳 string[] = include shorthand;傳 DataTableSelection 支援反向選取(all + excluded) */
|
|
154
|
+
selection?: string[] | DataTableSelection
|
|
155
|
+
/** 預設選取(uncontrolled);同上接受 string[] 或 DataTableSelection */
|
|
156
|
+
defaultSelection?: string[] | DataTableSelection
|
|
157
|
+
/** Selection 變更 callback(emit DataTableSelection union;include / all 兩模型) */
|
|
158
|
+
onSelectionChange?: (next: DataTableSelection) => void
|
|
130
159
|
/** 是否啟用 selection / 模式;true 等同 'multi' */
|
|
131
160
|
selectable?: boolean | 'single' | 'multi'
|
|
132
161
|
/** Row 是否可選(disabled rows 只 disable checkbox,row 內容正常 render) */
|
|
133
162
|
isRowSelectable?: (row: TData) => boolean
|
|
134
163
|
/** 取 row 唯一 ID(selection 用);default `(row, index) => String(index)` */
|
|
135
164
|
getRowId?: (row: TData, index: number) => string
|
|
136
|
-
/** Checkbox aria-label fallback;default `'
|
|
165
|
+
/** Checkbox aria-label fallback;default `'選取此列'` */
|
|
137
166
|
getRowAriaLabel?: (row: TData) => string
|
|
138
167
|
/** Filter 後 hidden selected rows 是否保留(default false,對齊 Material/AG Grid 共識) */
|
|
139
168
|
preserveSelectionOnFilter?: boolean
|
|
@@ -175,8 +204,8 @@ export interface DataTableProps<TData>
|
|
|
175
204
|
*
|
|
176
205
|
* **v2(2026-05-05)修正**:
|
|
177
206
|
* - Virtualizer × transform:被拖 row 略過 `measureElement`(透過 SortableRowCtx 廣播 active id),避免 transform 干擾測量
|
|
178
|
-
* - 3-panel mirror sync
|
|
179
|
-
* - Cross-parent drop:nested 全 row
|
|
207
|
+
* - 3-panel mirror sync:primary region 呼叫 `useDraggable` + `useDroppable`;mirror region 只 `useDroppable`(v15.4 split),isDragging 由 `useDndContext` active.id 同步 → 三 region 視覺一致
|
|
208
|
+
* - Cross-parent drop:nested 全 row 各自 `useDroppable`,自訂 collisionDetection 過濾出「同 parent siblings」;cross-parent over → 不觸發,handle cursor `not-allowed`
|
|
180
209
|
*
|
|
181
210
|
* 詳 `data-table.spec.md`「L4 Row drag」段。
|
|
182
211
|
*/
|
|
@@ -222,19 +251,42 @@ export interface DataTableProps<TData>
|
|
|
222
251
|
* @param position 'before' | 'after'
|
|
223
252
|
*/
|
|
224
253
|
onColumnReorder?: (sourceId: string, targetId: string, position: 'before' | 'after') => void
|
|
254
|
+
/**
|
|
255
|
+
* L5 分頁(2026-07-06):`true` 或 config 物件啟用——內部接 TanStack `getPaginationRowModel`,
|
|
256
|
+
* 表格下方渲染分頁列(消費 `<Pagination>` 獨立元件,間距 tight、頁碼靠右)。
|
|
257
|
+
* 啟用時虛擬滾動自動關閉(TanStack 官方:互斥替代策略)。v1 = client-side only。
|
|
258
|
+
* 詳 data-table.spec.md「L5:分頁」段。
|
|
259
|
+
*/
|
|
260
|
+
pagination?: boolean | DataTablePaginationOptions
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** L5 分頁 config(頁碼 1-based 對外,對齊 Pagination / Ant;詳 data-table.spec.md「L5:分頁」段) */
|
|
264
|
+
export interface DataTablePaginationOptions {
|
|
265
|
+
/** 每頁筆數(預設 20) */
|
|
266
|
+
pageSize?: number
|
|
267
|
+
/** 每頁筆數選項;傳了才渲染「每頁 N 筆」Select(消費既有 Select size="sm") */
|
|
268
|
+
pageSizeOptions?: number[]
|
|
269
|
+
/** 左側「共 N 筆」文字(opt-in,= Ant showTotal 邏輯;數源 = filter 後全集 getPrePaginationRowModel,非 selection all-mode 的 server-side 全集數 M — 那是 consumer 自持) */
|
|
270
|
+
showTotal?: boolean
|
|
271
|
+
/** 當前頁(1-based,controlled;不傳 = uncontrolled) */
|
|
272
|
+
page?: number
|
|
273
|
+
/** uncontrolled 初始頁(1-based,預設 1) */
|
|
274
|
+
defaultPage?: number
|
|
275
|
+
onPageChange?: (page: number) => void
|
|
276
|
+
onPageSizeChange?: (pageSize: number) => void
|
|
225
277
|
}
|
|
226
278
|
|
|
227
279
|
// ── Cell Rendering(Phase C 2026-05-05 — type-keyed registry SSOT)─────────────
|
|
228
280
|
//
|
|
229
281
|
// 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch
|
|
230
282
|
// 已 collapse 為單一 `cellRegistry`(./cell-registry.ts)— 每個 type → 一個 cell component,
|
|
231
|
-
// 同時處理
|
|
283
|
+
// 同時處理 view + edit mode(底層 Field control 的 mode prop)。對齊 M17 SSOT consolidation。
|
|
232
284
|
//
|
|
233
285
|
// 對齊 Notion / Airtable type-aware inline edit canonical(詳 spec §十二):
|
|
234
286
|
// - string / number / currency:cell click → inline edit
|
|
235
287
|
// - date / time / select / multiSelect / person / multiPerson:cell click → 進 edit mode
|
|
236
288
|
// - boolean:不分 read/edit mode,直接 `<Checkbox>` 點即 toggle + commit
|
|
237
|
-
// - url:read = LinkInput
|
|
289
|
+
// - url:read = LinkInput view + hover Pencil button,click Pencil 才進 edit mode
|
|
238
290
|
//
|
|
239
291
|
// Cell id format: `${rowId}__${columnId}`(編輯狀態 keying)
|
|
240
292
|
// Commit: blur OR Enter OR overlay close → 呼叫 onCellCommit
|
|
@@ -251,6 +303,50 @@ const cellEditId = (rowId: string, colId: string) => `${rowId}__${colId}`
|
|
|
251
303
|
// (詳 ./data-table.css)— consumer 可走 CSS override 改值,不再 hard-code in TS。
|
|
252
304
|
// L2 selection 內部 column id(避免 magic string 重複)
|
|
253
305
|
const SELECT_COL_ID = '__select__'
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* L2 選取模型(discriminated union,2026-06-22 對齊 MUI X DataGrid v8
|
|
309
|
+
* rowSelectionModel { type: include | exclude, ids } + AG Grid selectAll + toggledNodes)。
|
|
310
|
+
*
|
|
311
|
+
* - mode==='include' (ids):只選 ids 列(預設;= 載入/可見列逐一選取)。
|
|
312
|
+
* - mode==='all' (excluded):全資料集(filter 後)選取,扣掉 excluded —— 反向選取(inverted)。
|
|
313
|
+
* 解決「全選 10k 筆只載 50 筆 → 無法列舉其餘 ID」:all 模式「選取 = 全集 − excluded」,
|
|
314
|
+
* 任何 toggle 都只是 excluded 的 add/remove,對任意順序封閉、O(1)、不需列舉未載入 ID。
|
|
315
|
+
*
|
|
316
|
+
* 計數(consumer):mode==='all' ? M − excluded.length : ids.length(M = consumer 自持的
|
|
317
|
+
* server-side / filter 後全集筆數;2026-07-13 D1 拍板:DataTable 不收 totalCount prop — DS 內部
|
|
318
|
+
* 零消費 no-op 已移除,計數本來就全由 consumer 端算)。
|
|
319
|
+
* 進入 all 模式:consumer 在「選取全部 M」hint 點擊時 setSelection({ mode: 'all', excluded: [] })。
|
|
320
|
+
*/
|
|
321
|
+
export type DataTableSelection =
|
|
322
|
+
| { mode: 'include'; ids: string[] }
|
|
323
|
+
| { mode: 'all'; excluded: string[] }
|
|
324
|
+
|
|
325
|
+
// 正規化:string[] shorthand → { mode:'include' }(向後相容既有 consumer 傳 ID 陣列)
|
|
326
|
+
function normalizeSelection(
|
|
327
|
+
input: string[] | DataTableSelection | undefined,
|
|
328
|
+
): DataTableSelection | undefined {
|
|
329
|
+
if (input === undefined) return undefined
|
|
330
|
+
if (Array.isArray(input)) return { mode: 'include', ids: input }
|
|
331
|
+
return input
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// union-aware「把 ids 設成 willSelect 狀態」純函式(對任意 toggle 順序封閉)
|
|
335
|
+
function applySelectIds(
|
|
336
|
+
sel: DataTableSelection,
|
|
337
|
+
ids: string[],
|
|
338
|
+
willSelect: boolean,
|
|
339
|
+
): DataTableSelection {
|
|
340
|
+
if (sel.mode === 'include') {
|
|
341
|
+
const set = new Set(sel.ids)
|
|
342
|
+
ids.forEach((id) => { if (willSelect) set.add(id); else set.delete(id) })
|
|
343
|
+
return { mode: 'include', ids: Array.from(set) }
|
|
344
|
+
}
|
|
345
|
+
// all 模式:選取 = 全集 − excluded → willSelect 移出 excluded;取消選取 加進 excluded
|
|
346
|
+
const set = new Set(sel.excluded)
|
|
347
|
+
ids.forEach((id) => { if (willSelect) set.delete(id); else set.add(id) })
|
|
348
|
+
return { mode: 'all', excluded: Array.from(set) }
|
|
349
|
+
}
|
|
254
350
|
const cellPadding: React.CSSProperties = { paddingBlock: 'var(--table-cell-py)', paddingInline: 'var(--table-cell-px)' }
|
|
255
351
|
const HEADER_BG = 'bg-muted'
|
|
256
352
|
|
|
@@ -298,67 +394,29 @@ function columnSizeStyle(
|
|
|
298
394
|
//
|
|
299
395
|
// **flex-basis: baseSize(2026-05-06 v14.2)**:把 baseSize 當 explicit basis(不是 `0%`)。
|
|
300
396
|
// 為什麼:flex item base = basis + padding(box-sizing: border-box content-box 行為)。前 `0%`
|
|
301
|
-
// basis → cell padding 變 base 一部分。
|
|
302
|
-
// 兩態 base 不同 → flex 重分配 → user 報「Price cell 進 edit 寬度縮 12px」
|
|
303
|
-
//
|
|
304
|
-
// explicit basis = baseSize 讓 padding 不參與 base 計算 →
|
|
397
|
+
// basis → cell padding 變 base 一部分。view(padding 12)vs edit(padding 0,Field 接管)
|
|
398
|
+
// 兩態 base 不同 → flex 重分配 → user 報「Price cell 進 edit 寬度縮 12px」
|
|
399
|
+
// (量測:Price view 130.5 → edit 118.5 = -12px)。
|
|
400
|
+
// explicit basis = baseSize 讓 padding 不參與 base 計算 → view↔edit 寬度穩定。
|
|
305
401
|
return { flex: `1 1 ${baseSize}px`, minWidth: baseSize, maxWidth: maxSize }
|
|
306
402
|
}
|
|
307
403
|
|
|
308
404
|
const SYSTEM_COL_IDS = new Set([SELECT_COL_ID, '__drag__', '__actions__'])
|
|
309
405
|
const isSystemColumn = (colId: string) => SYSTEM_COL_IDS.has(colId)
|
|
310
406
|
|
|
311
|
-
// ──
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const cb = roCallbacks.get(entry.target)
|
|
325
|
-
if (cb) cb(entry)
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
return sharedResizeObserver
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function observeShared(el: Element, cb: RoCallback): () => void {
|
|
332
|
-
const obs = getSharedRO()
|
|
333
|
-
roCallbacks.set(el, cb)
|
|
334
|
-
obs.observe(el)
|
|
335
|
-
return () => {
|
|
336
|
-
roCallbacks.delete(el)
|
|
337
|
-
obs.unobserve(el)
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function TruncateCell({ children, className }: { children: React.ReactNode; className?: string }) {
|
|
342
|
-
const ref = React.useRef<HTMLSpanElement>(null)
|
|
343
|
-
const [isTruncated, setIsTruncated] = React.useState(false)
|
|
344
|
-
React.useEffect(() => {
|
|
345
|
-
const el = ref.current
|
|
346
|
-
if (!el) return
|
|
347
|
-
const check = () => setIsTruncated(el.scrollWidth > el.clientWidth)
|
|
348
|
-
check()
|
|
349
|
-
return observeShared(el, check)
|
|
350
|
-
}, [])
|
|
351
|
-
const span = <span ref={ref} className={cn('truncate min-w-0', className)}>{children}</span>
|
|
352
|
-
if (!isTruncated) return span
|
|
353
|
-
return <Tooltip><TooltipTrigger asChild>{span}</TooltipTrigger><TooltipContent>{children}</TooltipContent></Tooltip>
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// ── L4 Row Drag: SortableRowContext (v2) ─────────────────────────────────────
|
|
357
|
-
// v2:每 region(left / center / right)各 mount 一次 SortableRowProvider — 多個 useSortable
|
|
358
|
-
// 共用同一 SortableContext / 同 row id 時,dnd-kit 內部以 id 為 unit 分發 transform / isDragging,
|
|
359
|
-
// 各 hook instance 取得相同值,因此 mirror region 自然跟動(v1 mirror static bug 修正)。
|
|
360
|
-
// listeners 仍只走 primary region(避免 pointer 事件雙重觸發);primary = left region 若存在否則 center。
|
|
361
|
-
// `invalidDrop`(cross-parent over)走 prop 廣播給 DragHandleCell 切 cursor-not-allowed。
|
|
407
|
+
// ── TruncatedText ── 2026-07-19:truncate+tooltip 引擎 + presentation 已抽成 SSOT primitive
|
|
408
|
+
// `patterns/element-anatomy/truncated-text`(`<TruncatedText>` 消費 `useTruncated` hook)。原 file-local
|
|
409
|
+
// shared RO(2026-04-22 D3 perf audit 的「全 DS 共用單一 RO」特性由 hook 承接)+ TruncateCell 已移除,
|
|
410
|
+
// 改用 `<TruncatedText tooltip={children} className={...}>`(display 預設 inline,保 cell baseline)。
|
|
411
|
+
// compound 欄位仍在 renderCellContent bypass(見下)—— 只 primitive string/number 走 TruncatedText。
|
|
412
|
+
|
|
413
|
+
// ── L4 Row Drag: SortableRowContext(v15 Path B;2026-07-14 JSDoc 對齊實作)──────
|
|
414
|
+
// 每 region(left / center / right)各 mount 一次 SortableRowProvider,依 role 分流(v15.4 split):
|
|
415
|
+
// primary → SourceRowProvider(useDraggable + useDroppable)= 唯一 drag source;
|
|
416
|
+
// mirror → MirrorRowProvider(useDroppable only),isDragging 走 useDndContext active.id 同步。
|
|
417
|
+
// 無 SortableContext / useSortable(v15.0 Path B 已砍,見檔頭 import 註解)。listeners 全走
|
|
418
|
+
// RowDragHandle Button(v15.6 button-only;row 本身不接 listeners)。primary = left region 若存在否則 center。
|
|
419
|
+
// `invalidDrop`(cross-parent over)走 prop 廣播給 RowDragHandle 切 cursor-not-allowed。
|
|
362
420
|
interface SortableRowCtxValue {
|
|
363
421
|
setNodeRef: (el: HTMLElement | null) => void
|
|
364
422
|
role: 'primary' | 'mirror'
|
|
@@ -384,10 +442,11 @@ interface SortableRowCtxValue {
|
|
|
384
442
|
}
|
|
385
443
|
const SortableRowCtx = React.createContext<SortableRowCtxValue | null>(null)
|
|
386
444
|
|
|
387
|
-
/** Per-region per-row
|
|
388
|
-
* 同 row.id 在 left/center/right 三 region 各 mount
|
|
389
|
-
*
|
|
390
|
-
*
|
|
445
|
+
/** Per-region per-row drag wrapper(v15.4 architectural split)。
|
|
446
|
+
* 同 row.id 在 left/center/right 三 region 各 mount 一次,但 hook mount tree 完全分離:
|
|
447
|
+
* primary → SourceRowProvider(useDraggable + useDroppable);mirror → MirrorRowProvider
|
|
448
|
+
* (useDroppable only,isDragging 由 useDndContext 同步)。activator / listeners 只給
|
|
449
|
+
* primary 的 RowDragHandle Button(v15.6 button-only);mirror 不提供避免雙觸發。 */
|
|
391
450
|
function SortableRowProvider(props: {
|
|
392
451
|
id: string
|
|
393
452
|
disabled?: boolean
|
|
@@ -427,7 +486,6 @@ function SourceRowProvider({
|
|
|
427
486
|
droppable.setNodeRef(el)
|
|
428
487
|
}, [draggable.setNodeRef, droppable.setNodeRef])
|
|
429
488
|
const isDragging = draggable.isDragging
|
|
430
|
-
const style: React.CSSProperties = { ...dragSourceStyle(isDragging) }
|
|
431
489
|
// a11y(2026-05-07 v15.10 codex P1 fix):button-only drag mode 下,row 本身不該成為
|
|
432
490
|
// keyboard tab stop。dnd-kit `useDraggable.attributes` 含 `role="button" tabIndex=0
|
|
433
491
|
// aria-roledescription="..."` 全給 activator 用,套到 row div 會讓每筆 row tabbable
|
|
@@ -435,10 +493,14 @@ function SourceRowProvider({
|
|
|
435
493
|
// **拆分**:rowAttributes 留空(row 是 passive container)/ handleAttributes 全給
|
|
436
494
|
// RowDragHandle Button(它是真 activator,Button 自帶 role/tabIndex 完全相容)。
|
|
437
495
|
const handleAttrs = draggable.attributes as unknown as Record<string, unknown>
|
|
438
|
-
|
|
496
|
+
// 2026-07-05 D3 perf fix:ctxValue useMemo — 原每 render 新 object,RowDragHandle 的
|
|
497
|
+
// useLayoutEffect deps [rowEl, ctx] 在每次 DataTableInner render 都 teardown/重掛
|
|
498
|
+
// MutationObserver + window scroll/resize listener(×每個 visible primary row)。
|
|
499
|
+
// memo 後 identity 只在 drag 相關值真變(isDragging / invalidDrop 等)時才換。
|
|
500
|
+
const ctxValue: SortableRowCtxValue = React.useMemo(() => ({
|
|
439
501
|
setNodeRef: setRefs,
|
|
440
502
|
role,
|
|
441
|
-
style,
|
|
503
|
+
style: { ...dragSourceStyle(isDragging) },
|
|
442
504
|
attributes: {},
|
|
443
505
|
isDragging,
|
|
444
506
|
// row 不接 listeners(button-only),baseRowDiv `{...(extra?.listeners ?? {})}` 自動 noop
|
|
@@ -451,7 +513,7 @@ function SourceRowProvider({
|
|
|
451
513
|
handleListeners: draggable.listeners as unknown as Record<string, unknown> | undefined,
|
|
452
514
|
handleAttributes: handleAttrs,
|
|
453
515
|
invalidDrop,
|
|
454
|
-
}
|
|
516
|
+
}), [setRefs, role, isDragging, draggable.setActivatorNodeRef, draggable.listeners, handleAttrs, invalidDrop])
|
|
455
517
|
return <SortableRowCtx.Provider value={ctxValue}>{children(ctxValue)}</SortableRowCtx.Provider>
|
|
456
518
|
}
|
|
457
519
|
|
|
@@ -479,7 +541,9 @@ function MirrorRowProvider({
|
|
|
479
541
|
const droppable = useDroppable({ id, disabled, data: { type: 'row' } })
|
|
480
542
|
const dndCtx = useDndContext()
|
|
481
543
|
const isDragging = dndCtx.active?.id === id
|
|
482
|
-
|
|
544
|
+
// 2026-07-05 D3 perf fix:ctxValue useMemo(同 SourceRowProvider — 消掉 RowDragHandle
|
|
545
|
+
// effect 的每 render observer/listener churn;mirror 雖不渲 handle,identity 穩定仍省下游 diff)
|
|
546
|
+
const ctxValue: SortableRowCtxValue = React.useMemo(() => ({
|
|
483
547
|
setNodeRef: droppable.setNodeRef,
|
|
484
548
|
role,
|
|
485
549
|
style: { ...dragSourceStyle(isDragging) },
|
|
@@ -491,18 +555,19 @@ function MirrorRowProvider({
|
|
|
491
555
|
handleListeners: undefined,
|
|
492
556
|
handleAttributes: {},
|
|
493
557
|
invalidDrop,
|
|
494
|
-
}
|
|
558
|
+
}), [droppable.setNodeRef, role, isDragging, invalidDrop])
|
|
495
559
|
return <SortableRowCtx.Provider value={ctxValue}>{children(ctxValue)}</SortableRowCtx.Provider>
|
|
496
560
|
}
|
|
497
561
|
|
|
498
|
-
/** DraggableHeaderCell — wrap header cell 跟 dnd-kit
|
|
562
|
+
/** DraggableHeaderCell — wrap header cell 跟 dnd-kit useDraggable + useDroppable 接軌
|
|
563
|
+
* (2026-05-06 v14.2;v15.0 Path B 改分離 hooks,無 SortableContext)。
|
|
499
564
|
*
|
|
500
565
|
* Why wrap-not-rewrite:`headerCellEl` 既有邏輯複雜(sort / resize / select column / right region 等),
|
|
501
|
-
* 改 inline
|
|
566
|
+
* 改 inline useDraggable/useDroppable 入侵性高。本 wrapper cloneElement 注入 ref / style / listeners → 既有 render
|
|
502
567
|
* 保持 untouched,單一職責 = 加 drag affordance。
|
|
503
568
|
*
|
|
504
569
|
* Behavior:
|
|
505
|
-
* -
|
|
570
|
+
* - useDraggable + useDroppable 永遠 call(Rules of Hooks)— `disabled=true` 時不啟動 listeners
|
|
506
571
|
* - `data: { type: 'column', columnId }` 餵 dnd-kit handleDragStart / handleDragEnd 區分 row/column drag
|
|
507
572
|
* - 注入 ref(setNodeRef)+ transform style + transition + opacity(drag 時 source invisible,DragOverlay 顯 ghost)
|
|
508
573
|
* - draggable 時注入 attributes + listeners + cursor:grab / `data-column-id` (DragOverlay snapshot 用)
|
|
@@ -546,12 +611,33 @@ function DraggableHeaderCell({
|
|
|
546
611
|
: dropIndicatorSide === 'after'
|
|
547
612
|
? dropIndicatorColumn.pseudoAfter
|
|
548
613
|
: ''
|
|
614
|
+
// dnd-kit KeyboardSensor 的 activator = listeners.onKeyDown,掛在整個 header cell 上(column
|
|
615
|
+
// 無獨立 activator node,不像 row drag 的 button-only handle)。巢狀互動 descendant(more-menu
|
|
616
|
+
// 按鈕 / resize separator / 排序 chevron)的 Enter/Space 冒泡到此 → dnd-kit preventDefault 啟動
|
|
617
|
+
// 欄位拖曳,吃掉按鈕原生啟動。包一層 guard:事件來自互動 descendant(非 header cell 本身)時
|
|
618
|
+
// 交回原生,不啟動拖曳。對齊 dnd-kit「activator node 排除互動 descendant」idiom。
|
|
619
|
+
const rawListeners = draggable.listeners as Record<string, ((e: React.SyntheticEvent) => void) | undefined> | undefined
|
|
620
|
+
const guardedListeners: Record<string, unknown> | undefined = rawListeners
|
|
621
|
+
? {
|
|
622
|
+
...rawListeners,
|
|
623
|
+
onKeyDown: (e: React.KeyboardEvent) => {
|
|
624
|
+
const target = e.target as HTMLElement
|
|
625
|
+
if (
|
|
626
|
+
target !== e.currentTarget &&
|
|
627
|
+
target.closest('button, a, input, select, textarea, [role="menuitem"], [role="separator"]')
|
|
628
|
+
) {
|
|
629
|
+
return
|
|
630
|
+
}
|
|
631
|
+
rawListeners.onKeyDown?.(e)
|
|
632
|
+
},
|
|
633
|
+
}
|
|
634
|
+
: rawListeners
|
|
549
635
|
return React.cloneElement(children as React.ReactElement<Record<string, unknown>>, {
|
|
550
636
|
ref: setRefs,
|
|
551
637
|
style: { ...(childProps.style ?? {}), ...dragStyle },
|
|
552
638
|
'data-column-id': id,
|
|
553
639
|
'data-column-locked': isLocked || undefined,
|
|
554
|
-
...(disabled ? {} : { ...draggableAttrs, ...(
|
|
640
|
+
...(disabled ? {} : { ...draggableAttrs, ...(guardedListeners ?? {}) }),
|
|
555
641
|
// 2026-05-06 v14.9 cursor canonical(對齊 Notion / Jira):
|
|
556
642
|
// **idle hover NOT 顯 cursor-grab** — header click 觸發 sort,grab cursor 會誤導 user 以為「點 = 拖」;
|
|
557
643
|
// **drag activation 後**(isDragging=true,過 8px activationConstraint)才顯 cursor-grabbing。
|
|
@@ -562,8 +648,9 @@ function DraggableHeaderCell({
|
|
|
562
648
|
|
|
563
649
|
/** Row drag handle — Portal-rendered, position:fixed 真正水平置中於 table outer border line(Jira canonical)。
|
|
564
650
|
*
|
|
565
|
-
* v15.
|
|
566
|
-
*
|
|
651
|
+
* v15.6 button-only drag(推翻 v15.2「整列接 listeners」,2026-07-14 JSDoc 對齊):Button =
|
|
652
|
+
* 唯一 activator,接 handleSetActivatorNodeRef + handleListeners(SourceRowProvider ctx);
|
|
653
|
+
* row div 不接 listeners(rowListeners=undefined),row click 保留給 select / open detail 等 UX。
|
|
567
654
|
*
|
|
568
655
|
* Why Portal + position:fixed(2026-05-05 v4):
|
|
569
656
|
* DataTable 結構含三層 overflow-hidden(outer wrapper / leftBody / row),用 absolute + translate-x:-50%
|
|
@@ -604,11 +691,16 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
604
691
|
// v15.1:drag 期間 source button hide(visible 邏輯已 guard isDragging),
|
|
605
692
|
// 此處只報「真實 hover」狀態,不疊 isDragging mask。
|
|
606
693
|
const rowHovered = rowEl.hasAttribute('data-hovered')
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
694
|
+
const top = rRect.top + rRect.height / 2
|
|
695
|
+
const left = tRect.left // table outer 左 border line position(viewport coords)
|
|
696
|
+
// 2026-07-05 D3 perf fix:prev 值比對 — 位置/hover 沒變時回傳 prev reference,
|
|
697
|
+
// React Object.is bail out(原每 scroll frame 無條件新 object → 每個 visible handle
|
|
698
|
+
// 每 frame 必 re-render Button + Tooltip + portal,即使位置根本沒動)。
|
|
699
|
+
setPos((prev) =>
|
|
700
|
+
prev && prev.top === top && prev.left === left && prev.rowHovered === rowHovered
|
|
701
|
+
? prev
|
|
702
|
+
: { top, left, rowHovered },
|
|
703
|
+
)
|
|
612
704
|
}
|
|
613
705
|
|
|
614
706
|
update()
|
|
@@ -623,6 +715,11 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
623
715
|
// useOverflowCount fix `combobox.tsx:130`)。
|
|
624
716
|
let scrollRafId = 0
|
|
625
717
|
const onScroll = () => {
|
|
718
|
+
// D3 NO-SAMPLE audit(2026-08-02):non-hovered virtual rows still share the window
|
|
719
|
+
// listener, but their hidden handles do not need rect reads. Without this guard a
|
|
720
|
+
// 50-row virtual window scheduled 50 rAF callbacks + getBoundingClientRect calls
|
|
721
|
+
// for every scroll frame even though only one handle can be visible.
|
|
722
|
+
if (!rowEl.hasAttribute('data-hovered') && !buttonHovered && !ctx.isDragging) return
|
|
626
723
|
if (scrollRafId) cancelAnimationFrame(scrollRafId)
|
|
627
724
|
scrollRafId = requestAnimationFrame(() => {
|
|
628
725
|
scrollRafId = 0
|
|
@@ -638,7 +735,7 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
638
735
|
window.removeEventListener('scroll', onScroll, true)
|
|
639
736
|
window.removeEventListener('resize', onScroll)
|
|
640
737
|
}
|
|
641
|
-
}, [rowEl, ctx])
|
|
738
|
+
}, [rowEl, ctx, buttonHovered])
|
|
642
739
|
|
|
643
740
|
// 永遠 render anchor span(讓 anchorRef 可拿到 row element)。
|
|
644
741
|
// A3 fix(2026-05-05):顯式 `top:0 left:0 pointer-events:none` — 雖 width/height=0 不該佔
|
|
@@ -694,13 +791,13 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
694
791
|
// 2026-05-12 fix v2(user 抓「drag column sort 啟用時 button 不是 disable 視覺」):
|
|
695
792
|
// 前 Round 4.5 加 `aria-disabled:opacity-[var(--opacity-disabled)]` 在 Button cva
|
|
696
793
|
// 沒生效 — 因為 inline style `opacity` 永遠 win over Tailwind class。Fix:把 disabled
|
|
697
|
-
// state opacity 也 compute 進 inline style。priority order:invisible 0 → drag
|
|
698
|
-
//
|
|
794
|
+
// state opacity 也 compute 進 inline style。priority order:invisible 0 → drag var(--opacity-disabled)
|
|
795
|
+
// 0.45(2026-07-04 修:原硬寫 0.5 違 lib/drag-visual.ts SSOT)→ canDrag=false(sort active)
|
|
796
|
+
// disabled visual var(--opacity-disabled) 0.45 → idle 1。
|
|
699
797
|
opacity: visible
|
|
700
|
-
? (ctx.isDragging ?
|
|
798
|
+
? (ctx.isDragging ? 'var(--opacity-disabled)' as unknown as number : (canDrag ? 1 : 'var(--opacity-disabled)' as unknown as number))
|
|
701
799
|
: 0,
|
|
702
800
|
pointerEvents: visible ? 'auto' : 'none',
|
|
703
|
-
transition: 'opacity 150ms ease',
|
|
704
801
|
}}
|
|
705
802
|
className={cn(
|
|
706
803
|
// 2026-05-12 debug fix(user 抓「hover 還是透明」)— Round 4.5 我未授權加
|
|
@@ -712,6 +809,7 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
712
809
|
// row 任何 state 視覺都有 token-level 對比(在 token 差異存在的 mode;light mode --surface-raised
|
|
713
810
|
// 等於 --surface 是 design token semantic,非本 fix scope)。
|
|
714
811
|
'bg-surface-raised hover:bg-surface-raised aria-disabled:bg-surface-raised',
|
|
812
|
+
'transition-opacity duration-150 ease-in-out motion-reduce:duration-0',
|
|
715
813
|
canDrag && !showInvalid && 'cursor-grab',
|
|
716
814
|
canDrag && showInvalid && 'cursor-not-allowed !text-error !border-error',
|
|
717
815
|
// drag 進行中 source button cursor(opacity 0.5 via style;aria-disabled visual 由 Button cva 接管)
|
|
@@ -738,25 +836,80 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
|
|
|
738
836
|
}
|
|
739
837
|
|
|
740
838
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
741
|
-
// AG Grid 模式:header 在 scroll 外面,
|
|
839
|
+
// AG Grid 模式:header 在 scroll 外面,V scroll 在 center-body(AR44 後現況)。
|
|
742
840
|
//
|
|
743
841
|
// table
|
|
744
842
|
// ├── header(固定頂部,不在 scroll 內)
|
|
745
843
|
// │ ├── left-header
|
|
746
844
|
// │ ├── center-header(overflow:hidden,JS sync scrollLeft)
|
|
747
845
|
// │ └── right-header
|
|
748
|
-
// └── body-viewport(
|
|
749
|
-
// ├── left-body(overflow:hidden)
|
|
750
|
-
// ├── center-body(overflow-x:auto, overflow-y:
|
|
751
|
-
//
|
|
846
|
+
// └── body-viewport(display:flex,無 overflow — AR44 後不再是 scroll container)
|
|
847
|
+
// ├── left-body(overflow:hidden,JS sync scrollTop)
|
|
848
|
+
// ├── center-body(overflow-x:auto, overflow-y:auto — 唯一 V scroll,
|
|
849
|
+
// │ onCenterBodyScroll 同步兩側 scrollTop + header scrollLeft)
|
|
850
|
+
// └── right-body(overflow:hidden,JS sync scrollTop)
|
|
752
851
|
//
|
|
753
|
-
// 不用 CSS sticky。Header
|
|
852
|
+
// 不用 CSS sticky。Header 永遠在頂部。細節見下方「JS scroll sync(AR44)」註解。
|
|
754
853
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
755
854
|
|
|
855
|
+
// ── MemoCellSlot(2026-07-05 D3 perf fix)────────────────────────────────────
|
|
856
|
+
// cell-registry 2026-05-13 已把每個 cell type 包成 module-level cached `React.memo(CellWithSurface)`,
|
|
857
|
+
// 但 renderCellContent 每次 render 傳 3 個全新 inline closure(onCommit / onCommitLive /
|
|
858
|
+
// onRequestEdit)+ `meta ?? {}` 新 object → memo shallow-compare 100% fail,防線靜默失效
|
|
859
|
+
// (DataTableInner 任何 re-render — scroll / resize / drag / spreadsheet 選取 / portal keystroke —
|
|
860
|
+
// 都讓全部 visible cells 的 Field view subtree 整棵重渲)。
|
|
861
|
+
// Fix:中介 memo slot — 從 parent 接 stable callback(commitCell / cancelCellEdit / onCellCommit /
|
|
862
|
+
// enterCellEdit)+ primitive rowId / colId,在 slot 內 useCallback 綁 per-cell closure;
|
|
863
|
+
// props 全 primitive / stable reference → memo 真命中,unchanged cells render 成本歸零。
|
|
864
|
+
// Cite world-class:AG Grid「cell renderer stable reference」/ MUI X DataGrid memoized subcomponents。
|
|
865
|
+
const EMPTY_META: Record<string, unknown> = {}
|
|
866
|
+
|
|
867
|
+
interface MemoCellSlotProps {
|
|
868
|
+
Cell: React.ComponentType<CellComponentProps>
|
|
869
|
+
rowId: string
|
|
870
|
+
colId: string
|
|
871
|
+
// any-allow: free-form column value(consumer-defined,同 CellComponentProps.value)
|
|
872
|
+
value: any
|
|
873
|
+
// any-allow: free-form consumer meta bag(同 CellComponentProps.meta)
|
|
874
|
+
meta: Record<string, any>
|
|
875
|
+
mode: 'view' | 'edit'
|
|
876
|
+
size: 'sm' | 'md' | 'lg'
|
|
877
|
+
autoRowHeight: boolean
|
|
878
|
+
isEditable: boolean
|
|
879
|
+
onCommitCell: (rowId: string, colId: string, next: unknown) => void
|
|
880
|
+
onCancelCell: (rowId: string, colId: string) => void
|
|
881
|
+
onCellCommitLive?: (rowId: string, colId: string, next: unknown) => void
|
|
882
|
+
onEnterEdit: (rowId: string, colId: string) => void
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const MemoCellSlot = React.memo(function MemoCellSlot({
|
|
886
|
+
Cell, rowId, colId, value, meta, mode, size, autoRowHeight,
|
|
887
|
+
isEditable, onCommitCell, onCancelCell, onCellCommitLive, onEnterEdit,
|
|
888
|
+
}: MemoCellSlotProps) {
|
|
889
|
+
const onCommit = React.useCallback((next: unknown) => onCommitCell(rowId, colId, next), [onCommitCell, rowId, colId])
|
|
890
|
+
const onCommitLive = React.useCallback((next: unknown) => onCellCommitLive?.(rowId, colId, next), [onCellCommitLive, rowId, colId])
|
|
891
|
+
const onCancel = React.useCallback(() => onCancelCell(rowId, colId), [onCancelCell, rowId, colId])
|
|
892
|
+
const onRequestEdit = React.useCallback(() => onEnterEdit(rowId, colId), [onEnterEdit, rowId, colId])
|
|
893
|
+
return (
|
|
894
|
+
<Cell
|
|
895
|
+
value={value}
|
|
896
|
+
meta={meta}
|
|
897
|
+
mode={mode}
|
|
898
|
+
size={size}
|
|
899
|
+
autoRowHeight={autoRowHeight}
|
|
900
|
+
isEditable={isEditable}
|
|
901
|
+
onCommit={onCommit}
|
|
902
|
+
onCommitLive={onCommitLive}
|
|
903
|
+
onCancel={onCancel}
|
|
904
|
+
onRequestEdit={onRequestEdit}
|
|
905
|
+
/>
|
|
906
|
+
)
|
|
907
|
+
})
|
|
908
|
+
|
|
756
909
|
// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding
|
|
757
910
|
function DataTableInner<TData>(
|
|
758
911
|
{
|
|
759
|
-
columns, data, size = 'md', autoRowHeight = false, height
|
|
912
|
+
columns, data, size = 'md', autoRowHeight = false, height: heightProp,
|
|
760
913
|
overscan = 5, emptyState, enableHover = true, bordered,
|
|
761
914
|
estimateRowHeight, tableOptions, rowActions, cellErrors,
|
|
762
915
|
pinnedLeftColumns, pinnedRightColumns, inlineEdit = false,
|
|
@@ -776,22 +929,25 @@ function DataTableInner<TData>(
|
|
|
776
929
|
experimentalSpreadsheetOverlay = false,
|
|
777
930
|
experimentalActiveEditorController = false,
|
|
778
931
|
spreadsheetMode = false,
|
|
932
|
+
pagination,
|
|
779
933
|
className, ...props
|
|
780
934
|
}: DataTableProps<TData>,
|
|
781
935
|
ref: React.ForwardedRef<HTMLDivElement>
|
|
782
936
|
) {
|
|
937
|
+
// L5 分頁 × height 預設(2026-07-06):未顯式傳 height 時 —— 分頁 = 'auto' 自然高度
|
|
938
|
+
// (頁碼是唯一導覽通道,不疊 body 內捲動;Ant Table 無預設高度罩慣例),
|
|
939
|
+
// 未分頁 = 既有 '400px' 預設不變。顯式傳 height 一律尊重(prop docblock 有完整規則)。
|
|
940
|
+
const height = heightProp ?? (pagination ? 'auto' : '400px')
|
|
783
941
|
// ── L4 Inline edit state ──
|
|
784
942
|
// editingCellId: `${rowId}__${columnId}` 標識當前進 edit mode 的 cell;null = 無
|
|
785
943
|
const [editingCellId, setEditingCellId] = React.useState<string | null>(null)
|
|
786
944
|
// Phase 7 D.3 portal Field virtualizer unmount preserve draft(2026-05-10 per codex Q-B4 verdict):
|
|
787
945
|
// Lifted draft state in DataTable — Cell DOM unmount(virtualizer scroll out)時 draft 不丟,
|
|
788
946
|
// mount-back 時 portal Field value=draft 而非 row.value,user 編輯中字保留。
|
|
789
|
-
//
|
|
947
|
+
// draft 生命週期(2026-07-05 D4 fix):cancelCellEdit / commitCell 清 draft;Tab 換格
|
|
948
|
+
// (handleEditTab)先 commit 當前 draft 再換格 — 原註解宣稱「editingCellId 變時 useEffect
|
|
949
|
+
// reset draft」的 effect 從未存在,曾致 Tab 換格後下一格顯示上一格草稿。
|
|
790
950
|
const [editingDraft, setEditingDraft] = React.useState<unknown>(undefined)
|
|
791
|
-
const exitEdit = React.useCallback(() => {
|
|
792
|
-
setEditingCellId(null)
|
|
793
|
-
setEditingDraft(undefined)
|
|
794
|
-
}, [])
|
|
795
951
|
|
|
796
952
|
// ── Slice D Step 4 spreadsheet semantics state(2026-05-10) ──
|
|
797
953
|
// selectedCellId:`${rowId}:${colId}` Excel-like 選取(click 1)
|
|
@@ -820,14 +976,44 @@ function DataTableInner<TData>(
|
|
|
820
976
|
document.addEventListener('pointerdown', handler, true)
|
|
821
977
|
return () => document.removeEventListener('pointerdown', handler, true)
|
|
822
978
|
}, [spreadsheetMode, selectedCellId, rangeAnchor])
|
|
979
|
+
// 2026-07-05 D4 fix:edit 退出(commit / cancel)後還原 spreadsheet selection 到該 cell +
|
|
980
|
+
// 收回焦點到 table root — 原本只清 editingCellId,editor unmount 後 document.activeElement
|
|
981
|
+
// 掉到 body、selection 不還原 → 每次編輯後鍵盤導覽死巷(方向鍵全滅、必須滑鼠重點),違反
|
|
982
|
+
// datatable-spreadsheet-rfc.md Contract 11「退出後還給 active cell」(對齊 Excel / AG Grid / Sheets)。
|
|
983
|
+
const restoreCellSelection = React.useCallback((rowId: string, colId: string) => {
|
|
984
|
+
if (!spreadsheetMode) return
|
|
985
|
+
const cellId = `${rowId}:${colId}`
|
|
986
|
+
setSelectedCellId(cellId)
|
|
987
|
+
setRangeAnchor(cellId)
|
|
988
|
+
setRangeFocus(null)
|
|
989
|
+
// 等 editor unmount 完成後才收回焦點;activeElement 非 body(user 點了其他 focusable /
|
|
990
|
+
// Tab 換格後下一格 editor autoFocus)時不搶焦點。
|
|
991
|
+
requestAnimationFrame(() => {
|
|
992
|
+
const el = tableRef.current
|
|
993
|
+
if (!el) return
|
|
994
|
+
const active = document.activeElement
|
|
995
|
+
if (active === document.body || active === null) el.focus({ preventScroll: true })
|
|
996
|
+
})
|
|
997
|
+
}, [spreadsheetMode])
|
|
823
998
|
const commitCell = React.useCallback(
|
|
824
999
|
(rowId: string, colId: string, next: unknown) => {
|
|
825
1000
|
onCellCommit?.(rowId, colId, next)
|
|
826
1001
|
setEditingCellId(null)
|
|
827
1002
|
setEditingDraft(undefined) // Phase 7:commit 後清 draft
|
|
1003
|
+
restoreCellSelection(rowId, colId) // 2026-07-05 D4:commit 後 selection 還原(Contract 11)
|
|
828
1004
|
},
|
|
829
|
-
[onCellCommit],
|
|
1005
|
+
[onCellCommit, restoreCellSelection],
|
|
830
1006
|
)
|
|
1007
|
+
// cancel 路徑(Esc / popover dismiss)— 同 commit 還原 selection;取代舊無參數 exitEdit
|
|
1008
|
+
const cancelCellEdit = React.useCallback((rowId: string, colId: string) => {
|
|
1009
|
+
setEditingCellId(null)
|
|
1010
|
+
setEditingDraft(undefined)
|
|
1011
|
+
restoreCellSelection(rowId, colId)
|
|
1012
|
+
}, [restoreCellSelection])
|
|
1013
|
+
// edit 進入點(MemoCellSlot onEnterEdit 消費;stable identity 維持 memo 命中)
|
|
1014
|
+
const enterCellEdit = React.useCallback((rowId: string, colId: string) => {
|
|
1015
|
+
setEditingCellId(cellEditId(rowId, colId))
|
|
1016
|
+
}, [])
|
|
831
1017
|
// 判 column meta.editable 對特定 row 是否成立(支援 fn)
|
|
832
1018
|
// column meta 是 free-form consumer bag(同 renderTypedValue any policy),不適合窄型化
|
|
833
1019
|
const isCellEditable = React.useCallback(
|
|
@@ -839,28 +1025,13 @@ function DataTableInner<TData>(
|
|
|
839
1025
|
},
|
|
840
1026
|
[],
|
|
841
1027
|
)
|
|
842
|
-
// 2026-
|
|
843
|
-
//
|
|
844
|
-
//
|
|
845
|
-
// 透過 isDisabled prop 走 mode='disabled'(各 Field type 內部具體 disabled token,非 wrapper blanket opacity),
|
|
846
|
-
// (c) edit entry condition: `cellEditable && !cellDisabled`。
|
|
847
|
-
const isCellDisabled = React.useCallback(
|
|
848
|
-
// any-allow: free-form consumer meta — same rationale as L143 renderTypedValue
|
|
849
|
-
(meta: Record<string, any> | undefined, row: unknown): boolean => {
|
|
850
|
-
const d = meta?.disabled
|
|
851
|
-
if (typeof d === 'function') return d(row) === true
|
|
852
|
-
return d === true
|
|
853
|
-
},
|
|
854
|
-
[],
|
|
855
|
-
)
|
|
856
|
-
// 2026-05-13:canEditCell helper consolidation(per codex V4 follow-up + user「沒理由不做」拍板)
|
|
857
|
-
// 抽 4-site repeated `editable && !disabled` pattern。3 path sites(keyboard / Tab / InteractionLayer)
|
|
858
|
-
// call canEditCell;另 2 sites(renderCellContent + onEditableCellClick)用 already-computed `editable`/
|
|
859
|
-
// `disabled` 變數(因為 disabled 還要單獨給 isDisabled prop + bg-disabled class),不 collapse to helper。
|
|
1028
|
+
// 2026-07-16 round16:cell「disabled」態廢除(世界級 grid 無 disabled cell;meta.disabled 全庫 0 消費)。
|
|
1029
|
+
// 鎖定 cell = `editable:(row)=>false`(= isCellEditable 模型),非灰化 disabled 態。原 isCellDisabled
|
|
1030
|
+
// helper + bg-disabled TD 灰化 + isDisabled prop 全移除;canEditCell 收斂為 isCellEditable。
|
|
860
1031
|
const canEditCell = React.useCallback(
|
|
861
1032
|
(meta: Record<string, unknown> | undefined, row: unknown): boolean =>
|
|
862
|
-
isCellEditable(meta, row)
|
|
863
|
-
[isCellEditable
|
|
1033
|
+
isCellEditable(meta, row),
|
|
1034
|
+
[isCellEditable],
|
|
864
1035
|
)
|
|
865
1036
|
const [sorting, setSorting] = React.useState<SortingState>(tableOptions?.state?.sorting as SortingState ?? [])
|
|
866
1037
|
|
|
@@ -874,9 +1045,9 @@ function DataTableInner<TData>(
|
|
|
874
1045
|
// ── L2 Selection state ──
|
|
875
1046
|
const enabled = selectable !== false
|
|
876
1047
|
const mode = selectable === 'single' ? 'single' : 'multi'
|
|
877
|
-
const [selection, setSelection] = useControllable<
|
|
878
|
-
value: selectionProp,
|
|
879
|
-
defaultValue: defaultSelection ?? [],
|
|
1048
|
+
const [selection, setSelection] = useControllable<DataTableSelection>({
|
|
1049
|
+
value: normalizeSelection(selectionProp),
|
|
1050
|
+
defaultValue: normalizeSelection(defaultSelection) ?? { mode: 'include', ids: [] },
|
|
880
1051
|
onChange: onSelectionChange,
|
|
881
1052
|
})
|
|
882
1053
|
// Shift-click anchor:存最後一次「單擊」的 row id,shift-click 時做區間選
|
|
@@ -942,6 +1113,20 @@ function DataTableInner<TData>(
|
|
|
942
1113
|
// 注意:`...tableOptions` 必 spread 在 `state` 前,否則 user 傳的 tableOptions 會
|
|
943
1114
|
// 整個 override 掉我們組的 state(含 __select__ 自動 pinning + columnOrder 注入)。
|
|
944
1115
|
// 之前 bug:checkbox column 跑到右邊 = 此處 spread 順序錯。
|
|
1116
|
+
// ── L5 分頁 state(2026-07-06)──────────────────────────────────────────────
|
|
1117
|
+
// 共用模式(user 拍板):<Pagination> 獨立元件為頁碼視覺 SSOT,DataTable 內建接 TanStack
|
|
1118
|
+
// 分頁模型消費它(Ant Table 消費 Pagination / Atlassian DynamicTable rowsPerPage / MUI
|
|
1119
|
+
// DataGrid 同派;shadcn data-table 教學同款「分頁 render 在元件 JSX 內」)。
|
|
1120
|
+
const paginationEnabled = !!pagination
|
|
1121
|
+
const paginationOpts = typeof pagination === 'object' ? pagination : undefined
|
|
1122
|
+
const [pageSizeState, setPageSizeState] = React.useState(paginationOpts?.pageSize ?? 20)
|
|
1123
|
+
// 1-based 對外(對齊 Pagination / Ant);餵 TanStack state 時換算 0-based
|
|
1124
|
+
const [currentPage, setCurrentPage] = useControllable<number>({
|
|
1125
|
+
value: paginationOpts?.page,
|
|
1126
|
+
defaultValue: paginationOpts?.defaultPage ?? 1,
|
|
1127
|
+
onChange: paginationOpts?.onPageChange,
|
|
1128
|
+
})
|
|
1129
|
+
|
|
945
1130
|
const table = useReactTable({
|
|
946
1131
|
...tableOptions,
|
|
947
1132
|
data, columns: columnsWithSelection,
|
|
@@ -951,6 +1136,9 @@ function DataTableInner<TData>(
|
|
|
951
1136
|
// columnPinning + columnOrder 在 user state 後 override,確保 __select__ 永遠左
|
|
952
1137
|
columnPinning: { left: effectivePinnedLeft, right: pinnedRightColumns ?? [] },
|
|
953
1138
|
...(effectiveColumnOrder ? { columnOrder: effectiveColumnOrder } : {}),
|
|
1139
|
+
// L5 分頁:必在 ...tableOptions?.state 之後 spread(同 columnPinning override 理由——
|
|
1140
|
+
// 防 user state 蓋掉內建接線);頁碼變更由 <Pagination onPageChange> 驅動,不走 TanStack 內部 setter
|
|
1141
|
+
...(paginationEnabled ? { pagination: { pageIndex: currentPage - 1, pageSize: pageSizeState } } : {}),
|
|
954
1142
|
},
|
|
955
1143
|
enableMultiSort,
|
|
956
1144
|
// **#1 fix(2026-05-04)**:chain user `tableOptions.onSortingChange`(spread 在前被 override = 之前 bug)
|
|
@@ -968,6 +1156,8 @@ function DataTableInner<TData>(
|
|
|
968
1156
|
getSortedRowModel: getSortedRowModel(),
|
|
969
1157
|
// L4 nested rows:啟用 expanded row model(consumer 透過 tableOptions.getSubRows + state.expanded forward)
|
|
970
1158
|
getExpandedRowModel: getExpandedRowModel(),
|
|
1159
|
+
// L5 分頁:條件掛載(TanStack 官方:pagination 與 virtualization 為互斥替代策略)
|
|
1160
|
+
...(paginationEnabled ? { getPaginationRowModel: getPaginationRowModel() } : {}),
|
|
971
1161
|
getRowId: getRowId,
|
|
972
1162
|
// 2026-05-06 v14 column resize:`onChange` mode → drag 中 column 即時跟動 cursor(world-class
|
|
973
1163
|
// canonical:TanStack docs / AG Grid / Excel / Google Sheets 全部 live resize)。前 v13.2
|
|
@@ -982,10 +1172,20 @@ function DataTableInner<TData>(
|
|
|
982
1172
|
})
|
|
983
1173
|
|
|
984
1174
|
// v13.2:onColumnResize callback 透過 useEffect 觀測 columnSizing state 變動 fire(uncontrolled state pattern)
|
|
1175
|
+
// 2026-07-06 D3 fix:兌現 prop docblock「commit-on-pointerup,非 live」契約 —
|
|
1176
|
+
// columnResizeMode:'onChange' 讓 drag 中 columnSizing 每 mousemove 變一次(視覺即時跟動,
|
|
1177
|
+
// 保留),原 effect 無 gate → callback 每 mousemove fire 一次;docblock 明文建議 consumer
|
|
1178
|
+
// 在此 callback 做 width persistence(localStorage / URL / API)= 每 mousemove I/O。
|
|
1179
|
+
// 改以 TanStack columnSizingInfo.isResizingColumn 為訊號:drag 進行中不 fire、也不推進
|
|
1180
|
+
// snapshot(保留 drag 前基準);pointerup(isResizingColumn 轉 false)才 diff snapshot,
|
|
1181
|
+
// fire 一次最終寬度。非 drag 路徑(「自動調整寬度」menu 的 setColumnSizing)不經
|
|
1182
|
+
// isResizingColumn,行為不變。
|
|
985
1183
|
const columnSizingState = table.getState().columnSizing
|
|
1184
|
+
const isResizingColumn = table.getState().columnSizingInfo.isResizingColumn
|
|
986
1185
|
const prevColumnSizingRef = React.useRef(columnSizingState)
|
|
987
1186
|
React.useEffect(() => {
|
|
988
1187
|
if (!onColumnResize) return
|
|
1188
|
+
if (isResizingColumn) return
|
|
989
1189
|
const prev = prevColumnSizingRef.current
|
|
990
1190
|
Object.keys(columnSizingState).forEach(id => {
|
|
991
1191
|
if (columnSizingState[id] !== prev[id]) {
|
|
@@ -993,10 +1193,17 @@ function DataTableInner<TData>(
|
|
|
993
1193
|
}
|
|
994
1194
|
})
|
|
995
1195
|
prevColumnSizingRef.current = columnSizingState
|
|
996
|
-
}, [columnSizingState, onColumnResize])
|
|
1196
|
+
}, [columnSizingState, isResizingColumn, onColumnResize])
|
|
997
1197
|
|
|
998
1198
|
const { rows } = table.getRowModel()
|
|
999
1199
|
const isEmpty = rows.length === 0
|
|
1200
|
+
|
|
1201
|
+
// L5 分頁:filter / data 縮小時 TanStack 不自動 clamp 當前頁(會停在空頁);對齊 MUI X 自動 clamp
|
|
1202
|
+
const pageCount = paginationEnabled ? table.getPageCount() : 0
|
|
1203
|
+
React.useEffect(() => {
|
|
1204
|
+
if (!paginationEnabled) return
|
|
1205
|
+
if (pageCount > 0 && currentPage > pageCount) setCurrentPage(pageCount)
|
|
1206
|
+
}, [paginationEnabled, pageCount, currentPage, setCurrentPage])
|
|
1000
1207
|
const hasHeightConstraint = height !== 'auto'
|
|
1001
1208
|
// Fill-parent mode:height='100%' / '100vh' / 'fill' 等百分比 / 視口語義 → outer flex column + body flex-1 撐滿。
|
|
1002
1209
|
// 固定 px/rem 仍維持 maxHeight cap 行為(資料少 = 內容高度,資料多 = 上限後 scroll)— 對齊既有 stories 預期。
|
|
@@ -1008,7 +1215,8 @@ function DataTableInner<TData>(
|
|
|
1008
1215
|
// direct render 完全 bypass 此 race,且小資料下虛擬化沒效益(浪費 reflow)。
|
|
1009
1216
|
// 對齊 AG Grid `suppressVirtualization` / TanStack Table virtualization-when-needed idiom。
|
|
1010
1217
|
const VIRTUAL_THRESHOLD = 30
|
|
1011
|
-
|
|
1218
|
+
// L5 分頁互斥:分頁後每頁 rows ≤ pageSize,虛擬化無效益(TanStack 官方:兩者為互斥替代策略)
|
|
1219
|
+
const useVirtual = !paginationEnabled && hasHeightConstraint && !isEmpty && rows.length > VIRTUAL_THRESHOLD
|
|
1012
1220
|
const hasRowActions = !!rowActions
|
|
1013
1221
|
|
|
1014
1222
|
// Refs
|
|
@@ -1029,7 +1237,7 @@ function DataTableInner<TData>(
|
|
|
1029
1237
|
// 2026-05-06 v10 DragOverlay canonical:retire windowed sticky range extractor (v4-v9 workaround)。
|
|
1030
1238
|
// 改用 `<DragOverlay>` portal 把 source row 視覺解耦 — source 即使 unmount(virtual scroll out)
|
|
1031
1239
|
// overlay 仍 render 由 cloned outerHTML 提供視覺。dnd-kit transform / collision 走 active item id
|
|
1032
|
-
// (
|
|
1240
|
+
// (DndContext store 以 active id 追蹤,跟 hook instance mount 狀態無關;v15 無 SortableContext)。
|
|
1033
1241
|
// 對齊 dnd-kit GitHub #1674 + drag-overlay docs canonical「virtualized list MUST use DragOverlay」。
|
|
1034
1242
|
// overscan 仍輕微拉高(避免 source row 旁邊 rows 也 unmount 致使 hover signal 計算抖動)。
|
|
1035
1243
|
const effectiveOverscan = enableRowDrag ? Math.max(overscan, 5) : overscan
|
|
@@ -1060,6 +1268,8 @@ function DataTableInner<TData>(
|
|
|
1060
1268
|
// 後續 measureElement 修正到 6×40 = 240,差 24px 視覺看起來像「table 慢慢長高」。fix = estimate
|
|
1061
1269
|
// 預設 size-aware 對齊 token(見下方 estimateRowHeight default 計算)。
|
|
1062
1270
|
const [bodyMaxHeight, setBodyMaxHeight] = React.useState<number | null>(null)
|
|
1271
|
+
// L5 分頁 × isFillHeight(2026-07-07 C12):bar 高度量測用 — compute() 需扣分頁列 footprint
|
|
1272
|
+
const paginationBarRef = React.useRef<HTMLDivElement | null>(null)
|
|
1063
1273
|
React.useLayoutEffect(() => {
|
|
1064
1274
|
if (!isFillHeight) { setBodyMaxHeight(null); return }
|
|
1065
1275
|
// **R4 真根因 fix(2026-05-09 v2 — codex Q3.6 root cause + Q3.9 reproduce verified)**:
|
|
@@ -1102,7 +1312,15 @@ function DataTableInner<TData>(
|
|
|
1102
1312
|
?? tableRef.current.getBoundingClientRect().height
|
|
1103
1313
|
const headerEl = tableRef.current.firstElementChild as HTMLElement | null
|
|
1104
1314
|
const headerH = headerEl?.getBoundingClientRect().height ?? 0
|
|
1105
|
-
|
|
1315
|
+
// L5 分頁 × isFillHeight(2026-07-07 C12):啟用分頁時 parent slot = composedContent
|
|
1316
|
+
// wrapper(含分頁列 + tight gap),body 可用高必扣分頁列 footprint,否則 body 撐滿
|
|
1317
|
+
// 把分頁列擠出 / 被 overflow 裁掉
|
|
1318
|
+
const barEl = paginationBarRef.current
|
|
1319
|
+
const barFootprint = barEl
|
|
1320
|
+
? barEl.getBoundingClientRect().height +
|
|
1321
|
+
(parseFloat(getComputedStyle(barEl.parentElement as Element).rowGap) || 0)
|
|
1322
|
+
: 0
|
|
1323
|
+
const next = Math.max(0, slotH - headerH - barFootprint)
|
|
1106
1324
|
// Diff guard < 4px(濾 micro-step,real resize δ 必 ≫ 4px)
|
|
1107
1325
|
if (lastValue != null && Math.abs(next - lastValue) < 4) return
|
|
1108
1326
|
lastValue = next
|
|
@@ -1149,10 +1367,9 @@ function DataTableInner<TData>(
|
|
|
1149
1367
|
|
|
1150
1368
|
// ── Phase 9 Issue 1 fix(2026-05-10):range cells lifted compute + Set ────
|
|
1151
1369
|
// 計算 spreadsheet range cell IDs(Shift+click rectangle from anchor↔focus),
|
|
1152
|
-
//
|
|
1153
|
-
//
|
|
1154
|
-
//
|
|
1155
|
-
// (per codex Q1 verdict:bg fill 移到 cell bg layer 不在 overlay,內容才不被蓋)
|
|
1370
|
+
// 提供 `rangeCellIdSet` Set → cell wrapper data-range-cell attr for cell-bg fill
|
|
1371
|
+
// (per codex Q1 verdict:bg fill 走 cell bg layer 不在 overlay,內容才不被蓋;
|
|
1372
|
+
// layer 的 outer ring / rangeCellIds prop 已 retire — 2026-07-14 對齊清理)
|
|
1156
1373
|
const rangeCellIds = React.useMemo<string[] | undefined>(() => {
|
|
1157
1374
|
if (!spreadsheetMode || !rangeAnchor || !rangeFocus || rangeAnchor === rangeFocus) return undefined
|
|
1158
1375
|
const parseCell = (id: string) => {
|
|
@@ -1209,7 +1426,13 @@ function DataTableInner<TData>(
|
|
|
1209
1426
|
return () => obs.disconnect()
|
|
1210
1427
|
}, [hasLeft, hasRight, rows.length])
|
|
1211
1428
|
|
|
1212
|
-
|
|
1429
|
+
// 2026-07-09 root-cause fix(user 以 GitHub Pages 對比抓出 regression):
|
|
1430
|
+
// 舊 `h-table-row-${size}` 模板字串 Tailwind **靜態掃描看不到** → `.h-table-row-{sm,md,lg}` 規則
|
|
1431
|
+
// 唯一靠 uiSize.spec.md 裡的 literal 被 content-detection 掃到才生成;戰役期間掃描樹變動後未生成
|
|
1432
|
+
// → 規則消失 → row 塌成「內容高度」(非編輯 33px / 編輯 44px)而非固定 token 40px,連帶選取控件與
|
|
1433
|
+
// 列文字對不齊。改用 literal map(對齊 field-wrapper cva 的 `h-field-md` literal 慣例),Tailwind
|
|
1434
|
+
// 永遠掃得到、不再依賴脆弱的 spec.md literal → 永不再漂移。
|
|
1435
|
+
const rowHeight = { sm: 'h-table-row-sm', md: 'h-table-row-md', lg: 'h-table-row-lg' }[size] ?? 'h-table-row-md'
|
|
1213
1436
|
|
|
1214
1437
|
// ── Cross-region row hover (2026-04-22 D3 perf audit):event delegation 改 per-row closure
|
|
1215
1438
|
// 舊:每 row 建 `{ onMouseEnter, onMouseLeave }` + 2 arrow functions → 100 row = 200 closures/render
|
|
@@ -1249,56 +1472,58 @@ function DataTableInner<TData>(
|
|
|
1249
1472
|
const hoverProps = (_idx: number): Record<string, never> => ({})
|
|
1250
1473
|
|
|
1251
1474
|
// ── Cell render(Phase C 2026-05-05 — type-keyed registry SSOT)──
|
|
1252
|
-
// 命中 columnType → 走 cellRegistry(
|
|
1475
|
+
// 命中 columnType → 走 cellRegistry(view / edit mode 同元件 with `mode` prop);
|
|
1253
1476
|
// 無 columnType → consumer 自訂 cell.columnDef.cell。
|
|
1254
1477
|
const renderCellContent = (cell: ReturnType<typeof rows[number]['getVisibleCells']>[number]) => {
|
|
1255
1478
|
const meta = cell.column.columnDef.meta
|
|
1256
1479
|
const colType = meta?.type as ColumnType | undefined
|
|
1257
1480
|
const wrap = autoRowHeight && meta?.wrap === true
|
|
1258
|
-
// 已知 compound 欄位(Tag / PersonDisplay / LinkInput 等自帶 layout)直接 bypass
|
|
1481
|
+
// 已知 compound 欄位(Tag / PersonDisplay / LinkInput 等自帶 layout)直接 bypass TruncatedText,
|
|
1259
1482
|
// 因為 `truncate` 的 inline baseline context 會破壞自訂 layout 的垂直對齊。
|
|
1260
|
-
// 2026-05-09 D-path:date / time 加入(showDisplayEndIcon → Field naked-
|
|
1261
|
-
// 右對齊 ItemSuffix。
|
|
1483
|
+
// 2026-05-09 D-path:date / time 加入(showDisplayEndIcon → Field naked-view 需 full width 才能
|
|
1484
|
+
// 右對齊 ItemSuffix。TruncatedText 的 `<span truncate min-w-0>` block-display 會 collapse Field
|
|
1262
1485
|
// to content size,讓 Calendar / Clock icon 緊貼 value text 而非右邊緣)。
|
|
1263
1486
|
const isKnownCompound = colType === 'select' || colType === 'multiSelect' || colType === 'person' || colType === 'multiPerson' || colType === 'url' || colType === 'date' || colType === 'time'
|
|
1264
1487
|
const rowId = cell.row.id
|
|
1265
1488
|
const colId = cell.column.id
|
|
1266
1489
|
const editable = isCellEditable(meta, cell.row.original)
|
|
1267
|
-
const disabled = isCellDisabled(meta, cell.row.original)
|
|
1268
1490
|
const isEditingThisCell = editingCellId === cellEditId(rowId, colId)
|
|
1269
1491
|
|
|
1270
1492
|
let content: React.ReactNode
|
|
1271
1493
|
if (colType) {
|
|
1272
1494
|
const Cell = resolveCellComponent(colType)
|
|
1273
1495
|
// 2026-05-10 Slice D Step 5(D.3 portal Field):當 portal flag 啟 + cell 編輯中 →
|
|
1274
|
-
// cell 保持
|
|
1275
|
-
// 預設 inline-edit:isEditingThisCell ? edit :
|
|
1276
|
-
|
|
1277
|
-
const cellMode: 'edit' | 'display' =
|
|
1496
|
+
// cell 保持 view mode(SSOT preserved per codex Q6.2),portal layer 渲 edit Field 在上。
|
|
1497
|
+
// 預設 inline-edit:isEditingThisCell ? edit : view。
|
|
1498
|
+
const cellMode: 'edit' | 'view' =
|
|
1278
1499
|
(experimentalActiveEditorController && isEditingThisCell)
|
|
1279
|
-
? '
|
|
1280
|
-
:
|
|
1500
|
+
? 'view'
|
|
1501
|
+
: isEditingThisCell ? 'edit' : 'view'
|
|
1502
|
+
// 2026-07-05 D3 perf fix:改經 MemoCellSlot — 原 inline closure props 讓 CellWithSurface
|
|
1503
|
+
// memo 100% miss(詳 MemoCellSlot 檔頭註解)。
|
|
1281
1504
|
content = (
|
|
1282
|
-
<
|
|
1505
|
+
<MemoCellSlot
|
|
1506
|
+
Cell={Cell}
|
|
1507
|
+
rowId={rowId}
|
|
1508
|
+
colId={colId}
|
|
1283
1509
|
value={cell.getValue()}
|
|
1284
|
-
meta={meta ??
|
|
1510
|
+
meta={meta ?? EMPTY_META}
|
|
1285
1511
|
mode={cellMode}
|
|
1286
1512
|
size={size}
|
|
1287
1513
|
autoRowHeight={autoRowHeight}
|
|
1288
1514
|
isEditable={editable}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
onRequestEdit={() => !disabled && setEditingCellId(cellEditId(rowId, colId))}
|
|
1515
|
+
onCommitCell={commitCell}
|
|
1516
|
+
onCancelCell={cancelCellEdit}
|
|
1517
|
+
onCellCommitLive={onCellCommit}
|
|
1518
|
+
onEnterEdit={enterCellEdit}
|
|
1294
1519
|
/>
|
|
1295
1520
|
)
|
|
1296
1521
|
} else {
|
|
1297
1522
|
content = flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
1298
1523
|
}
|
|
1299
1524
|
// Consumer 自訂 cell(無 colType)若回傳 React element,視為 compound — consumer 自己處理
|
|
1300
|
-
// 對齊與截斷。回傳 primitive(string / number)才走
|
|
1301
|
-
// 理由:
|
|
1525
|
+
// 對齊與截斷。回傳 primitive(string / number)才走 TruncatedText。
|
|
1526
|
+
// 理由:TruncatedText 的 `span.truncate` 強制 white-space:nowrap + inline baseline,
|
|
1302
1527
|
// 對 inline-flex / icon+text 自訂結構會拉歪(見 circular-progress sync table 案例)。
|
|
1303
1528
|
// **edit mode bypass**(2026-05-05 v9 Bug 2 修):editing cell 內部是 Field 控件
|
|
1304
1529
|
// (Input/Textarea/Select etc.)自管 layout + 替代元素(textarea)不該被包進 inline span
|
|
@@ -1307,15 +1532,15 @@ function DataTableInner<TData>(
|
|
|
1307
1532
|
return isEditingThisCell ? content
|
|
1308
1533
|
: wrap ? <span className="break-words min-w-0">{content}</span>
|
|
1309
1534
|
: (isKnownCompound || isConsumerCompound) ? content
|
|
1310
|
-
: <
|
|
1535
|
+
: <TruncatedText>{content}</TruncatedText>
|
|
1311
1536
|
}
|
|
1312
1537
|
|
|
1313
1538
|
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
|
|
1314
1539
|
const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
1315
1540
|
|
|
1316
1541
|
// 2026-05-09 D-path retired:`getEditIndicator(colType)` parallel system 移除。
|
|
1317
|
-
// Indicator authority 從 DataTable cellEl 移交 **Field naked-
|
|
1318
|
-
// — Select / TimePicker / DatePicker / Combobox / PeoplePicker 5 picker 的
|
|
1542
|
+
// Indicator authority 從 DataTable cellEl 移交 **Field naked-view branch via `showDisplayEndIcon` opt-in**
|
|
1543
|
+
// — Select / TimePicker / DatePicker / Combobox / PeoplePicker 5 picker 的 view mode 內建
|
|
1319
1544
|
// `<ItemSuffix>` 渲對應 trigger icon(同 edit DOM 結構)。LinkInput URL anchor 例外(無 suffix)。
|
|
1320
1545
|
// SSOT chain:cell-registry.tsx(opt-in props)→ Field component(intrinsic icon + ItemSuffix DOM)→
|
|
1321
1546
|
// item-anatomy ItemPrefix/ItemSuffix layout SSOT。詳 `.claude/planning/cell-indicator-ssot-rfc.md`。
|
|
@@ -1325,8 +1550,8 @@ function DataTableInner<TData>(
|
|
|
1325
1550
|
const dragDisabled = sorting.length > 0
|
|
1326
1551
|
|
|
1327
1552
|
// ── L4 Row drag v2:nested rows + parent map ─────────────────────────────────
|
|
1328
|
-
// v2 cross-parent fix:全 row
|
|
1329
|
-
// 過濾掉 cross-parent over candidates,保留「同 parent siblings」。沒命中 → invalid drop signal。
|
|
1553
|
+
// v2 cross-parent fix:全 row 各自掛 useDraggable/useDroppable(含 sub-rows;v15 無 SortableContext),
|
|
1554
|
+
// custom collisionDetection 過濾掉 cross-parent over candidates,保留「同 parent siblings」。沒命中 → invalid drop signal。
|
|
1330
1555
|
// parentMap: rowId → parentId(top-level row 的 parent = '' 哨兵 string)
|
|
1331
1556
|
const { allRowIds, parentMap } = React.useMemo(() => {
|
|
1332
1557
|
const ids: string[] = []
|
|
@@ -1362,13 +1587,13 @@ function DataTableInner<TData>(
|
|
|
1362
1587
|
const rowId = cell.row.id
|
|
1363
1588
|
const rowOriginal = cell.row.original
|
|
1364
1589
|
const isDisabled = isRowSelectable ? !isRowSelectable(rowOriginal) : false
|
|
1365
|
-
const ariaLabel = getRowAriaLabel?.(rowOriginal) ?? '
|
|
1590
|
+
const ariaLabel = getRowAriaLabel?.(rowOriginal) ?? '選取此列'
|
|
1366
1591
|
const checkboxSize = size === 'lg' ? 'lg' : 'md'
|
|
1367
1592
|
// Cell 整格可點:click cell padding 也觸發 toggle/select(對齊 Linear / Apple Mail / Material DataGrid)
|
|
1368
1593
|
// 內部 checkbox/radio 用 stopPropagation 避免 double-fire
|
|
1369
1594
|
const onCellClick = isDisabled ? undefined : (e: React.MouseEvent) => {
|
|
1370
1595
|
e.stopPropagation()
|
|
1371
|
-
if (mode === 'single') setSelection([rowId])
|
|
1596
|
+
if (mode === 'single') setSelection({ mode: 'include', ids: [rowId] })
|
|
1372
1597
|
else toggleRow(rowId, rowOriginal, { shiftKey: e.shiftKey })
|
|
1373
1598
|
}
|
|
1374
1599
|
return (
|
|
@@ -1395,7 +1620,7 @@ function DataTableInner<TData>(
|
|
|
1395
1620
|
) : (
|
|
1396
1621
|
<Checkbox
|
|
1397
1622
|
size={checkboxSize}
|
|
1398
|
-
checked={
|
|
1623
|
+
checked={isSelectedId(rowId)}
|
|
1399
1624
|
disabled={isDisabled}
|
|
1400
1625
|
aria-label={ariaLabel}
|
|
1401
1626
|
onClick={(e) => {
|
|
@@ -1423,17 +1648,15 @@ function DataTableInner<TData>(
|
|
|
1423
1648
|
const cellRowId = cell.row.id
|
|
1424
1649
|
const cellColId = cell.column.id
|
|
1425
1650
|
const cellEditable = isCellEditable(meta, cell.row.original)
|
|
1426
|
-
const cellDisabled = isCellDisabled(meta, cell.row.original)
|
|
1427
1651
|
const isEditingThisCell = editingCellId === cellEditId(cellRowId, cellColId)
|
|
1428
|
-
// Indicator canonical(2026-05-09 D-path retire):**Field naked-
|
|
1652
|
+
// Indicator canonical(2026-05-09 D-path retire):**Field naked-view branch own** via
|
|
1429
1653
|
// `showDisplayEndIcon` opt-in(per-picker `<ItemSuffix>` 渲 ChevronDown/Calendar/Clock)。
|
|
1430
1654
|
// DataTable cellEl 不再 render parallel indicator — SSOT 對齊 Field family。
|
|
1431
1655
|
// 詳 `.claude/planning/cell-indicator-ssot-rfc.md` Step 9。
|
|
1432
1656
|
// Cell click → 進 edit mode(boolean 不需 — 自己 toggle;url 不需 — 走內部 Pencil button,Phase C 由 UrlCell 內處理)
|
|
1433
1657
|
const cellSpreadsheetId = `${cellRowId}:${cellColId}`
|
|
1434
1658
|
const isSelectedCell = spreadsheetMode && selectedCellId === cellSpreadsheetId
|
|
1435
|
-
|
|
1436
|
-
const onEditableCellClick = cellEditable && !cellDisabled && colType !== 'boolean' && colType !== 'url' && !isEditingThisCell
|
|
1659
|
+
const onEditableCellClick = cellEditable && colType !== 'boolean' && colType !== 'url' && !isEditingThisCell
|
|
1437
1660
|
? (e: React.MouseEvent) => {
|
|
1438
1661
|
if (spreadsheetMode) {
|
|
1439
1662
|
// Slice D Step 4 spreadsheet semantics(2026-05-10 user 拍板,2026-05-12 v2 fix):
|
|
@@ -1477,7 +1700,13 @@ function DataTableInner<TData>(
|
|
|
1477
1700
|
const canExpand = cell.row.getCanExpand?.() ?? false
|
|
1478
1701
|
const isExpanded = cell.row.getIsExpanded?.() ?? false
|
|
1479
1702
|
const toggleExpand = cell.row.getToggleExpandedHandler?.()
|
|
1480
|
-
|
|
1703
|
+
// 2026-07-08 sibling-aware 佔位(WM root-cause 戰役):spec:382「同層 sibling 有 expandable
|
|
1704
|
+
// 時 leaf 也佔位」原本沒實作 — depth-0 leaf(無 children 的頂層列)拿不到 w-4+mr-2 佔位,
|
|
1705
|
+
// 與同層有 chevron 的列左緣錯位(PDF「chevron 空間」問題)。同層 = 同 parent 的 subRows;
|
|
1706
|
+
// 頂層 = core rows。只在 isFirstContent 時計算,成本一列一次。
|
|
1707
|
+
const siblingRows = cell.row.getParentRow?.()?.subRows ?? table.getCoreRowModel().rows
|
|
1708
|
+
const siblingHasExpand = isFirstContent && siblingRows.some((r) => r.getCanExpand?.() ?? false)
|
|
1709
|
+
const showNestedPrefix = isFirstContent && (depth > 0 || canExpand || siblingHasExpand)
|
|
1481
1710
|
// Issue 9 cell error(2026-05-10):lookup `${rowId}:${colId}` in cellErrors map
|
|
1482
1711
|
// editing cell 自動 clear visual error(per spec 「edit-clears-own-cell」)— consumer 走
|
|
1483
1712
|
// onCellCommit 驗證後決定回填新 error(由 consumer 端控制 cellErrors map state)。
|
|
@@ -1503,7 +1732,7 @@ function DataTableInner<TData>(
|
|
|
1503
1732
|
role="cell"
|
|
1504
1733
|
// group/cell + data-row-mode:讓 Field naked 用 `group-data-[row-mode=...]/cell:items-X`
|
|
1505
1734
|
// 從 cell 取 alignment(autoRowHeight=auto 頂對齊 / fixed=fixed 置中)。CSS propagation,
|
|
1506
|
-
// Field API 不變;每個 mode 內
|
|
1735
|
+
// Field API 不變;每個 mode 內 view↔edit 同 alignment(同 Field, 同 group → 同 items)。
|
|
1507
1736
|
// H1(2026-05-10):per-row error → effectiveAutoRowForCell 同 row.tsx effectiveAutoRow
|
|
1508
1737
|
data-row-mode={effectiveAutoRowForCell ? 'auto' : 'fixed'}
|
|
1509
1738
|
data-column-id={cell.column.id}
|
|
@@ -1513,8 +1742,6 @@ function DataTableInner<TData>(
|
|
|
1513
1742
|
// Phase 9 Issue 1 fix(2026-05-10):range cell bg fill via CSS [data-range-cell],
|
|
1514
1743
|
// 不在 overlay layer(避免 layer fixed-position bg 蓋 cell content)。
|
|
1515
1744
|
data-range-cell={spreadsheetMode && rangeCellIdSet.has(`${cell.row.id}:${cell.column.id}`) ? '' : undefined}
|
|
1516
|
-
// 2026-05-13 V1.6:data-cell-disabled attribute 給 CSS `:not([data-cell-disabled])` 過濾,disabled cell 不被 range fill 蓋
|
|
1517
|
-
data-cell-disabled={cellDisabled ? 'true' : undefined}
|
|
1518
1745
|
// Issue 9 cell error(2026-05-10):aria-describedby 接 error message id 給 AT 讀
|
|
1519
1746
|
aria-describedby={cellErrorId}
|
|
1520
1747
|
aria-invalid={hasCellError || undefined}
|
|
@@ -1529,7 +1756,11 @@ function DataTableInner<TData>(
|
|
|
1529
1756
|
// 「框框跟 cell 一樣大並取代 cell 的框且與 table 隔線無縫接軌」(2026-05-05)。
|
|
1530
1757
|
// - **沒有** cell 自己 box-shadow ring — focus / hover / open ring 由 Field naked 自帶
|
|
1531
1758
|
// state machine 提供(對齊 user「狀態樣式取決於原輸入框」reminder)
|
|
1532
|
-
|
|
1759
|
+
// 字級隨 size:sm/md text-body / lg text-body-lg(fieldDisplayTextClass),對齊 Field family
|
|
1760
|
+
// size→font SSOT。此為非-Field content(consumer 自訂 cell / TruncatedText 純文字)的 fallback 字級;
|
|
1761
|
+
// typed cell 各自的 Field 控件已自帶 size→font(cell-registry 傳 size)。
|
|
1762
|
+
'group/cell flex text-foreground font-normal shrink-0 relative self-stretch',
|
|
1763
|
+
fieldDisplayTextClass(size),
|
|
1533
1764
|
// Issue 9(2026-05-10):有 cell error → unset overflow-hidden 讓 error message
|
|
1534
1765
|
// wrap 撐 row 高。**H1(2026-05-10)升級**:overflow-visible 條件改 `rowHasAnyError` —
|
|
1535
1766
|
// row 內任一 cell 有 error 整 row 全 cells 都 overflow-visible(error 訊息可能多行
|
|
@@ -1541,22 +1772,24 @@ function DataTableInner<TData>(
|
|
|
1541
1772
|
// Phase 9 Issue 8 fix(2026-05-10 user 撞 + codex 重比稿 verdict ADOPT):
|
|
1542
1773
|
// 之前 `border-r border-divider` 只 right edge → hover overlay outline:-1px 只 right
|
|
1543
1774
|
// 邊壓 cell border,上左下 sub-pixel 不一致(user 抓「右 1px / 上左下 2px」bug)。
|
|
1544
|
-
// 改 `dtCellGrid`
|
|
1545
|
-
//
|
|
1546
|
-
//
|
|
1775
|
+
// 改 `dtCellGrid`(data-table.css「dtCellGrid v2/v3」段)box-shadow inset **只保右邊**
|
|
1776
|
+
// `inset -1px 0 0 var(--divider)`(bottom 由 row border-b 接管、:last-child 設 none 防 2px;
|
|
1777
|
+
// 2026-07-04 對齊 css 現況 — 原「4 邊 inset」敘述已被 v2/v3 取代),不佔 layout
|
|
1778
|
+
// (per user verbatim「在 cell 內容起始位置不變」前提)→ 視覺 4 邊 grid line 由
|
|
1779
|
+
// row border + 相鄰 cell 合成 → overlay outline:-1px 壓 cell border line。
|
|
1547
1780
|
// Field naked edit border 仍 own(per Field SSOT)— 編輯時 Field 自帶 border 1px,
|
|
1548
1781
|
// 跟 cell 4 邊 inset divider 視覺相疊(同 pixel)= 1 line visual,不雙線。
|
|
1549
1782
|
inlineEdit && 'dtCellGrid',
|
|
1550
|
-
onEditableCellClick && ['cursor-pointer', nakedCellEditableDisplayHover], // editable cell
|
|
1551
|
-
// 2026-
|
|
1552
|
-
//
|
|
1553
|
-
|
|
1783
|
+
onEditableCellClick && ['cursor-pointer', nakedCellEditableDisplayHover], // editable cell view hover affordance(對齊 Notion / Airtable hover-cell-shows-border canonical)
|
|
1784
|
+
// a11y(2026-07-14 dim-10 修):非 spreadsheet inlineEdit cell 可 Tab 聚焦(見下方
|
|
1785
|
+
// tabIndex/onKeyDown)— focus-visible ring 對齊本檔 expand button / sortable header canonical。
|
|
1786
|
+
onEditableCellClick && !spreadsheetMode && 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
|
|
1554
1787
|
// z-10 raise inline-edit cell;portal mode 不需(layer z-3 already on top)。
|
|
1555
1788
|
isEditingThisCell && !experimentalActiveEditorController && 'z-10',
|
|
1556
1789
|
)}
|
|
1557
1790
|
style={{
|
|
1558
1791
|
...columnSizeStyle(cell.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(cell.column.id) }),
|
|
1559
|
-
// Padding override 只在 inline-edit cell(naked Field 撐滿 cell);portal mode cell 走正常
|
|
1792
|
+
// Padding override 只在 inline-edit cell(naked Field 撐滿 cell);portal mode cell 走正常 view padding
|
|
1560
1793
|
...(isEditingThisCell && !experimentalActiveEditorController ? {} : cellPadding),
|
|
1561
1794
|
// Slice D Step 2(2026-05-10):flag 開時 set CSS variable 抑制 Field naked hover outline,
|
|
1562
1795
|
// 讓 overlay layer 接管 hover ring paint(per RFC Contract 8 「one geometry owner, two paint owners」)。
|
|
@@ -1564,9 +1797,22 @@ function DataTableInner<TData>(
|
|
|
1564
1797
|
...(experimentalSpreadsheetOverlay && { '--cell-hover-outline-color': 'transparent' } as React.CSSProperties),
|
|
1565
1798
|
}}
|
|
1566
1799
|
onClick={onEditableCellClick}
|
|
1800
|
+
// a11y(2026-07-14 dim-10 修):非 spreadsheet 的 inlineEdit cell 原本只有 onClick —
|
|
1801
|
+
// 鍵盤 user 無法聚焦 cell、無法進入編輯(WCAG 2.1.1)。對齊 Atlassian InlineEdit
|
|
1802
|
+
// read-view-focusable idiom:editable view cell 可 Tab 聚焦,Enter / F2 進 edit。
|
|
1803
|
+
// spreadsheetMode 不加(該模式走 table-level selectedCellId 鍵盤導覽 SSOT,per-cell
|
|
1804
|
+
// tab stop 會跟 roving 模型衝突);cell 內 embedded 控件事件不攔(target guard)。
|
|
1805
|
+
tabIndex={onEditableCellClick && !spreadsheetMode ? 0 : undefined}
|
|
1806
|
+
onKeyDown={onEditableCellClick && !spreadsheetMode ? (e) => {
|
|
1807
|
+
if (e.target !== e.currentTarget) return
|
|
1808
|
+
if (e.key === 'Enter' || e.key === 'F2') {
|
|
1809
|
+
e.preventDefault()
|
|
1810
|
+
setEditingCellId(cellEditId(cellRowId, cellColId))
|
|
1811
|
+
}
|
|
1812
|
+
} : undefined}
|
|
1567
1813
|
>
|
|
1568
1814
|
{/* Issue 9 cell error(2026-05-10):有 error → cell 內外結構切 flex-col,
|
|
1569
|
-
上 row 渲既有 nested + content,下 row 渲 error message
|
|
1815
|
+
上 row 渲既有 nested + content,下 row 渲 error message `text-body text-error`。
|
|
1570
1816
|
無 error 時走原 flex-row(backward-compat 0 layout shift)。 */}
|
|
1571
1817
|
{hasCellError ? (
|
|
1572
1818
|
<span className="flex flex-col self-stretch w-full min-w-0 gap-1">
|
|
@@ -1581,7 +1827,7 @@ function DataTableInner<TData>(
|
|
|
1581
1827
|
type="button"
|
|
1582
1828
|
aria-label={isExpanded ? '收合' : '展開'}
|
|
1583
1829
|
aria-expanded={isExpanded}
|
|
1584
|
-
className="inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-
|
|
1830
|
+
className="inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-fg-secondary rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-transform motion-reduce:duration-0"
|
|
1585
1831
|
style={{ transform: isExpanded ? 'rotate(90deg)' : undefined }}
|
|
1586
1832
|
onClick={(e) => { e.stopPropagation(); toggleExpand?.() }}
|
|
1587
1833
|
>
|
|
@@ -1626,7 +1872,7 @@ function DataTableInner<TData>(
|
|
|
1626
1872
|
type="button"
|
|
1627
1873
|
aria-label={isExpanded ? '收合' : '展開'}
|
|
1628
1874
|
aria-expanded={isExpanded}
|
|
1629
|
-
className="inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-
|
|
1875
|
+
className="inline-flex items-center justify-center shrink-0 w-4 h-4 mr-2 text-fg-muted hover:text-fg-secondary rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-transform motion-reduce:duration-0"
|
|
1630
1876
|
style={{ transform: isExpanded ? 'rotate(90deg)' : undefined }}
|
|
1631
1877
|
onClick={(e) => { e.stopPropagation(); toggleExpand?.() }}
|
|
1632
1878
|
>
|
|
@@ -1662,8 +1908,10 @@ function DataTableInner<TData>(
|
|
|
1662
1908
|
React.useEffect(() => {
|
|
1663
1909
|
if (!enabled || preserveSelectionOnFilter) return
|
|
1664
1910
|
setSelection(prev => {
|
|
1665
|
-
|
|
1666
|
-
|
|
1911
|
+
// all 模式 = 「全部符合當前 filter」→ 不清(excluded 留著,被 filter 掉的 excluded 列無害)
|
|
1912
|
+
if (prev.mode === 'all') return prev
|
|
1913
|
+
const filtered = prev.ids.filter(id => visibleRowIdsSet.has(id))
|
|
1914
|
+
return filtered.length === prev.ids.length ? prev : { mode: 'include', ids: filtered }
|
|
1667
1915
|
})
|
|
1668
1916
|
}, [visibleRowIdsKey, enabled, preserveSelectionOnFilter, visibleRowIdsSet, setSelection])
|
|
1669
1917
|
|
|
@@ -1675,9 +1923,22 @@ function DataTableInner<TData>(
|
|
|
1675
1923
|
.map(r => r.id)
|
|
1676
1924
|
}, [rows, enabled, isRowSelectable])
|
|
1677
1925
|
|
|
1926
|
+
// Union-aware「某列是否選取」+ 計數(include = ids 內;all = 不在 excluded 內)
|
|
1927
|
+
const includeSet = React.useMemo(
|
|
1928
|
+
() => (selection.mode === 'include' ? new Set(selection.ids) : new Set<string>()),
|
|
1929
|
+
[selection],
|
|
1930
|
+
)
|
|
1931
|
+
const excludeSet = React.useMemo(
|
|
1932
|
+
() => (selection.mode === 'all' ? new Set(selection.excluded) : new Set<string>()),
|
|
1933
|
+
[selection],
|
|
1934
|
+
)
|
|
1935
|
+
const isSelectedId = React.useCallback(
|
|
1936
|
+
(id: string) => (selection.mode === 'include' ? includeSet.has(id) : !excludeSet.has(id)),
|
|
1937
|
+
[selection.mode, includeSet, excludeSet],
|
|
1938
|
+
)
|
|
1939
|
+
const hasAnySelection = selection.mode === 'all' || includeSet.size > 0
|
|
1678
1940
|
// Header tri-state checkbox value
|
|
1679
|
-
const
|
|
1680
|
-
const visibleSelectedCount = selectableVisibleIds.filter(id => selectionSet.has(id)).length
|
|
1941
|
+
const visibleSelectedCount = selectableVisibleIds.filter(id => isSelectedId(id)).length
|
|
1681
1942
|
const headerCheckedState: boolean | 'indeterminate' =
|
|
1682
1943
|
selectableVisibleIds.length === 0 ? false
|
|
1683
1944
|
: visibleSelectedCount === 0 ? false
|
|
@@ -1691,20 +1952,16 @@ function DataTableInner<TData>(
|
|
|
1691
1952
|
)
|
|
1692
1953
|
|
|
1693
1954
|
const toggleHeaderCheckbox = React.useCallback(() => {
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
} else {
|
|
1699
|
-
// 選全可見(扣除 disabled);保留可見外的既有 selection
|
|
1700
|
-
setSelection(prev => Array.from(new Set([...prev, ...selectableVisibleIds])))
|
|
1701
|
-
}
|
|
1955
|
+
// header tri-state visible-scoped:全可見已選 → 取消可見;否則 → 選全可見。
|
|
1956
|
+
// include / all 兩模型由 applySelectIds 處理(all 模式 toggle 改寫 excluded)。
|
|
1957
|
+
const willSelect = headerCheckedState !== true
|
|
1958
|
+
setSelection(prev => applySelectIds(prev, selectableVisibleIds, willSelect))
|
|
1702
1959
|
}, [headerCheckedState, selectableVisibleIds, setSelection])
|
|
1703
1960
|
|
|
1704
1961
|
const toggleRow = React.useCallback((rowId: string, rowOriginal: TData, opts?: { shiftKey?: boolean }) => {
|
|
1705
1962
|
if (isRowSelectable && !isRowSelectable(rowOriginal)) return
|
|
1706
1963
|
if (mode === 'single') {
|
|
1707
|
-
setSelection(
|
|
1964
|
+
setSelection(isSelectedId(rowId) ? { mode: 'include', ids: [] } : { mode: 'include', ids: [rowId] })
|
|
1708
1965
|
anchorRowIdRef.current = rowId
|
|
1709
1966
|
return
|
|
1710
1967
|
}
|
|
@@ -1722,24 +1979,16 @@ function DataTableInner<TData>(
|
|
|
1722
1979
|
return row && (!isRowSelectable || isRowSelectable(row.original))
|
|
1723
1980
|
})
|
|
1724
1981
|
// Mail / GitHub 慣例:shift-click 把 range 全變「rowId 點擊後該變的狀態」
|
|
1725
|
-
const willCheck = !
|
|
1726
|
-
setSelection(prev =>
|
|
1727
|
-
const set = new Set(prev)
|
|
1728
|
-
rangeIds.forEach(id => willCheck ? set.add(id) : set.delete(id))
|
|
1729
|
-
return Array.from(set)
|
|
1730
|
-
})
|
|
1982
|
+
const willCheck = !isSelectedId(rowId)
|
|
1983
|
+
setSelection(prev => applySelectIds(prev, rangeIds, willCheck))
|
|
1731
1984
|
return
|
|
1732
1985
|
}
|
|
1733
1986
|
}
|
|
1734
|
-
// 一般 toggle + 更新 anchor
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
if (set.has(rowId)) set.delete(rowId)
|
|
1738
|
-
else set.add(rowId)
|
|
1739
|
-
return Array.from(set)
|
|
1740
|
-
})
|
|
1987
|
+
// 一般 toggle + 更新 anchor(include / all 由 applySelectIds 處理)
|
|
1988
|
+
const willCheck = !isSelectedId(rowId)
|
|
1989
|
+
setSelection(prev => applySelectIds(prev, [rowId], willCheck))
|
|
1741
1990
|
anchorRowIdRef.current = rowId
|
|
1742
|
-
}, [isRowSelectable, mode,
|
|
1991
|
+
}, [isRowSelectable, mode, isSelectedId, rows, visibleIdToRow, setSelection])
|
|
1743
1992
|
|
|
1744
1993
|
// ── Cmd+A / Esc / Arrow keys 鍵盤 handler(table-level)──
|
|
1745
1994
|
// code-quality-allow: long-function — single keyboard dispatch covering Cmd+A / Esc / Arrow / Space + selection state mutations,拆 sub-handler 會切散 keyboard mode coherence
|
|
@@ -1752,7 +2001,33 @@ function DataTableInner<TData>(
|
|
|
1752
2001
|
// Phase B3 IME guard(2026-05-10 per codex Q-B3):中文輸入法組字中 ignore 所有 nav keys。
|
|
1753
2002
|
// 2026-05-16 Round 5 audit Dim 27 fix:`keyCode` deprecated but still in KeyboardEvent type — no cast needed。
|
|
1754
2003
|
if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return
|
|
1755
|
-
|
|
2004
|
+
// 2026-07-14 dim-10 修:spreadsheet 分支排除 descendant 互動控件 — 焦點在 cell 內
|
|
2005
|
+
// action button / link / input 時,Enter 應 activate 該控件、方向鍵交還控件,
|
|
2006
|
+
// 原 handler 會 preventDefault 取消按鈕 activation、拿舊 selectedCellId 導覽。
|
|
2007
|
+
// 對齊下方 row-selection 分支 2026-07-09 既有 input-family guard + AG Grid
|
|
2008
|
+
// embedded-control convention(cell renderer 內控件 own keyboard)。
|
|
2009
|
+
const spreadsheetKbTarget = e.target as HTMLElement | null
|
|
2010
|
+
const targetIsEmbeddedControl = !!spreadsheetKbTarget?.closest?.(
|
|
2011
|
+
'button, a[href], input, select, textarea, [contenteditable="true"]',
|
|
2012
|
+
)
|
|
2013
|
+
// 2026-07-05 D4 fix:spreadsheet 鍵盤入口 — selection 尚未建立時按方向鍵,seed 第一個
|
|
2014
|
+
// visible cell(原本唯一 set 起點是 mouse click → 鍵盤-only 使用者 Tab 進 table 後方向鍵
|
|
2015
|
+
// 全 no-op,整個 spreadsheet 導覽被滑鼠 gate,違反 spec「鍵盤完整可操作」驗證宣稱。
|
|
2016
|
+
// 對齊 Excel / Google Sheets / AG Grid「focus grid → first cell active」canonical)。
|
|
2017
|
+
if (spreadsheetMode && !targetIsEmbeddedControl && selectedCellId == null && editingCellId == null
|
|
2018
|
+
&& ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
|
|
2019
|
+
const allRows = table.getRowModel().rows.map((r) => r.id)
|
|
2020
|
+
const allCols = table.getVisibleLeafColumns().map((c) => c.id).filter((id) => id !== SELECT_COL_ID)
|
|
2021
|
+
if (allRows.length > 0 && allCols.length > 0) {
|
|
2022
|
+
e.preventDefault()
|
|
2023
|
+
const firstCellId = `${allRows[0]}:${allCols[0]}`
|
|
2024
|
+
setSelectedCellId(firstCellId)
|
|
2025
|
+
setRangeAnchor(firstCellId)
|
|
2026
|
+
setRangeFocus(null)
|
|
2027
|
+
}
|
|
2028
|
+
return
|
|
2029
|
+
}
|
|
2030
|
+
if (spreadsheetMode && !targetIsEmbeddedControl && selectedCellId != null && editingCellId == null) {
|
|
1756
2031
|
const navKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter', 'F2', 'Escape']
|
|
1757
2032
|
if (!navKeys.includes(e.key)) return
|
|
1758
2033
|
const lastColon = selectedCellId.lastIndexOf(':')
|
|
@@ -1770,8 +2045,7 @@ function DataTableInner<TData>(
|
|
|
1770
2045
|
else if (e.key === 'ArrowLeft' && curColIdx > 0) { nextColIdx = curColIdx - 1 }
|
|
1771
2046
|
else if (e.key === 'ArrowRight' && curColIdx < allCols.length - 1) { nextColIdx = curColIdx + 1 }
|
|
1772
2047
|
else if (e.key === 'Enter' || e.key === 'F2') {
|
|
1773
|
-
// Enter / F2 → 進 edit(若 cell editable + 非 boolean / url
|
|
1774
|
-
// 2026-05-13 codex V1 fix:加 `!isCellDisabled(meta, row)` gate(對齊 mouse click invariant)
|
|
2048
|
+
// Enter / F2 → 進 edit(若 cell editable + 非 boolean / url)。edit 入口統一走 canEditCell(= isCellEditable)。
|
|
1775
2049
|
const row = table.getRowModel().rowsById[curRowId]
|
|
1776
2050
|
const colDef = table.getAllLeafColumns().find((c) => c.id === curColId)
|
|
1777
2051
|
// any-allow: column meta free-form
|
|
@@ -1803,22 +2077,33 @@ function DataTableInner<TData>(
|
|
|
1803
2077
|
}
|
|
1804
2078
|
// ── Row selection mode keyboard handler(下方既有)──
|
|
1805
2079
|
if (!enabled) return
|
|
2080
|
+
// 2026-07-09 fix(圖一 Ctrl+A bug):焦點在可編輯輸入元素(cell edit / inline edit / 搜尋框)時,
|
|
2081
|
+
// 鍵盤(Cmd/Ctrl+A 全選、Esc)應交給該元素(全選 cell 文字 / 取消編輯),**不**攔成 row selection。
|
|
2082
|
+
// 對齊 Notion / Airtable / Linear:編輯格內 Ctrl+A = 選格內文字,非選全表列。
|
|
2083
|
+
const kbTarget = e.target as HTMLElement | null
|
|
2084
|
+
if (
|
|
2085
|
+
editingCellId != null ||
|
|
2086
|
+
(kbTarget && (kbTarget.tagName === 'INPUT' || kbTarget.tagName === 'TEXTAREA' || kbTarget.tagName === 'SELECT' || kbTarget.isContentEditable))
|
|
2087
|
+
) return
|
|
1806
2088
|
// Cmd/Ctrl+A:選全可見(扣 disabled)— 對齊 Mail / GitHub / Linear 慣例
|
|
1807
2089
|
if ((e.metaKey || e.ctrlKey) && e.key === 'a' && mode === 'multi') {
|
|
1808
2090
|
e.preventDefault()
|
|
1809
|
-
setSelection(prev =>
|
|
2091
|
+
setSelection(prev => applySelectIds(prev, selectableVisibleIds, true))
|
|
1810
2092
|
return
|
|
1811
2093
|
}
|
|
1812
2094
|
// Esc:clear selection
|
|
1813
|
-
if (e.key === 'Escape' &&
|
|
2095
|
+
if (e.key === 'Escape' && hasAnySelection) {
|
|
1814
2096
|
e.preventDefault()
|
|
1815
|
-
setSelection([])
|
|
2097
|
+
setSelection({ mode: 'include', ids: [] })
|
|
1816
2098
|
anchorRowIdRef.current = null
|
|
1817
2099
|
return
|
|
1818
2100
|
}
|
|
1819
2101
|
},
|
|
1820
|
-
|
|
1821
|
-
|
|
2102
|
+
// D3 dep-hygiene fix(2026-07-06):handler 內(portal edit Enter 分支)呼叫的是 canEditCell,
|
|
2103
|
+
// 非 isCellEditable — 原 deps 列 isCellEditable 是靠 canEditCell identity-stable 才無實害的
|
|
2104
|
+
// stale-closure 地雷;改列真實依賴 canEditCell(其 useCallback deps 已含 isCellEditable)。
|
|
2105
|
+
[enabled, mode, hasAnySelection, selectableVisibleIds, setSelection,
|
|
2106
|
+
spreadsheetMode, selectedCellId, editingCellId, table, canEditCell]
|
|
1822
2107
|
)
|
|
1823
2108
|
|
|
1824
2109
|
// ── Header cell ──
|
|
@@ -1841,7 +2126,7 @@ function DataTableInner<TData>(
|
|
|
1841
2126
|
checked={headerCheckedState}
|
|
1842
2127
|
onClick={(e) => e.stopPropagation()}
|
|
1843
2128
|
onCheckedChange={() => toggleHeaderCheckbox()}
|
|
1844
|
-
aria-label="
|
|
2129
|
+
aria-label="全選可見列"
|
|
1845
2130
|
disabled={selectableVisibleIds.length === 0}
|
|
1846
2131
|
/>
|
|
1847
2132
|
)}
|
|
@@ -1875,7 +2160,10 @@ function DataTableInner<TData>(
|
|
|
1875
2160
|
// absolute → hover 顯時佔位 → label 自動讓出空間給 sort + more,**不再重疊**(對齊
|
|
1876
2161
|
// user 圖示質疑 + Notion / Airtable header layout 共識)。
|
|
1877
2162
|
// cell padding 12px 由外層 cellPadding style 提供 → more 距 cell 右邊 = 12px。
|
|
1878
|
-
|
|
2163
|
+
// header 字級也隨 size(原寫死 text-body → lg 表格 header 字偏小,跟 body 不一致)。
|
|
2164
|
+
// 對齊 cell wrapper + Field family size→font SSOT。色弱化由 text-fg-secondary 維持。
|
|
2165
|
+
'group relative flex items-center gap-2 text-fg-secondary font-normal shrink-0 overflow-hidden select-none',
|
|
2166
|
+
fieldDisplayTextClass(size),
|
|
1879
2167
|
align === 'right' && 'justify-end',
|
|
1880
2168
|
align === 'center' && 'justify-center',
|
|
1881
2169
|
)}
|
|
@@ -1891,17 +2179,22 @@ function DataTableInner<TData>(
|
|
|
1891
2179
|
className={cn(
|
|
1892
2180
|
'flex items-center min-w-0 flex-1 gap-1 outline-none',
|
|
1893
2181
|
canSort && 'cursor-pointer hover:text-foreground transition-colors',
|
|
1894
|
-
|
|
2182
|
+
// 2026-07-04:rounded-sm → rounded-md(radius.spec.md 設計哲學(4)rounded-sm 保留未使用,4px 一律 rounded-md)
|
|
2183
|
+
canSort && 'focus-visible:ring-2 focus-visible:ring-ring rounded-md',
|
|
1895
2184
|
)}
|
|
1896
2185
|
>
|
|
1897
|
-
<
|
|
2186
|
+
<TruncatedText className={cn('min-w-0', align === 'right' && 'text-right', align === 'center' && 'text-center')}>
|
|
1898
2187
|
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
|
|
1899
|
-
</
|
|
2188
|
+
</TruncatedText>
|
|
1900
2189
|
{canSort && sortDir && !isMultiSort && (
|
|
1901
2190
|
// 2026-05-18 改 per user 拍板「DataTable sort 跟 row size 變」+「做完」approval:
|
|
1902
2191
|
// 原固定 14 違反 uiSize.spec.md Icon Tier(sm/md→16, lg→20)。改 ICON_SIZE[size]
|
|
1903
2192
|
// 隨 DataTable size prop 變。
|
|
1904
|
-
|
|
2193
|
+
// 顏色不釘死(2026-08-18 user 拍板「與 label 同色連動」):繼承點擊區文字色 —
|
|
2194
|
+
// 靜止 fg-secondary、hover 隨父層 hover:text-foreground 與 label 同升。禁 fg-muted
|
|
2195
|
+
//(muted 家 = 永遠在場的裝飾/affordance 標記;排序箭頭 = 套用後才出現的狀態資訊)、
|
|
2196
|
+
// 禁 primary。SSOT → data-table.spec.md「Header cell internal」表 sort arrow 顏色列。
|
|
2197
|
+
<SortIcon size={ICON_SIZE[size]} aria-hidden className="shrink-0" />
|
|
1905
2198
|
)}
|
|
1906
2199
|
</div>
|
|
1907
2200
|
{/* 右區:⌄ menu(hover/focus-within 才顯;**不顯示時不佔位**)
|
|
@@ -1985,16 +2278,40 @@ function DataTableInner<TData>(
|
|
|
1985
2278
|
const colOptIn = colMeta?.resizable !== false
|
|
1986
2279
|
const isResizable = enableColumnResize && !isSystemColumn(colId) && colOptIn
|
|
1987
2280
|
const isResizing = header.column.getIsResizing?.()
|
|
2281
|
+
// 鍵盤 resize(WAI-ARIA window-splitter):方向鍵調整欄寬,公開目前值 + 下限。
|
|
2282
|
+
// effectiveMinWidth 對齊 drag 路徑(resolveColumnSizing minSize),step 16px。
|
|
2283
|
+
const effectiveMinWidth = header.column.columnDef.minSize ?? MIN_COLUMN_WIDTH
|
|
2284
|
+
const currentWidth = Math.round(header.column.getSize())
|
|
2285
|
+
const RESIZE_KEY_STEP = 16
|
|
1988
2286
|
// H2: 不論 showDivider,只要 isResizable 就 render hot zone(panel boundary col 仍可拖)
|
|
1989
2287
|
if (!showDivider && !isResizable) return null
|
|
1990
2288
|
return (
|
|
1991
2289
|
<span
|
|
1992
2290
|
role={isResizable ? 'separator' : undefined}
|
|
1993
2291
|
aria-orientation={isResizable ? 'vertical' : undefined}
|
|
1994
|
-
aria-label={isResizable ? '
|
|
2292
|
+
aria-label={isResizable ? '調整欄寬' : undefined}
|
|
2293
|
+
// 鍵盤可操作 separator(WAI-ARIA window-splitter):focusable + 方向鍵調整 +
|
|
2294
|
+
// 公開目前寬度 / 下限。aria-valuetext 給 SR px 值(避免無 valuemax 時被誤讀成百分比)。
|
|
2295
|
+
tabIndex={isResizable ? 0 : undefined}
|
|
2296
|
+
aria-valuenow={isResizable ? currentWidth : undefined}
|
|
2297
|
+
aria-valuemin={isResizable ? effectiveMinWidth : undefined}
|
|
2298
|
+
aria-valuetext={isResizable ? `${currentWidth}px` : undefined}
|
|
2299
|
+
onKeyDown={isResizable ? (e: React.KeyboardEvent<HTMLSpanElement>) => {
|
|
2300
|
+
let next: number | null = null
|
|
2301
|
+
if (e.key === 'ArrowLeft') next = Math.max(effectiveMinWidth, currentWidth - RESIZE_KEY_STEP)
|
|
2302
|
+
else if (e.key === 'ArrowRight') next = currentWidth + RESIZE_KEY_STEP
|
|
2303
|
+
else if (e.key === 'Home') next = effectiveMinWidth
|
|
2304
|
+
if (next == null) return
|
|
2305
|
+
// stopPropagation:不讓方向鍵冒泡到 header 排序 / 欄位拖曳 keyboard listener。
|
|
2306
|
+
e.preventDefault()
|
|
2307
|
+
e.stopPropagation()
|
|
2308
|
+
table.setColumnSizing((prev) => ({ ...prev, [colId]: next as number }))
|
|
2309
|
+
// onColumnResize 由 columnSizing useEffect 自動 fire(非 drag 路徑不經 isResizingColumn)。
|
|
2310
|
+
} : undefined}
|
|
1995
2311
|
className={cn(
|
|
1996
2312
|
'group/resize absolute top-0 bottom-0 right-0 -mr-[3px] w-[7px]',
|
|
1997
2313
|
isResizable && 'cursor-col-resize select-none',
|
|
2314
|
+
isResizable && 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',
|
|
1998
2315
|
)}
|
|
1999
2316
|
// 2026-05-12 fix v2(user 抓 R3 stopPropagation 沒生效):dnd-kit PointerSensor
|
|
2000
2317
|
// 監聽 `pointerdown`,我前一輪只 stop `onMouseDown` → pointerdown 仍冒泡 →
|
|
@@ -2054,6 +2371,18 @@ function DataTableInner<TData>(
|
|
|
2054
2371
|
// 2026-05-06 v14.4 Notion blue line drop indicator(column reorder visual canonical)
|
|
2055
2372
|
// 必須宣告在 renderHeaderRow 之前(closure 引用,避 minified bundler TDZ false-positive)
|
|
2056
2373
|
const [dropIndicator, setDropIndicator] = React.useState<{ id: string; side: 'before' | 'after'; type: 'row' | 'column' } | null>(null)
|
|
2374
|
+
// 2026-07-05 D3 perf fix:shallow-compare setter — drag 中每次 over 變更 handleDragOver 都
|
|
2375
|
+
// set 全新 object,即使 id/side/type 沒變也觸發整個 DataTableInner 重渲(全 visible rows +
|
|
2376
|
+
// cells + header)。值相同 → 回傳 prev reference 讓 React bail out(對齊檔內 invalidRef guard
|
|
2377
|
+
// pattern;`setDropIndicator(null)` 自帶 Object.is bail out 不需經此)。
|
|
2378
|
+
const setDropIndicatorIfChanged = React.useCallback(
|
|
2379
|
+
(next: { id: string; side: 'before' | 'after'; type: 'row' | 'column' }) => {
|
|
2380
|
+
setDropIndicator((prev) =>
|
|
2381
|
+
prev && prev.id === next.id && prev.side === next.side && prev.type === next.type ? prev : next,
|
|
2382
|
+
)
|
|
2383
|
+
},
|
|
2384
|
+
[],
|
|
2385
|
+
)
|
|
2057
2386
|
// ref for stable lookup in handleDragOver(避免 closure 抓舊值)
|
|
2058
2387
|
const reorderableColumnIdsRef = React.useRef<string[]>([])
|
|
2059
2388
|
|
|
@@ -2074,7 +2403,7 @@ function DataTableInner<TData>(
|
|
|
2074
2403
|
const meta = h.column.columnDef.meta as { locked?: boolean } | undefined
|
|
2075
2404
|
const isLocked = meta?.locked === true
|
|
2076
2405
|
const isSystem = isSystemColumn(colId)
|
|
2077
|
-
//
|
|
2406
|
+
// useDraggable + useDroppable per header(Rules of Hooks compliant — same hook count per render
|
|
2078
2407
|
// as long as headers count consistent;column reorder/hide 整 row reflow 自然觸發 React reconcile)。
|
|
2079
2408
|
// disabled=true 時仍 call hook 不啟動 listeners。
|
|
2080
2409
|
const isDraggable = enableColumnReorder && !isLocked && !isSystem
|
|
@@ -2124,13 +2453,13 @@ function DataTableInner<TData>(
|
|
|
2124
2453
|
const isPrimaryRegion = isCenter
|
|
2125
2454
|
const regionRole: 'primary' | 'mirror' = isPrimaryRegion ? 'primary' : 'mirror'
|
|
2126
2455
|
|
|
2127
|
-
// code-quality-allow: long-function — virtualizer × sticky panel × drag listeners × hover delegation × per-row state 多 closure capture;拆會破壞
|
|
2456
|
+
// code-quality-allow: long-function — virtualizer × sticky panel × drag listeners × hover delegation × per-row state 多 closure capture;拆會破壞 dnd-kit hooks 跟 row idx 的 stable binding
|
|
2128
2457
|
const rowEl = (row: typeof rows[number], idx: number, opts?: { virtual?: boolean; start?: number; isLast?: boolean }) => {
|
|
2129
2458
|
const showBorder = bordered !== false ? !opts?.isLast : true
|
|
2130
|
-
// L4 row drag v2:nested rows
|
|
2131
|
-
// sub-rows: depth>0
|
|
2459
|
+
// L4 row drag v2:nested rows 也可拖(配合 cross-parent collisionDetection 過濾)
|
|
2460
|
+
// sub-rows: depth>0 也各自掛 useDraggable/useDroppable,但 collisionDetection 只接受 same-parent over
|
|
2132
2461
|
const isThisRowDragging = enableRowDrag && activeDragId === row.id
|
|
2133
|
-
const
|
|
2462
|
+
const dragRowWrap = enableRowDrag
|
|
2134
2463
|
|
|
2135
2464
|
// H1 fix(2026-05-10,per user 確認):per-row autoRowHeight when any cell in this row has
|
|
2136
2465
|
// error。Fixed-height row 模式下,該 row 的任一 cell 有 error msg → THAT row 自動 auto-height
|
|
@@ -2145,8 +2474,9 @@ function DataTableInner<TData>(
|
|
|
2145
2474
|
const effectiveAutoRow = autoRowHeight || rowHasError
|
|
2146
2475
|
|
|
2147
2476
|
// L4 row drag:handle absolute 貼齊 row 左 border(Jira canonical),不佔 column 空間。
|
|
2148
|
-
// 只在 primary region
|
|
2149
|
-
// 內部再用 ctx.role === 'primary' 守門避免
|
|
2477
|
+
// 只在 primary region + depth===0 render — primary 永遠 = center(v15.4 撤銷「left 優先」,
|
|
2478
|
+
// 見上方 isPrimaryRegion 註解);RowDragHandle 內部再用 ctx.role === 'primary' 守門避免
|
|
2479
|
+
// mirror region 重複 render。
|
|
2150
2480
|
const showDragHandle = enableRowDrag && (row.depth ?? 0) === 0 && isPrimaryRegion
|
|
2151
2481
|
// v15.2 SSOT 對齊 TreeView:drag 期間 suppress 全表 hover state
|
|
2152
2482
|
// (user directive「drag 時 row 不應 hover / drag button 不應出現」)
|
|
@@ -2184,7 +2514,10 @@ function DataTableInner<TData>(
|
|
|
2184
2514
|
// 找 source row(避免 multi-region 場景挑錯 region 的 row 當 ghost)
|
|
2185
2515
|
data-row-drag-source={enableRowDrag && isPrimaryRegion ? 'true' : undefined}
|
|
2186
2516
|
role="row"
|
|
2187
|
-
|
|
2517
|
+
// L5 分頁(2026-07-07 C13):rowindex 加分頁 offset — aria-rowcount 是全集,
|
|
2518
|
+
// 第 2 頁起 index 必須接續(否則 AT 讀到「第 129 列中的第 2 列」錯位);
|
|
2519
|
+
// 不可用 row.index(sort/filter 後是原始資料序,非視覺序)
|
|
2520
|
+
aria-rowindex={(paginationEnabled ? (currentPage - 1) * pageSizeState : 0) + idx + 2}
|
|
2188
2521
|
className={cn(
|
|
2189
2522
|
'group/row flex relative',
|
|
2190
2523
|
// H1 fix(2026-05-10):effectiveAutoRow 覆 global autoRowHeight,per-row 若有 cell error
|
|
@@ -2228,20 +2561,20 @@ function DataTableInner<TData>(
|
|
|
2228
2561
|
</div>
|
|
2229
2562
|
)
|
|
2230
2563
|
|
|
2231
|
-
if (
|
|
2564
|
+
if (dragRowWrap) {
|
|
2232
2565
|
// invalidDrop 只對「正在被拖」的 row 顯示 — handle 在 active row 上,UI 警示只需該 row
|
|
2233
|
-
// code-quality-allow: long-function — 此 const 之下的整個 if-block 含
|
|
2566
|
+
// code-quality-allow: long-function — 此 const 之下的整個 if-block 含 dnd-kit hooks + SortableRowProvider + baseRowDiv composition;audit 把 const 誤認為 function entry,實 long body 在 closure 內 dnd-kit + per-row state 多 capture,拆會破壞 hook order invariant
|
|
2234
2567
|
const rowInvalidDrop = isThisRowDragging && invalidDropActive
|
|
2235
2568
|
return (
|
|
2236
2569
|
<SortableRowProvider key={row.id} id={row.id} disabled={dragDisabled} role={regionRole} invalidDrop={rowInvalidDrop}>
|
|
2237
2570
|
{(ctx) => baseRowDiv({
|
|
2238
|
-
//
|
|
2239
|
-
//
|
|
2571
|
+
// primary 掛 useDraggable+useDroppable 合成 ref;mirror 只掛 useDroppable ref
|
|
2572
|
+
// (v15.4 split — mirror 不進 drag source store,isDragging 走 useDndContext 同步)
|
|
2240
2573
|
ref: ctx.setNodeRef,
|
|
2241
2574
|
style: ctx.style,
|
|
2242
2575
|
isDragging: ctx.isDragging,
|
|
2243
|
-
// v15.
|
|
2244
|
-
//
|
|
2576
|
+
// v15.6 button-only:rowListeners 恆 undefined(activator = RowDragHandle Button),
|
|
2577
|
+
// baseRowDiv spread `{...(extra?.listeners ?? {})}` 自動 noop;attributes 留空 = row 純 container
|
|
2245
2578
|
listeners: ctx.rowListeners,
|
|
2246
2579
|
attributes: ctx.rowAttributes,
|
|
2247
2580
|
})}
|
|
@@ -2302,7 +2635,8 @@ function DataTableInner<TData>(
|
|
|
2302
2635
|
// 行為:**永遠 hug rows**,只在被約束時才 cap + body shrink + V scroll。
|
|
2303
2636
|
// 簡單需求:有約束 → rows 沒超就 hug;超就 cap+scroll;RWD 同理。
|
|
2304
2637
|
style={isFillHeight ? { maxHeight: height } : undefined}
|
|
2305
|
-
|
|
2638
|
+
// L5 分頁:aria-rowcount = 全集筆數非當頁(ARIA 規範;getPrePaginationRowModel = filter 後全集)
|
|
2639
|
+
role="table" aria-rowcount={(paginationEnabled ? table.getPrePaginationRowModel().rows.length : rows.length) + 1}
|
|
2306
2640
|
// Phase 9 Issue 12 fix(2026-05-10 codex 抓):**single tabIndex prop**,合併 selection
|
|
2307
2641
|
// 跟 spreadsheet 兩 path。React 在 dup props 只 keep last 是 silent regression risk。
|
|
2308
2642
|
tabIndex={enabled || spreadsheetMode ? 0 : undefined}
|
|
@@ -2321,10 +2655,10 @@ function DataTableInner<TData>(
|
|
|
2321
2655
|
)}
|
|
2322
2656
|
{/* Header 的 center 區保持 overflow-hidden(非 scroll)—— body 的 center 才有 scroll,
|
|
2323
2657
|
header 靠 JS 同步 scrollLeft(見 onCenterBodyScroll)。這樣不會出現雙 scrollbar。
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2658
|
+
V scrollbar 對齊:centerBody **刻意不用** `scrollbar-gutter: stable`(決策見 centerBody
|
|
2659
|
+
className 註解 — 永久預留 15px 會讓 content-fit 看起來像恆有 V 捲軸);trade-off =
|
|
2660
|
+
V scroll 出現時 body 內側少 ~15px、header 不縮 → 右端微 misalign,content-fit 乾淨優先。
|
|
2661
|
+
header 的 `scrollbar-gutter` 本就無效(overflow-hidden),刻意不設 */}
|
|
2328
2662
|
<div
|
|
2329
2663
|
ref={centerHeaderRef}
|
|
2330
2664
|
data-datatable-header-panel="center"
|
|
@@ -2372,16 +2706,28 @@ function DataTableInner<TData>(
|
|
|
2372
2706
|
<div
|
|
2373
2707
|
ref={centerBodyRef}
|
|
2374
2708
|
// Center body 同時擁有 H + V scroll;maxHeight 限制讓 H scrollbar 落在 visible 底部
|
|
2375
|
-
// `scrollbar-gutter: stable` 永遠預留 V scrollbar 寬度(~15-17px),避免 body 出現 V
|
|
2376
|
-
// scrollbar 時右端被縮,跟 header 右端產生 gap(Windows/Linux native scrollbar 吃寬)
|
|
2377
2709
|
data-datatable-hscroll
|
|
2378
2710
|
data-datatable-panel="center"
|
|
2711
|
+
// a11y(scrollable-region-focusable,對齊 DS ScrollArea Viewport canonical):唯讀表格
|
|
2712
|
+
// 的可捲動 body 若無任何 focusable descendant,鍵盤使用者無法捲動。read-only 模式
|
|
2713
|
+
// (非 enabled / spreadsheet)outer table 也不 focusable → 這裡補 tabIndex=0 + 具名 +
|
|
2714
|
+
// inset focus ring,讓鍵盤可聚焦後方向鍵捲動;互動模式已由 outer table keyboard handler
|
|
2715
|
+
// + focusable cells 覆蓋,不重複加 tab stop。
|
|
2716
|
+
// **role="rowgroup" 必要**(2026-07-29 WM beta.95 axe 錨例):focusable 的無 role
|
|
2717
|
+
// 中間層會被 axe aria-required-children 視為 role="table" 的不合法 owned child,
|
|
2718
|
+
// 打斷 table→row ownership(修 scrollable-region-focusable 反引爆 required-children,
|
|
2719
|
+
// 與 Tabs 2026-07-18 決策1 同型)。rowgroup = W3C ARIA 1.2 合法 table 子代 + 可具名
|
|
2720
|
+
// (Name from author §5.2.8.4)+ 容納 rows,兩規則唯一同時滿足解。
|
|
2721
|
+
// 空表例外:Empty 塊非 row → 不掛 rowgroup;空表無 overflow 也無需 tabIndex/名稱。
|
|
2722
|
+
role={isEmpty ? undefined : 'rowgroup'}
|
|
2723
|
+
tabIndex={enabled || spreadsheetMode || isEmpty ? undefined : 0}
|
|
2724
|
+
aria-label={enabled || spreadsheetMode || isEmpty ? undefined : '表格內容,可捲動'}
|
|
2379
2725
|
// overflow-x/y: auto — 沒 overflow 就不顯 bar。wrapper minWidth 仍 trigger H 真 overflow。
|
|
2380
2726
|
// **不**用 scrollbar-gutter: stable — 那會永遠保留 V 軸 15px 空間,
|
|
2381
2727
|
// content fit 時看起來像「永遠有 V 捲軸」(Image #5 bug)。
|
|
2382
2728
|
// trade-off:V scroll 出現時 body 內側少 15px,header 不縮 → 右端微 misalign,
|
|
2383
2729
|
// 但 content fit 視覺乾淨優先(Mac 用戶 overlay scrollbar 不可見)。
|
|
2384
|
-
className="flex-1 min-w-0 overflow-x-auto overflow-y-auto"
|
|
2730
|
+
className="flex-1 min-w-0 overflow-x-auto overflow-y-auto focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring"
|
|
2385
2731
|
// isFillHeight:用 JS 算的 px(bodyMaxHeight),bypass CSS % 在 flex 場景的不可靠 shrink。
|
|
2386
2732
|
// 固定 px(300px etc):直接套 height。
|
|
2387
2733
|
style={
|
|
@@ -2434,7 +2780,7 @@ function DataTableInner<TData>(
|
|
|
2434
2780
|
activeEditorEnabled={experimentalActiveEditorController}
|
|
2435
2781
|
// Slice D Step 5(D.3 portal Field,2026-05-10):real portal Field render callback。
|
|
2436
2782
|
// Layer 在 ActiveEditorHost(z 3 float rect)render `<Cell mode="edit" />` 同 registry。
|
|
2437
|
-
// Cell wrapper 保持 mode="
|
|
2783
|
+
// Cell wrapper 保持 mode="view"(SSOT preserved per codex Q6.2)。
|
|
2438
2784
|
activeEditorRender={experimentalActiveEditorController ? (cellId) => {
|
|
2439
2785
|
const lastColon = cellId.lastIndexOf(':')
|
|
2440
2786
|
if (lastColon < 0) return null
|
|
@@ -2505,12 +2851,25 @@ function DataTableInner<TData>(
|
|
|
2505
2851
|
// 2026-05-13:canEditCell helper(per V4 consolidation,合 editable + !disabled invariant)
|
|
2506
2852
|
if (!nextRow || !canEditCell(nextMeta, nextRow.original)) continue
|
|
2507
2853
|
// 找到 next editable cell → commit current + start next edit
|
|
2854
|
+
// 2026-07-05 D4 fix:原本只 setEditingCellId —(a)同 type 相鄰 cell React 同位
|
|
2855
|
+
// 重用 input DOM,blur 不 fire → onBlur commit 不觸發,剛打的 draft 整段遺失;
|
|
2856
|
+
// (b)editingDraft 不清 → 下一格 portal value 顯示上一格草稿(甚至把上一格 draft
|
|
2857
|
+
// commit 進錯的 cell)。Fix:有 draft 先 commit 當前 cell(commitCell 內已清 draft),
|
|
2858
|
+
// 再換格;spreadsheet selection 對齊 edit-entry canonical 清空(commitCell 的
|
|
2859
|
+
// selection restore 對 Tab 換格不適用 — 下一格馬上進 edit)。
|
|
2860
|
+
if (editingDraft !== undefined) commitCell(rowId, colId, editingDraft)
|
|
2508
2861
|
setEditingCellId(cellEditId(allRows[nextRowIdx], allCols[nextColIdx]))
|
|
2862
|
+
setSelectedCellId(null)
|
|
2863
|
+
setRangeAnchor(null)
|
|
2864
|
+
setRangeFocus(null)
|
|
2509
2865
|
return
|
|
2510
2866
|
}
|
|
2511
2867
|
}
|
|
2512
2868
|
return (
|
|
2513
|
-
|
|
2869
|
+
// 2026-07-05 D4 fix:key={cellId} 強制 per-cell remount — 相鄰同型欄位 Tab 過去時
|
|
2870
|
+
// uncontrolled Input / NumberCell localValue 原封不動(上一格的字跑到下一格)。
|
|
2871
|
+
// 對齊 cell-registry「mode-keyed remount canonical」(per-cell edit session 是不同 mount cycle)。
|
|
2872
|
+
<div key={cellId} onKeyDownCapture={handleEditTab} style={{ width: '100%', height: '100%' }}>
|
|
2514
2873
|
<Cell
|
|
2515
2874
|
value={value}
|
|
2516
2875
|
meta={meta}
|
|
@@ -2520,19 +2879,18 @@ function DataTableInner<TData>(
|
|
|
2520
2879
|
isEditable={cellEditable}
|
|
2521
2880
|
onCommit={(next) => commitCell(rowId, colId, next)}
|
|
2522
2881
|
onCommitLive={(next) => onCellCommit?.(rowId, colId, next)}
|
|
2523
|
-
onCancel={
|
|
2882
|
+
onCancel={() => cancelCellEdit(rowId, colId)} // 2026-07-05 D4:cancel 還原 selection(Contract 11)
|
|
2524
2883
|
onDraft={setEditingDraft} // Phase 7:每 keystroke 寫 draft → preserve across virtualizer unmount
|
|
2525
2884
|
/>
|
|
2526
2885
|
</div>
|
|
2527
2886
|
)
|
|
2528
2887
|
} : undefined}
|
|
2529
|
-
// Slice D Step 4 spreadsheet semantics(2026-05-10):
|
|
2530
|
-
// selectedCellId(click 1)= solid border
|
|
2531
|
-
//
|
|
2532
|
-
// CSS `[data-range-cell]`(per Issue 1 codex verdict;layer 不畫
|
|
2533
|
-
// RangeOuterRing
|
|
2888
|
+
// Slice D Step 4 spreadsheet semantics(2026-05-10;2026-07-14 對齊清理):
|
|
2889
|
+
// selectedCellId(click 1)= solid border SelectionRing z 2
|
|
2890
|
+
// range(Shift+click rectangle from anchor↔focus)= cell-bg fill via
|
|
2891
|
+
// CSS `[data-range-cell]`(per Issue 1 codex verdict;layer 不畫 range 視覺,
|
|
2892
|
+
// RangeOuterRing / rangeCellIds prop 已 retire)
|
|
2534
2893
|
selectedCellId={spreadsheetMode ? selectedCellId : null}
|
|
2535
|
-
rangeCellIds={rangeCellIds}
|
|
2536
2894
|
cellClickEntersEdit={(cellId) => {
|
|
2537
2895
|
// 2026-05-10 codex review red light fix(per dual-track verify):
|
|
2538
2896
|
// 1. cellId parse 用 lastIndexOf(':')(row id 可含 colon)
|
|
@@ -2561,14 +2919,14 @@ function DataTableInner<TData>(
|
|
|
2561
2919
|
|
|
2562
2920
|
// ── L4 Row drag DnD wrapper ───────────────────────────────────────────────
|
|
2563
2921
|
// Sensors:Pointer(8px activation distance,避免 cell click 誤觸 drag)+ Keyboard(a11y)
|
|
2564
|
-
// SortableContext
|
|
2565
|
-
// 同 parent level
|
|
2922
|
+
// v15.0 Path B:無 SortableContext — 每 row 各自 useDraggable / useDroppable;
|
|
2923
|
+
// 同 parent level 限制由自訂 collisionDetection 過濾 cross-parent target 成立(cross-parent over → invalidDrop)。
|
|
2566
2924
|
// DragEnd:active.id / over.id → 算 position(active vs over 視覺位置),呼叫 onRowReorder。
|
|
2567
2925
|
// hooks 必呼叫(rules-of-hooks)— 即使 enableRowDrag=false 也走 useSensors;wrap 才條件化。
|
|
2568
2926
|
// **codex P1 fix(2026-05-07 v15.13)**:KeyboardSensor 不傳 `coordinateGetter`,用
|
|
2569
2927
|
// dnd-kit 預設 25px 箭頭 stepping。`sortableKeyboardCoordinates` 是 `@dnd-kit/sortable`
|
|
2570
2928
|
// preset,需 `<SortableContext>` 才正確 resolve 下一個 sortable target — 但 v15.0
|
|
2571
|
-
// path B 已 explicit 砍 SortableContext 改用 useDraggable+useDroppable(
|
|
2929
|
+
// path B 已 explicit 砍 SortableContext 改用 useDraggable+useDroppable(見檔頭 import 註解),
|
|
2572
2930
|
// 此 getter 在無 context 下 keyboard nav 無法 reliable resolve target → keyboard
|
|
2573
2931
|
// drag/reorder regression。Default getter(arrow-key Δ25px)在 useDraggable 場景是
|
|
2574
2932
|
// dnd-kit canonical(`@dnd-kit/core/src/sensors/keyboard/defaults.ts` 預設行為)。
|
|
@@ -2584,7 +2942,7 @@ function DataTableInner<TData>(
|
|
|
2584
2942
|
// pointerWithin 要求 pointer 真在 droppable rect 內才返回 → release 在 gap 自然 over=null →
|
|
2585
2943
|
// 不觸發 reorder → snap back 自然成立(對齊 Notion / TreeView 行為)。
|
|
2586
2944
|
// rectIntersection fallback 給 keyboard sensor(無 pointer)。
|
|
2587
|
-
// 詳
|
|
2945
|
+
// 詳 packages/design-system/ds-canonical/references/drag-canonical.md。
|
|
2588
2946
|
const sameParentCollisionDetection: CollisionDetection = React.useCallback((args) => {
|
|
2589
2947
|
const activeId = args.active?.id != null ? String(args.active.id) : null
|
|
2590
2948
|
if (!activeId) {
|
|
@@ -2731,7 +3089,7 @@ function DataTableInner<TData>(
|
|
|
2731
3089
|
const side: 'before' | 'after' = activeIdx < overIdx ? 'after' : 'before'
|
|
2732
3090
|
// **v15.3 noop suppress**:drop position 等同原位 → 不顯 indicator(對齊 handleDragEnd noop guard)
|
|
2733
3091
|
if (isReorderNoop(activeIdx, overIdx, side)) { setDropIndicator(null); return }
|
|
2734
|
-
|
|
3092
|
+
setDropIndicatorIfChanged({ id: String(over.id), side, type: 'column' })
|
|
2735
3093
|
} else {
|
|
2736
3094
|
// Row drag — 用 allRowIds 算位置(只 same-parent siblings,跨 parent collisionDetection 已過濾)
|
|
2737
3095
|
const activeIdx = allRowIds.indexOf(String(active.id))
|
|
@@ -2739,9 +3097,9 @@ function DataTableInner<TData>(
|
|
|
2739
3097
|
if (activeIdx === -1 || overIdx === -1) { setDropIndicator(null); return }
|
|
2740
3098
|
const side: 'before' | 'after' = activeIdx < overIdx ? 'after' : 'before'
|
|
2741
3099
|
if (isReorderNoop(activeIdx, overIdx, side)) { setDropIndicator(null); return }
|
|
2742
|
-
|
|
3100
|
+
setDropIndicatorIfChanged({ id: String(over.id), side, type: 'row' })
|
|
2743
3101
|
}
|
|
2744
|
-
}, [allRowIds, isReorderNoop])
|
|
3102
|
+
}, [allRowIds, isReorderNoop, setDropIndicatorIfChanged])
|
|
2745
3103
|
|
|
2746
3104
|
const handleDragCancel = React.useCallback(() => {
|
|
2747
3105
|
setActiveDragId(null)
|
|
@@ -2765,8 +3123,11 @@ function DataTableInner<TData>(
|
|
|
2765
3123
|
const meta = table.getColumn(id)?.columnDef.meta as { locked?: boolean } | undefined
|
|
2766
3124
|
return !meta?.locked
|
|
2767
3125
|
})
|
|
3126
|
+
// D3 dep-hygiene fix(2026-07-06):補 columnVisibility — memo 讀 table.getVisibleLeafColumns()
|
|
3127
|
+
// (live,受 visibility 影響)原 deps 漏列,隱藏欄位後清單 stale(隱藏欄仍在 reorderable
|
|
3128
|
+
// 列表 → handleDragOver 的 drop side 計算錯位)。
|
|
2768
3129
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2769
|
-
}, [table, columnsWithSelection, tableOptions?.state?.columnOrder])
|
|
3130
|
+
}, [table, columnsWithSelection, tableOptions?.state?.columnOrder, columnVisibility])
|
|
2770
3131
|
// Sync ref(handleDragOver closure 抓不到最新 reorderableColumnIds)
|
|
2771
3132
|
React.useEffect(() => { reorderableColumnIdsRef.current = reorderableColumnIds }, [reorderableColumnIds])
|
|
2772
3133
|
|
|
@@ -2840,6 +3201,43 @@ function DataTableInner<TData>(
|
|
|
2840
3201
|
return sameParentCollisionDetection(args)
|
|
2841
3202
|
}, [sameParentCollisionDetection])
|
|
2842
3203
|
|
|
3204
|
+
// ── L5 分頁列(2026-07-06,詳 data-table.spec.md「L5:分頁」段)────────────────
|
|
3205
|
+
// 間距 tight = layoutSpace spec 規則 3「跨範疇 functional 交互」;頁碼靠右(shadcn justify-end /
|
|
3206
|
+
// Ant Table bottomEnd / MUI / Carbon 4 家實證,左側空也靠右);「共 N 筆」數源 = filter 後全集
|
|
3207
|
+
// getPrePaginationRowModel(≠ selection all-mode 的 server-side 全集數 M — consumer 自持,語意不同)。
|
|
3208
|
+
// 2026-07-06 user 拍板:「Pagination 元件本身提供完整功能(showTotal / 每頁筆數)= SSOT,
|
|
3209
|
+
// Table 按一致定義套用」—— 分頁列的資訊/選單/「資訊左、操作右」layout 全部 own 在
|
|
3210
|
+
// <Pagination> 完整形態;DataTable 只轉發 config + own TanStack state(controlled 消費:
|
|
3211
|
+
// page/pageSize 狀態在本層、定義在 Pagination)。
|
|
3212
|
+
const totalRowCount = paginationEnabled ? table.getPrePaginationRowModel().rows.length : 0
|
|
3213
|
+
const paginationBar = paginationEnabled && !isEmpty ? (
|
|
3214
|
+
// 無條件 justify-end(2026-07-07 C16:原 paginationHasExtras 判斷式 = 平行重複 Pagination
|
|
3215
|
+
// 內部 hasExtras 拼寫,未來加 extra 必 drift)——完整形態 Pagination 自帶 w-full
|
|
3216
|
+
// justify-between,justify-end 對其為 no-op;純頁碼形態靠右 = 拍板 #6(shadcn justify-end /
|
|
3217
|
+
// Ant Table bottomEnd / MUI / Carbon 4 家)。ref 供 isFillHeight bodyMaxHeight 扣 bar 高(C12)。
|
|
3218
|
+
<div ref={paginationBarRef} className="flex justify-end">
|
|
3219
|
+
<Pagination
|
|
3220
|
+
total={totalRowCount}
|
|
3221
|
+
page={currentPage}
|
|
3222
|
+
onPageChange={setCurrentPage}
|
|
3223
|
+
pageSize={pageSizeState}
|
|
3224
|
+
onPageSizeChange={(next) => {
|
|
3225
|
+
setPageSizeState(next)
|
|
3226
|
+
paginationOpts?.onPageSizeChange?.(next)
|
|
3227
|
+
}}
|
|
3228
|
+
showTotal={paginationOpts?.showTotal}
|
|
3229
|
+
pageSizeOptions={paginationOpts?.pageSizeOptions}
|
|
3230
|
+
/>
|
|
3231
|
+
</div>
|
|
3232
|
+
) : null
|
|
3233
|
+
// isFillHeight 並用:外層接管高度(h-full min-h-0),tableContent 的 maxHeight cap 在內層照常生效
|
|
3234
|
+
const composedContent = paginationBar ? (
|
|
3235
|
+
<div className={cn('flex flex-col gap-[var(--layout-space-tight)]', isFillHeight && 'h-full min-h-0')}>
|
|
3236
|
+
{tableContent}
|
|
3237
|
+
{paginationBar}
|
|
3238
|
+
</div>
|
|
3239
|
+
) : tableContent
|
|
3240
|
+
|
|
2843
3241
|
const wrapWithDnd = (node: React.ReactNode): React.ReactNode => {
|
|
2844
3242
|
if (!enableRowDrag && !enableColumnReorder) return node
|
|
2845
3243
|
return (
|
|
@@ -2886,14 +3284,14 @@ function DataTableInner<TData>(
|
|
|
2886
3284
|
if (enabled && mode === 'single') {
|
|
2887
3285
|
return (
|
|
2888
3286
|
<RadioGroupPrimitive.Root
|
|
2889
|
-
value={selection[0] ?? ''}
|
|
2890
|
-
onValueChange={(v) => v && setSelection([v])}
|
|
3287
|
+
value={selection.mode === 'include' ? (selection.ids[0] ?? '') : ''}
|
|
3288
|
+
onValueChange={(v) => v && setSelection({ mode: 'include', ids: [v] })}
|
|
2891
3289
|
>
|
|
2892
|
-
{wrapWithDnd(
|
|
3290
|
+
{wrapWithDnd(composedContent)}
|
|
2893
3291
|
</RadioGroupPrimitive.Root>
|
|
2894
3292
|
)
|
|
2895
3293
|
}
|
|
2896
|
-
return wrapWithDnd(
|
|
3294
|
+
return wrapWithDnd(composedContent)
|
|
2897
3295
|
}
|
|
2898
3296
|
|
|
2899
3297
|
export const DataTable = React.forwardRef(DataTableInner) as <TData>(
|
|
@@ -2913,7 +3311,9 @@ export const dataTableMeta = {
|
|
|
2913
3311
|
sizes: {
|
|
2914
3312
|
|
|
2915
3313
|
},
|
|
2916
|
-
|
|
3314
|
+
// 'active' 移除 — 全檔無 Tailwind 按壓 utility(rg `active:` 僅命中 dnd-kit `e.active` 物件),
|
|
3315
|
+
// 無按壓專屬視覺態;row action / drag handle 的按壓屬內嵌 Button meta(2026-07-07 對抗稽核補修)。
|
|
3316
|
+
states: ['default', 'hover', 'focus-visible', 'disabled'],
|
|
2917
3317
|
tokens: {
|
|
2918
3318
|
bg: ['bg-muted', 'bg-neutral-hover', 'bg-surface'],
|
|
2919
3319
|
fg: ['text-fg-muted', 'text-fg-secondary', 'text-foreground'],
|