@qijenchen/design-system 0.1.0-beta.84 → 0.1.0-beta.86
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 +210 -0
- package/CLAUDE.md +17 -191
- package/cli-init.mjs +30 -2
- package/dist/components/Accordion/accordion.d.ts +2 -2
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Avatar/avatar.js +1 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button-group.d.ts +2 -2
- package/dist/components/Button/button-group.d.ts.map +1 -1
- package/dist/components/Button/button-group.js +2 -2
- package/dist/components/Button/button-group.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -1
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +1 -1
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +14 -8
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +64 -37
- package/dist/components/Carousel/carousel.js.map +1 -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 +2 -2
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +49 -10
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +15 -6
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +13 -7
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +11 -2
- package/dist/components/Command/command.js.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 +41 -38
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +1 -17
- 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.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.js +154 -0
- package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +5 -328
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -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 +187 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +2 -2
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +44 -32
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +3 -3
- package/dist/components/DatePicker/date-picker.js +4 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.d.ts +3 -3
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
- package/dist/components/DescriptionList/description-list.js +6 -6
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +2 -2
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +16 -10
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-types.d.ts +2 -2
- 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 +20 -4
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +30 -31
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +25 -3
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Field/index.d.ts.map +1 -1
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/Field/use-form-validation.d.ts +1 -1
- package/dist/components/Field/use-form-validation.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +2 -5
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +5 -1
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +2 -1
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +2 -2
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +4 -2
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +104 -62
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +6 -6
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +5 -5
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +3 -3
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +17 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +7 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +12 -1
- package/dist/components/NumberInput/number-input.js.map +1 -1
- 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/people-picker.d.ts +5 -5
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +7 -5
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +1 -1
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +3 -3
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +1 -1
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +4 -0
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts +16 -6
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +17 -5
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +17 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +17 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
- package/dist/components/SelectionControl/boolean-value.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +2 -2
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.js +2 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +6 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +6 -4
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +19 -5
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +4 -4
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -1
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +73 -23
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts +3 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +2 -2
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +4 -4
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +15 -15
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +4 -4
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -5
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +27 -23
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +16 -0
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -11
- 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 +21 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +3 -3
- package/dist/tokens/categorical-color.d.ts.map +1 -1
- package/dist/tokens/categorical-color.js +2 -2
- package/dist/tokens/categorical-color.js.map +1 -1
- package/ds-canonical/fork/AGENTS.md +213 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
- package/ds-canonical/fork/codex/hooks.json +16 -0
- package/ds-canonical/fork/governance.lock +22 -7
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/fork/manifest.json +10 -1
- package/ds-canonical/fork/preamble.md +3 -2
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
- package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
- package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
- package/ds-canonical/references/certified-surfaces.md +20 -0
- package/ds-canonical/references/preflight-gate-baseline.json +5 -0
- package/ds-canonical/references/principle-dim-map.json +20 -2
- package/ds-canonical/references/props-naming.md +2 -1
- package/ds-canonical/references/ssot-index.md +2 -2
- package/ds-canonical/references/story-baseline-registry.json +2 -2
- package/ds-canonical/rules/story-rules.md +1 -1
- package/ds-canonical/rules/ui-development.md +2 -1
- package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
- package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
- package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
- package/ds-story-manifest.json +21 -21
- package/llms-full.txt +3 -3
- package/llms.txt +1 -1
- package/package.json +2 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
- package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
- package/src/components/Accordion/accordion.spec.md +10 -1
- package/src/components/Accordion/accordion.stories.tsx +10 -5
- package/src/components/Accordion/accordion.tsx +7 -2
- package/src/components/Alert/alert.principles.stories.tsx +2 -8
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
- package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
- package/src/components/AppShell/app-shell.spec.md +4 -0
- package/src/components/AppShell/app-shell.stories.tsx +4 -5
- package/src/components/Avatar/avatar.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -2
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
- package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
- package/src/components/Button/button-group.tsx +4 -4
- package/src/components/Button/button.anatomy.stories.tsx +26 -7
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.stories.tsx +22 -28
- package/src/components/Button/button.tsx +2 -1
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +1 -1
- package/src/components/Carousel/carousel.spec.md +17 -1
- package/src/components/Carousel/carousel.tsx +93 -42
- package/src/components/Checkbox/checkbox-group.tsx +26 -15
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
- package/src/components/Checkbox/checkbox.spec.md +14 -3
- package/src/components/Checkbox/checkbox.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.tsx +79 -19
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
- package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
- package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
- package/src/components/Combobox/combobox.spec.md +6 -2
- package/src/components/Combobox/combobox.stories.tsx +9 -36
- package/src/components/Combobox/combobox.tsx +42 -27
- package/src/components/Command/command.spec.md +3 -3
- package/src/components/Command/command.tsx +9 -2
- package/src/components/DataTable/cell-registry.tsx +75 -76
- package/src/components/DataTable/column-types.ts +4 -17
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
- package/src/components/DataTable/data-table-filter-group.tsx +231 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +19 -436
- package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
- package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
- package/src/components/DataTable/data-table.css +2 -3
- package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
- package/src/components/DataTable/data-table.spec.md +8 -8
- package/src/components/DataTable/data-table.stories.tsx +39 -29
- package/src/components/DataTable/data-table.tsx +94 -68
- package/src/components/DataTable/filter-operators.spec.md +5 -3
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
- package/src/components/DatePicker/date-picker.spec.md +9 -9
- package/src/components/DatePicker/date-picker.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.tsx +13 -13
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +12 -12
- package/src/components/DescriptionList/description-list.stories.tsx +3 -3
- package/src/components/DescriptionList/description-list.tsx +10 -10
- package/src/components/Dialog/dialog.tsx +4 -1
- package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +44 -37
- package/src/components/Field/field-types.ts +14 -12
- package/src/components/Field/field-wrapper.tsx +59 -43
- package/src/components/Field/field.anatomy.stories.tsx +6 -6
- package/src/components/Field/field.principles.stories.tsx +5 -28
- package/src/components/Field/field.spec.md +4 -4
- package/src/components/Field/field.stories.tsx +103 -72
- package/src/components/Field/field.tsx +36 -4
- package/src/components/Field/form-validation.spec.md +2 -0
- package/src/components/Field/index.ts +1 -0
- package/src/components/Field/use-form-validation.ts +1 -1
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
- package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
- package/src/components/FileItem/file-item.tsx +10 -8
- package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
- package/src/components/FileUpload/file-upload.spec.md +3 -2
- package/src/components/FileUpload/file-upload.tsx +5 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.spec.md +1 -1
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.tsx +3 -2
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
- package/src/components/HoverCard/hover-card.spec.md +2 -2
- package/src/components/HoverCard/hover-card.tsx +4 -2
- package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
- package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
- package/src/components/InlineEdit/inline-edit.spec.md +71 -46
- package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
- package/src/components/InlineEdit/inline-edit.tsx +211 -125
- package/src/components/Input/input.anatomy.stories.tsx +15 -15
- package/src/components/Input/input.principles.stories.tsx +3 -3
- package/src/components/Input/input.spec.md +4 -4
- package/src/components/Input/input.stories.tsx +3 -3
- package/src/components/Input/input.tsx +13 -13
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.spec.md +6 -2
- package/src/components/LinkInput/link-input.stories.tsx +8 -8
- package/src/components/LinkInput/link-input.tsx +21 -19
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.tsx +8 -2
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
- package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.spec.md +6 -6
- package/src/components/NumberInput/number-input.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.tsx +17 -5
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
- package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
- package/src/components/PeoplePicker/people-picker.tsx +39 -20
- package/src/components/PeoplePicker/person-display.tsx +3 -3
- package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
- package/src/components/Popover/popover.principles.stories.tsx +49 -28
- package/src/components/Popover/popover.spec.md +4 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
- package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
- package/src/components/README.md +1 -0
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
- package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
- package/src/components/RadioGroup/radio-group.tsx +19 -14
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
- package/src/components/Rating/rating.principles.stories.tsx +3 -3
- package/src/components/Rating/rating.spec.md +2 -2
- package/src/components/Rating/rating.stories.tsx +4 -18
- package/src/components/Rating/rating.tsx +5 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +5 -2
- package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
- package/src/components/SegmentedControl/segmented-control.tsx +6 -3
- package/src/components/Select/select.anatomy.stories.tsx +13 -7
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +11 -1
- package/src/components/Select/select.stories.tsx +41 -27
- package/src/components/Select/select.tsx +44 -26
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
- package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
- package/src/components/SelectMenu/select-menu.tsx +38 -5
- package/src/components/SelectionControl/boolean-value.tsx +2 -2
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
- package/src/components/Separator/separator.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
- package/src/components/Sheet/sheet.tsx +4 -1
- package/src/components/Sidebar/sidebar.tsx +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
- package/src/components/Slider/slider.principles.stories.tsx +6 -6
- package/src/components/Slider/slider.spec.md +13 -1
- package/src/components/Slider/slider.stories.tsx +44 -32
- package/src/components/Slider/slider.tsx +13 -4
- package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +4 -2
- package/src/components/Steps/steps.stories.tsx +4 -56
- package/src/components/Steps/steps.tsx +31 -7
- package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +4 -4
- package/src/components/Switch/switch.stories.tsx +3 -3
- package/src/components/Switch/switch.tsx +16 -10
- package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
- package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
- package/src/components/Tabs/tabs.spec.md +5 -2
- package/src/components/Tabs/tabs.stories.tsx +36 -44
- package/src/components/Tabs/tabs.tsx +101 -36
- package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
- package/src/components/Tag/tag.principles.stories.tsx +4 -4
- package/src/components/Tag/tag.spec.md +3 -1
- package/src/components/Tag/tag.tsx +5 -3
- package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
- package/src/components/Textarea/textarea.spec.md +5 -5
- package/src/components/Textarea/textarea.tsx +24 -24
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
- package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
- package/src/components/TimePicker/time-picker.spec.md +6 -5
- package/src/components/TimePicker/time-picker.stories.tsx +3 -3
- package/src/components/TimePicker/time-picker.tsx +24 -14
- package/src/components/Toast/toast.principles.stories.tsx +1 -1
- package/src/components/Toast/toast.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
- package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.spec.md +9 -3
- package/src/components/Tooltip/tooltip.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.tsx +12 -2
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
- package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
- package/src/components/TreeView/tree-view.spec.md +8 -6
- package/src/components/TreeView/tree-view.stories.tsx +9 -43
- package/src/components/TreeView/tree-view.tsx +36 -0
- package/src/index.ts +16 -9
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +19 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
- package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
- package/src/tokens/categorical-color.ts +5 -5
- package/src/tokens/color/color.spec.md +5 -5
- package/src/tokens/color/primitives.css +9 -2
- package/src/tokens/opacity/opacity.spec.md +1 -1
- package/src/tokens/orphan-tokens.spec.md +1 -1
- package/src/tokens/typography/typography.spec.md +2 -0
- package/src/tokens/uiSize/uiSize.css +6 -1
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
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(2026-07-14 自 data-table-filter-panel.tsx 拆檔搬移,原檔級 escape 隨段落帶入)。
|
|
2
|
+
// @internal — DS-internal 單元(FilterValuePicker value-picker switcher,只被
|
|
3
|
+
// data-table-filter-group.tsx FilterRow 消費);不隨 index.ts re-export 進 npm public surface。
|
|
4
|
+
// ────────────────────────────── 消費的 SSOT ──────────────────────────────
|
|
5
|
+
// - Field controls(Family 4,統一 size="sm"):Input / NumberInput / Select / Combobox /
|
|
6
|
+
// DatePicker + DatePickerRange(showTime)/ PeoplePicker — 按 ValueShape dispatch
|
|
7
|
+
// (ValueShape ↔ picker 對照 canonical:./data-table.spec.md「三、Operator × ValueShape SSOT」)
|
|
8
|
+
// - className 直接 forward 給 inner Field control(不另開 wrapper div)—
|
|
9
|
+
// field-control-group.spec.md「forward className」canonical(2026-05-04 #2 fix)
|
|
10
|
+
// - Operator / ValueShape SSOT:./filter-operators.ts(DATE_RELATIVE_OPTIONS / DATE_RELATIVE_GROUPS)
|
|
11
|
+
// - Person pool:PeoplePicker PersonValue(對齊 cell-registry meta.people SSOT)
|
|
12
|
+
// 設計規則:./filter-operators.spec.md「ValueShape canonical」+ ./data-table.spec.md「進階篩選」段
|
|
13
|
+
|
|
14
|
+
import { Select, type SelectOption } from '@/design-system/components/Select/select'
|
|
15
|
+
import { Combobox } from '@/design-system/components/Combobox/combobox'
|
|
16
|
+
import { Input } from '@/design-system/components/Input/input'
|
|
17
|
+
import { NumberInput } from '@/design-system/components/NumberInput/number-input'
|
|
18
|
+
import { DatePicker, DatePickerRange } from '@/design-system/components/DatePicker/date-picker'
|
|
19
|
+
import { PeoplePicker } from '@/design-system/components/PeoplePicker/people-picker'
|
|
20
|
+
import type { PersonValue } from '@/design-system/components/PeoplePicker/person-display'
|
|
21
|
+
import {
|
|
22
|
+
DATE_RELATIVE_OPTIONS,
|
|
23
|
+
DATE_RELATIVE_GROUPS,
|
|
24
|
+
type ValueShape,
|
|
25
|
+
} from './filter-operators'
|
|
26
|
+
|
|
27
|
+
// ── FilterValuePicker(value-picker switcher per ValueShape)────────────────
|
|
28
|
+
//
|
|
29
|
+
// 2026-05-03 M21 retract:本 helper 原獨立檔 filter-value-picker.tsx(187 行 / 1 consumer),
|
|
30
|
+
// claim「未來 inline filter UI 共用」= premature abstraction → inline 回 panel。
|
|
31
|
+
// 2026-07-14 拆檔 refactor:panel 822 行過 800 hard cap(file-size escalation)→ 重新抽出為
|
|
32
|
+
// @internal 私有模組(非 public API 抽象,與 M21 不衝突;consumer 仍只見 DataTableFilterPanel)。
|
|
33
|
+
|
|
34
|
+
export interface FilterValuePickerColInfo {
|
|
35
|
+
id: string
|
|
36
|
+
label: string
|
|
37
|
+
options?: Array<{ value: string; label: string }>
|
|
38
|
+
/** Person pool — person/multiPerson filter picker 用(2026-05-07 升級,SSOT 對齊 cell-registry) */
|
|
39
|
+
people?: Array<{ name: string; avatarUrl?: string; description?: string }>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface FilterValuePickerProps {
|
|
43
|
+
shape: ValueShape | null
|
|
44
|
+
value: unknown
|
|
45
|
+
onChange: (v: unknown) => void
|
|
46
|
+
colInfo?: FilterValuePickerColInfo
|
|
47
|
+
disabled?: boolean
|
|
48
|
+
/** 用 column.label 組「{label} 篩選值」(panel 每 row 不顯式 label,a11y 必填) */
|
|
49
|
+
ariaLabel?: string
|
|
50
|
+
/** Forward 給內部 Field control 的 className(2026-05-04 #2 fix)
|
|
51
|
+
* 避免外層包 wrapper div 破壞 FieldControlGroup CSS variants(rounded radii / margin overlap) */
|
|
52
|
+
className?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function FilterValuePicker({
|
|
56
|
+
shape,
|
|
57
|
+
value,
|
|
58
|
+
onChange,
|
|
59
|
+
colInfo,
|
|
60
|
+
disabled,
|
|
61
|
+
ariaLabel,
|
|
62
|
+
className,
|
|
63
|
+
}: FilterValuePickerProps) {
|
|
64
|
+
if (!shape || disabled) {
|
|
65
|
+
return <Input size="sm" value="" onChange={() => {}} placeholder="輸入值…" disabled aria-label={ariaLabel} className={className} />
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
switch (shape) {
|
|
69
|
+
case 'none':
|
|
70
|
+
return null
|
|
71
|
+
|
|
72
|
+
case 'text':
|
|
73
|
+
return (
|
|
74
|
+
<Input
|
|
75
|
+
size="sm"
|
|
76
|
+
value={String(value ?? '')}
|
|
77
|
+
onChange={(e) => onChange(e.target.value)}
|
|
78
|
+
placeholder="輸入值…"
|
|
79
|
+
aria-label={ariaLabel}
|
|
80
|
+
className={className}
|
|
81
|
+
/>
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
case 'number':
|
|
85
|
+
return (
|
|
86
|
+
<NumberInput
|
|
87
|
+
size="sm"
|
|
88
|
+
value={typeof value === 'number' ? value : null}
|
|
89
|
+
onChange={(v) => onChange(v ?? '')}
|
|
90
|
+
placeholder="輸入數字…"
|
|
91
|
+
aria-label={ariaLabel}
|
|
92
|
+
className={className}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
case 'date_single':
|
|
97
|
+
return (
|
|
98
|
+
<DatePicker
|
|
99
|
+
size="sm"
|
|
100
|
+
value={typeof value === 'string' ? value : null}
|
|
101
|
+
onChange={(v) => onChange(v ?? '')}
|
|
102
|
+
aria-label={ariaLabel}
|
|
103
|
+
className={className}
|
|
104
|
+
/>
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
case 'date_range':
|
|
108
|
+
return (
|
|
109
|
+
<DatePickerRange
|
|
110
|
+
size="sm"
|
|
111
|
+
value={Array.isArray(value) && value.length === 2
|
|
112
|
+
? (value as [string | null, string | null])
|
|
113
|
+
: null}
|
|
114
|
+
onChange={(v) => onChange(v)}
|
|
115
|
+
aria-label={ariaLabel}
|
|
116
|
+
className={className}
|
|
117
|
+
/>
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
case 'date_relative': {
|
|
121
|
+
// 群組分類:Past / Current / Future(對齊 Linear / Notion idiom),走 Select.groups → SelectMenu
|
|
122
|
+
const opts: SelectOption[] = DATE_RELATIVE_OPTIONS.map((o) => ({
|
|
123
|
+
value: o.value,
|
|
124
|
+
label: o.label,
|
|
125
|
+
group: o.group,
|
|
126
|
+
}))
|
|
127
|
+
return (
|
|
128
|
+
<Select
|
|
129
|
+
size="sm"
|
|
130
|
+
options={opts}
|
|
131
|
+
groups={DATE_RELATIVE_GROUPS as unknown as Array<{ key: string; label: string }>}
|
|
132
|
+
value={String(value ?? '')}
|
|
133
|
+
onChange={(v) => onChange(v)}
|
|
134
|
+
placeholder="選擇相對日期"
|
|
135
|
+
aria-label={ariaLabel}
|
|
136
|
+
className={className}
|
|
137
|
+
/>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case 'select_single': {
|
|
142
|
+
const opts: SelectOption[] = (colInfo?.options ?? []).map((o) => ({
|
|
143
|
+
value: o.value,
|
|
144
|
+
label: o.label,
|
|
145
|
+
}))
|
|
146
|
+
return (
|
|
147
|
+
<Select
|
|
148
|
+
size="sm"
|
|
149
|
+
options={opts}
|
|
150
|
+
value={String(value ?? '')}
|
|
151
|
+
onChange={(v) => onChange(v)}
|
|
152
|
+
placeholder="選擇值"
|
|
153
|
+
aria-label={ariaLabel}
|
|
154
|
+
className={className}
|
|
155
|
+
/>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
case 'select_multi': {
|
|
160
|
+
const opts = (colInfo?.options ?? []).map((o) => ({
|
|
161
|
+
value: o.value,
|
|
162
|
+
label: o.label,
|
|
163
|
+
}))
|
|
164
|
+
const arr = Array.isArray(value) ? (value as string[]) : []
|
|
165
|
+
return (
|
|
166
|
+
<Combobox
|
|
167
|
+
size="sm"
|
|
168
|
+
options={opts}
|
|
169
|
+
value={arr}
|
|
170
|
+
onChange={(v) => onChange(v)}
|
|
171
|
+
placeholder="選擇值…"
|
|
172
|
+
aria-label={ariaLabel}
|
|
173
|
+
className={className}
|
|
174
|
+
/>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
case 'datetime_single':
|
|
179
|
+
return (
|
|
180
|
+
<DatePicker
|
|
181
|
+
size="sm"
|
|
182
|
+
showTime
|
|
183
|
+
value={typeof value === 'string' ? value : null}
|
|
184
|
+
onChange={(v) => onChange(v ?? '')}
|
|
185
|
+
aria-label={ariaLabel}
|
|
186
|
+
className={className}
|
|
187
|
+
/>
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
case 'datetime_range':
|
|
191
|
+
return (
|
|
192
|
+
<DatePickerRange
|
|
193
|
+
size="sm"
|
|
194
|
+
showTime
|
|
195
|
+
value={Array.isArray(value) && value.length === 2
|
|
196
|
+
? (value as [string | null, string | null])
|
|
197
|
+
: null}
|
|
198
|
+
onChange={(v) => onChange(v)}
|
|
199
|
+
aria-label={ariaLabel}
|
|
200
|
+
className={className}
|
|
201
|
+
/>
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
// person_single / person_multi — 走 PeoplePicker(2026-05-07 升級,對齊 cell-registry SSOT)。
|
|
205
|
+
// colInfo.people 來自 column meta.people。Filter value:
|
|
206
|
+
// - person_single:存 PersonValue | null(picker emit array,我們取 [0])
|
|
207
|
+
// - person_multi:存 PersonValue[]
|
|
208
|
+
case 'person_single': {
|
|
209
|
+
const v = value as PersonValue | null | undefined
|
|
210
|
+
return (
|
|
211
|
+
<PeoplePicker
|
|
212
|
+
size="sm"
|
|
213
|
+
value={v ?? null}
|
|
214
|
+
people={colInfo?.people ?? []}
|
|
215
|
+
onChange={(next) => onChange(next[0] ?? null)}
|
|
216
|
+
aria-label={ariaLabel}
|
|
217
|
+
className={className}
|
|
218
|
+
/>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
case 'person_multi': {
|
|
222
|
+
const v = Array.isArray(value) ? (value as PersonValue[]) : []
|
|
223
|
+
return (
|
|
224
|
+
<PeoplePicker
|
|
225
|
+
size="sm"
|
|
226
|
+
value={v}
|
|
227
|
+
people={colInfo?.people ?? []}
|
|
228
|
+
onChange={(next) => onChange(next)}
|
|
229
|
+
aria-label={ariaLabel}
|
|
230
|
+
className={className}
|
|
231
|
+
/>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
default:
|
|
235
|
+
return null
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -63,8 +63,8 @@ interface DataTableInteractionLayerProps {
|
|
|
63
63
|
* truthy → layer call this 拿 React node(已 bind value/onCommit/onCancel from controller),
|
|
64
64
|
* 在 ActiveEditorHost portal(z 3,float rect)render 之。
|
|
65
65
|
*
|
|
66
|
-
* Per codex Q6.2 outline:cell 永遠 mode="
|
|
67
|
-
* mode="edit" 同 registry component;float pass-through + z-index 3 cover
|
|
66
|
+
* Per codex Q6.2 outline:cell 永遠 mode="view"(SSOT preserved);portal host 渲
|
|
67
|
+
* mode="edit" 同 registry component;float pass-through + z-index 3 cover view below。
|
|
68
68
|
*/
|
|
69
69
|
activeEditorRender?: (cellId: CellId, rect: CellRect) => React.ReactNode
|
|
70
70
|
}
|
|
@@ -441,7 +441,7 @@ function ClipMask({ clipRect, children }: { clipRect: CellRect; children: React.
|
|
|
441
441
|
*
|
|
442
442
|
* Per codex Q2 verdict:不該進 CellRingOverlay primitive — 它是 host 不是 ring。
|
|
443
443
|
* - pointerEvents:auto(child Field 接收 click / keyboard)
|
|
444
|
-
* - background:var(--canvas)(opaque cover
|
|
444
|
+
* - background:var(--canvas)(opaque cover view Field below;Cell SSOT 保留)
|
|
445
445
|
* - z-index 3(above hover / selected / range)
|
|
446
446
|
* - children = activeEditorRender 的回傳 React node
|
|
447
447
|
*
|
|
@@ -197,11 +197,11 @@ function SortRow({
|
|
|
197
197
|
{...listeners}
|
|
198
198
|
/>
|
|
199
199
|
<div className="flex-1 min-w-0">
|
|
200
|
-
<Select size="sm" options={optionsForRow} value={sort.id} onChange={onChangeId} />
|
|
200
|
+
<Select size="sm" aria-label="排序欄位" options={optionsForRow} value={sort.id} onChange={onChangeId} />
|
|
201
201
|
</div>
|
|
202
202
|
<div className="w-32 shrink-0">
|
|
203
203
|
{/* minRows={2} — 升冪/降冪只 2 選項,顯式縮 menu 高度(Q5) */}
|
|
204
|
-
<Select size="sm" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
|
|
204
|
+
<Select size="sm" aria-label="排序方向" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
|
|
205
205
|
</div>
|
|
206
206
|
{/* Trash 用 text Button(Q4 對齊 filter panel)— form-control row 必 Field 同高 */}
|
|
207
207
|
<Button variant="text" size="sm" iconOnly startIcon={Trash2} aria-label="刪除" onClick={onRemove} />
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @anatomy-rationale:
|
|
2
|
-
// SizeMatrix
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
2
|
+
// SizeMatrix 以 RowHeightMatrix 呈現 —— DataTable 的 size(sm / md / lg)主要
|
|
3
|
+
// 體現在 row height 這個結構決策上(spec.md「Size 不等於 density」:size 是
|
|
4
|
+
// 這張表格「需要多緊湊」的結構決策,density 是全域使用者偏好,兩者不同軸,
|
|
5
|
+
// 不套用 compact / cozy / comfortable 等外部密度命名)。lg 同時連動字級放大
|
|
6
|
+
// (sm/md → text-body / lg → text-body-lg,對齊 Field,SSOT fieldDisplayTextClass)。
|
|
7
|
+
// @benchmark-unverified: Linear / Notion / Airtable 的 row-density 控件僅為外部近似參照,非 DS 命名依據。
|
|
7
8
|
// StateBehavior covered by ColorMatrix「Row 狀態色彩」段(default / hover /
|
|
8
9
|
// selected / disabled)+ Features「排序」段。Row 互動是 row-level
|
|
9
10
|
// 而非元件 level,集中於 Row 色彩展示更直觀。
|
|
@@ -71,7 +72,7 @@ export const Overview: Story = {
|
|
|
71
72
|
<div className="flex flex-col gap-10">
|
|
72
73
|
<div>
|
|
73
74
|
<H3>Anatomy</H3>
|
|
74
|
-
<Desc>DataTable 基於 TanStack Table,透過 `meta.type` column type 系統自動套用對應 Field Control 的
|
|
75
|
+
<Desc>DataTable 基於 TanStack Table,透過 `meta.type` column type 系統自動套用對應 Field Control 的 view 態渲染 cell。底層用 `<div>` + ARIA role(不用語義 `<table>`)——虛擬捲動需要絕對定位 row,frozen column 需要獨立 scroll 區域,table 的佈局模型兩者都不支援。</Desc>
|
|
75
76
|
<DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
|
|
76
77
|
</div>
|
|
77
78
|
|
|
@@ -83,7 +84,7 @@ export const Overview: Story = {
|
|
|
83
84
|
<tbody>
|
|
84
85
|
<tr><Td>L1 Structure</Td><Td>DOM 結構 + 捲動行為</Td><Td mono><div> + ARIA role="table/row/cell" + useVirtualizer</Td></tr>
|
|
85
86
|
<tr><Td>L2 Typography / Spacing</Td><Td>Row 高度 / Cell padding / 對齊</Td><Td mono>--table-row-* + --field-height-* token</Td></tr>
|
|
86
|
-
<tr><Td>L3 Cell Rendering</Td><Td>根據 meta.type
|
|
87
|
+
<tr><Td>L3 Cell Rendering</Td><Td>根據 meta.type 自動選對應 Cell 元件</Td><Td mono>cell-registry.tsx cellRegistry 註冊 11 型:string/number/currency/date/time/select/multiSelect/person/multiPerson/boolean/url(column-types.ts 管 type union + 對齊預設)</Td></tr>
|
|
87
88
|
<tr><Td>L4 Interactions</Td><Td>排序 / 選取 / 欄位拖動 / frozen column</Td><Td>TanStack Table features + 自訂 state</Td></tr>
|
|
88
89
|
</tbody>
|
|
89
90
|
</table>
|
|
@@ -132,7 +133,7 @@ export const Inspector: Story = {
|
|
|
132
133
|
bordered: { control: 'boolean', description: '外框(嵌入已帶框容器時可設 false 避免雙重邊框)' },
|
|
133
134
|
pinnedLeft: { control: 'boolean', description: 'Pin 產品名稱欄到左側,橫向捲動時保持可見' },
|
|
134
135
|
pinnedRight: { control: 'boolean', description: 'Pin 上架日期欄到右側' },
|
|
135
|
-
inlineEdit: { control: 'boolean', description: 'inline edit 視覺:cell 間加垂直分隔線(dtCellGrid)。
|
|
136
|
+
inlineEdit: { control: 'boolean', description: 'inline edit 視覺:cell 間加垂直分隔線(dtCellGrid)。view 態零恆顯 chevron(2026-07-08 A 案,editable affordance = hover outline);edit 態才有控件 chrome' },
|
|
136
137
|
height: {
|
|
137
138
|
control: 'select',
|
|
138
139
|
options: ['auto', '300px'],
|
|
@@ -182,7 +183,7 @@ export const ColumnTypes: Story = {
|
|
|
182
183
|
<div className="flex flex-col gap-8">
|
|
183
184
|
<div>
|
|
184
185
|
<H3>meta.type 系統</H3>
|
|
185
|
-
<Desc>每個 column 透過 `meta.type` 宣告資料類型,DataTable 自動選擇對應 Field Control 的 `mode="
|
|
186
|
+
<Desc>每個 column 透過 `meta.type` 宣告資料類型,DataTable 自動選擇對應 Field Control 的 `mode="view"` 渲染——消費者不需要手寫 cell。</Desc>
|
|
186
187
|
<DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
|
|
187
188
|
</div>
|
|
188
189
|
|
|
@@ -190,21 +191,21 @@ export const ColumnTypes: Story = {
|
|
|
190
191
|
<H3>支援的 Column Types</H3>
|
|
191
192
|
<div className="overflow-x-auto">
|
|
192
193
|
<table className="text-caption border-collapse">
|
|
193
|
-
<thead><tr><Th>meta.type</Th><Th>
|
|
194
|
+
<thead><tr><Th>meta.type</Th><Th>view 渲染</Th><Th>對齊</Th><Th>典型場景</Th></tr></thead>
|
|
194
195
|
<tbody>
|
|
195
|
-
<tr><Td mono>string</Td><Td mono>{`<Input mode="
|
|
196
|
-
<tr><Td mono>number</Td><Td mono>{`<NumberInput mode="
|
|
197
|
-
<tr><Td mono>currency</Td><Td mono>{`<NumberInput mode="
|
|
198
|
-
<tr><Td mono>date</Td><Td mono>{`<DatePicker mode="
|
|
199
|
-
<tr><Td mono>boolean</Td><Td mono>{`<Checkbox mode="
|
|
200
|
-
<tr><Td mono>select</Td><Td mono>{`<Select mode="
|
|
201
|
-
<tr><Td mono>multiSelect</Td><Td mono>{`<Combobox mode="
|
|
196
|
+
<tr><Td mono>string</Td><Td mono>{`<Input mode="view">`}</Td><Td>left</Td><Td>姓名、title、slug</Td></tr>
|
|
197
|
+
<tr><Td mono>number</Td><Td mono>{`<NumberInput mode="view">`}</Td><Td>right</Td><Td>數量、年齡</Td></tr>
|
|
198
|
+
<tr><Td mono>currency</Td><Td mono>{`<NumberInput mode="view">`}(+ prefix)</Td><Td>right</Td><Td>金額、價格</Td></tr>
|
|
199
|
+
<tr><Td mono>date</Td><Td mono>{`<DatePicker mode="view">`}</Td><Td>left</Td><Td>日期、時間戳</Td></tr>
|
|
200
|
+
<tr><Td mono>boolean</Td><Td mono>{`<Checkbox mode="view">`}(勾 / 叉 icon)</Td><Td>left</Td><Td>啟用 / 可見</Td></tr>
|
|
201
|
+
<tr><Td mono>select</Td><Td mono>{`<Select mode="view">`}</Td><Td>left</Td><Td>狀態、類別</Td></tr>
|
|
202
|
+
<tr><Td mono>multiSelect</Td><Td mono>{`<Combobox mode="view">`}</Td><Td>left</Td><Td>多選 tags</Td></tr>
|
|
202
203
|
<tr><Td mono>person</Td><Td mono>PersonDisplay / MultiPersonDisplay</Td><Td>left</Td><Td>指派者、reviewer</Td></tr>
|
|
203
|
-
<tr><Td mono>url</Td><Td mono>{`<LinkInput mode="
|
|
204
|
+
<tr><Td mono>url</Td><Td mono>{`<LinkInput mode="view">`}</Td><Td>left</Td><Td>URL</Td></tr>
|
|
204
205
|
</tbody>
|
|
205
206
|
</table>
|
|
206
207
|
</div>
|
|
207
|
-
<p className="text-footnote text-fg-muted mt-3">擴充新 type:在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(
|
|
208
|
+
<p className="text-footnote text-fg-muted mt-3">擴充新 type:在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(view/edit 渲染 SSOT);`column-types.ts` 只設 `align` / default metadata。兩處對齊後自動跟所有 DataTable 整合</p>
|
|
208
209
|
</div>
|
|
209
210
|
</div>
|
|
210
211
|
)
|
|
@@ -419,14 +420,14 @@ export const ColorMatrix: Story = {
|
|
|
419
420
|
選取狀態由 __select__ 欄的 checkbox / radio 呈現,不套 row 底色;hover 與 selection 正交
|
|
420
421
|
(已選 row 仍可有 hover 的 neutral-hover tint,但不疊額外 selected 底色)。
|
|
421
422
|
isRowSelectable=false 僅 disable checkbox,row 不灰底(spec 禁止事項);
|
|
422
|
-
|
|
423
|
+
(2026-07-16 cell disabled 態已廢除,cell 不再套 --bg-disabled;鎖定改用 editable=false 純 view 態)。
|
|
423
424
|
</p>
|
|
424
425
|
</div>
|
|
425
426
|
|
|
426
427
|
<div>
|
|
427
|
-
<H3>Cell 內
|
|
428
|
+
<H3>Cell 內 view element 色彩</H3>
|
|
428
429
|
<Desc>
|
|
429
|
-
Cell 內的資料元件(Tag / Person / Link / NumberDisplay)各自維持 Field Controls 的
|
|
430
|
+
Cell 內的資料元件(Tag / Person / Link / NumberDisplay)各自維持 Field Controls 的 view 色彩。
|
|
430
431
|
DataTable 不覆寫 cell 內的色彩 token,維持跨元件視覺統一。
|
|
431
432
|
</Desc>
|
|
432
433
|
<div className="overflow-x-auto">
|
|
@@ -434,7 +435,7 @@ export const ColorMatrix: Story = {
|
|
|
434
435
|
<thead>
|
|
435
436
|
<tr>
|
|
436
437
|
<Th>meta.type</Th>
|
|
437
|
-
<Th>
|
|
438
|
+
<Th>view 色彩</Th>
|
|
438
439
|
</tr>
|
|
439
440
|
</thead>
|
|
440
441
|
<tbody>
|
|
@@ -463,7 +464,7 @@ export const EmptyState: Story = {
|
|
|
463
464
|
return (
|
|
464
465
|
<div>
|
|
465
466
|
<H3>無資料時消費 Empty primitive</H3>
|
|
466
|
-
<Desc>DataTable 的 empty state 走共用 `Empty` 元件——保持跟其他空狀態(SelectMenu、Combobox、Page section)
|
|
467
|
+
<Desc>DataTable 的 empty state 走共用 `Empty` 元件——保持跟其他空狀態(SelectMenu、Combobox、Page section)視覺一致。未傳 `emptyState` 時顯示下方的標準 fallback;正式產品應傳 `emptyState` 以業務語言說明「缺什麼資料 + 下一步」,避免抽象的「沒有資料」(對齊 Empty 文案準則)。</Desc>
|
|
467
468
|
<DataTable columns={columns} data={[]} height="auto" />
|
|
468
469
|
</div>
|
|
469
470
|
)
|
|
@@ -133,9 +133,8 @@
|
|
|
133
133
|
(在 cell content 之下),non-overlay。Per codex Q1 verdict 對齊 row selected idiom
|
|
134
134
|
`--primary-subtle`(`data-table.spec.md`「L2 選取」段;原引 L170-174 之 selected-row bg 語意 2026-05-31 已廢除,改指現行段)。
|
|
135
135
|
Layer 不再畫 RangeFill div(避免 layer fixed positioned bg 蓋 cell content)。 */
|
|
136
|
-
/* 2026-
|
|
137
|
-
|
|
138
|
-
[data-range-cell]:not([data-cell-disabled="true"]) {
|
|
136
|
+
/* range fill bg(2026-07-16:cell disabled 態已廢除,原 `:not([data-cell-disabled])` exclusion 移除)。 */
|
|
137
|
+
[data-range-cell] {
|
|
139
138
|
background: var(--primary-subtle);
|
|
140
139
|
}
|
|
141
140
|
|
|
@@ -4,6 +4,7 @@ import LinkTo from '@storybook/addon-links/react'
|
|
|
4
4
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
5
5
|
import { createColumnHelper } from '@tanstack/react-table'
|
|
6
6
|
import { DataTable } from './data-table'
|
|
7
|
+
import { Empty } from '@/design-system/components/Empty/empty'
|
|
7
8
|
import './column-types'
|
|
8
9
|
|
|
9
10
|
const meta: Meta = {
|
|
@@ -71,7 +72,7 @@ export const UsageGuidance: Story = {
|
|
|
71
72
|
<p>適合 DataTable 的真實業務場景(點擊跳轉「展示」頁範例):</p>
|
|
72
73
|
<ul className="space-y-1">
|
|
73
74
|
<li>
|
|
74
|
-
<LinkTo kind="Design System/Components/DataTable
|
|
75
|
+
<LinkTo kind="Design System/Components/DataTable/設計規格" name="對齊規則(跨產業共識)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品庫存後台 — 單價 / 金額數字靠右對齊</span></LinkTo>
|
|
75
76
|
</li>
|
|
76
77
|
<li>
|
|
77
78
|
<LinkTo kind="Design System/Components/DataTable/展示" name="自動行高"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品備註長短不一 — 自動行高撐開列高</span></LinkTo>
|
|
@@ -132,22 +133,22 @@ export const ColumnTypeRule: Story = {
|
|
|
132
133
|
return (
|
|
133
134
|
<div>
|
|
134
135
|
<Rule
|
|
135
|
-
title="✅ 宣告 `meta.type`,DataTable 自動選對應
|
|
136
|
-
note="每個 Field Control 的 `mode='
|
|
136
|
+
title="✅ 宣告 `meta.type`,DataTable 自動選對應 view 渲染"
|
|
137
|
+
note="每個 Field Control 的 `mode='view'` 渲染(`<Input mode='view'>` / `<NumberInput mode='view'>` / `<Checkbox mode='view'>` 等)是該資料類型的唯一真實來源——format 邏輯、對齊、null 顯示都住一份。Consumer 只需宣告 type,不需重複造輪子"
|
|
137
138
|
>
|
|
138
139
|
<DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
|
|
139
140
|
</Rule>
|
|
140
141
|
|
|
141
142
|
<Rule
|
|
142
143
|
title="❌ 手寫 cell render 自訂格式化"
|
|
143
|
-
note="每 column 自己寫 `cell: (info) => ...` 會繞過 `mode='
|
|
144
|
+
note="每 column 自己寫 `cell: (info) => ...` 會繞過 `mode='view'` 系統——**格式化邏輯會漂移**。一個 table 的 price 顯示「$2,490」,另一個 table 的 price 顯示「2490」,一個 boolean 顯示勾 icon,另一個 boolean 顯示「是」——整個系統 format 失去一致性"
|
|
144
145
|
>
|
|
145
|
-
<Label warn>除非真的需要 `mode='
|
|
146
|
+
<Label warn>除非真的需要 `mode='view'` 無法提供的客製視覺,否則一律走 meta.type 系統。客製化時完全跳過 type 讓 view 渲染不要干預</Label>
|
|
146
147
|
</Rule>
|
|
147
148
|
|
|
148
149
|
<Rule
|
|
149
150
|
title="擴充新 type:到 cell-registry.tsx 註冊"
|
|
150
|
-
note="新增資料類型(如 `percentage`、`relative-time`)在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(
|
|
151
|
+
note="新增資料類型(如 `percentage`、`relative-time`)在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(view/edit 渲染 SSOT);`column-types.ts` 只設 align / default metadata。兩處對齊後自動跟所有 DataTable 整合,不在單一 table 硬寫"
|
|
151
152
|
>
|
|
152
153
|
<Label>讓 column type 系統成為 single source of truth,所有 table 受惠同一次更新</Label>
|
|
153
154
|
</Rule>
|
|
@@ -189,7 +190,7 @@ export const VirtualScrollRule: Story = {
|
|
|
189
190
|
|
|
190
191
|
<Rule
|
|
191
192
|
title="固定 height 數字 — 大量資料(> 100 筆),啟用 virtualization"
|
|
192
|
-
note="傳固定高度時 TanStack Virtual 自動啟用——只渲染可見 rows。500 筆資料只渲染 ~20 rows
|
|
193
|
+
note="傳固定高度時 TanStack Virtual 自動啟用——只渲染可見 rows。500 筆資料只渲染 ~20 rows,大幅降低列渲染成本。注意:排序 / 篩選 / 完整 row model 與記憶體成本仍隨資料量增長——超大量或遠端資料仍需分頁或 server-side 排序 / 篩選"
|
|
193
194
|
>
|
|
194
195
|
<DataTable columns={columns} data={bigData} height="400px" />
|
|
195
196
|
<Label>↑ 500 筆資料,固定 400px 高度 → virtualizer 只渲染畫面中的 ~20 rows</Label>
|
|
@@ -218,10 +219,15 @@ export const EmptyStateRule: Story = {
|
|
|
218
219
|
<div>
|
|
219
220
|
<Rule
|
|
220
221
|
title="✅ 無資料 → 消費 Empty primitive(跟系統統一)"
|
|
221
|
-
note="DataTable empty state 走共用 `Empty` 元件——保持跟 SelectMenu / Combobox / Page section
|
|
222
|
+
note="DataTable empty state 走共用 `Empty` 元件——保持跟 SelectMenu / Combobox / Page section 視覺一致。「不自訂」指不手刻自家 empty 視覺,不是省略文案:正式產品應傳 `emptyState` 以業務語言說明「缺什麼資料 + 下一步」(對齊 Empty 文案準則);未傳時才落回抽象 fallback「沒有資料」"
|
|
222
223
|
>
|
|
223
|
-
<DataTable
|
|
224
|
-
|
|
224
|
+
<DataTable
|
|
225
|
+
columns={columns}
|
|
226
|
+
data={[]}
|
|
227
|
+
height="auto"
|
|
228
|
+
emptyState={<Empty title="尚無商品" description="點擊上方「新增商品」開始建立第一筆" />}
|
|
229
|
+
/>
|
|
230
|
+
<Label>↑ 傳 `emptyState` 消費 Empty primitive,並以業務語言描述缺什麼資料</Label>
|
|
225
231
|
</Rule>
|
|
226
232
|
|
|
227
233
|
<Rule
|
|
@@ -248,7 +254,7 @@ export const NotSpreadsheetRule: Story = {
|
|
|
248
254
|
<div>
|
|
249
255
|
<Rule
|
|
250
256
|
title="DataTable 預設不做公式計算、不做跨 cell 選取"
|
|
251
|
-
note="DataTable 的心智模型是「結構化資料展示」——每筆資料是一 row,每個屬性是一 column。預設不做:Excel 的公式、跨 cell range selection(Ctrl+drag)、cell clipboard paste、pivot、跨欄運算。**逃生門**:確需 Excel-like 編輯可 opt-in `spreadsheetMode` prop(Shift+click range + 方向鍵 cell 導覽 + cell editing;仍不做公式計算)
|
|
257
|
+
note="DataTable 的心智模型是「結構化資料展示」——每筆資料是一 row,每個屬性是一 column。預設不做:Excel 的公式、跨 cell range selection(Ctrl+drag)、cell clipboard paste、pivot、跨欄運算。**逃生門**:確需 Excel-like 編輯可 opt-in `spreadsheetMode` prop(Shift+click range + 方向鍵 cell 導覽 + cell editing;仍不做公式計算)——即使開啟 spreadsheetMode,DataTable 仍只是「可 range 選取 + 方向鍵導覽 + inline 編輯」的結構化資料表,不會變成有公式引擎的試算表。"
|
|
252
258
|
>
|
|
253
259
|
<Label>需要試算表能力 → 用專門 library(AG Grid Enterprise / Handsontable / Luckysheet),不往 DataTable 塞</Label>
|
|
254
260
|
</Rule>
|
|
@@ -72,7 +72,7 @@ DataTable 有三種尺寸(`sm`、`md`、`lg`),透過 `size` prop 控制。
|
|
|
72
72
|
|
|
73
73
|
水平 padding 固定,不隨 size 或 density 變化(具體 token 見 `data-table.tsx`);垂直方向由行高模式決定(見第四節)。
|
|
74
74
|
|
|
75
|
-
**Cell / header 字級隨 size,對齊 Field family。** 三種 size 的 cell 與 header 預設字級**必與同 size 的 Field 一致**:`sm`/`md` → `text-body`(14px)、`lg` → `text-body-lg`(16px),SSOT = `fieldDisplayTextClass()`(`field-wrapper.tsx`)。`lg` 行高放大時字級同步放大,避免「字小、行高大」失衡。**機制**:typed cell 由各自 Field 控件吃 `size` 自動套用(cell-registry 各 cell
|
|
75
|
+
**Cell / header 字級隨 size,對齊 Field family。** 三種 size 的 cell 與 header 預設字級**必與同 size 的 Field 一致**:`sm`/`md` → `text-body`(14px)、`lg` → `text-body-lg`(16px),SSOT = `fieldDisplayTextClass()`(`field-wrapper.tsx`)。`lg` 行高放大時字級同步放大,避免「字小、行高大」失衡。**機制**:typed cell 由各自 Field 控件吃 `size` 自動套用(cell-registry 各 cell view mode 必傳 `size`,**禁漏傳**否則 fallback md 卡 14px);header 與非-Field 內容(consumer 自訂 cell)由 cell wrapper / header `cn(fieldDisplayTextClass(size))` 套用。`1lh`-based cell-py 公式(見第四節)隨字級自動吸收,row 高不變。
|
|
76
76
|
|
|
77
77
|
### 二、高度模式(有高度約束 vs 無高度約束,決定可用的功能組合)
|
|
78
78
|
|
|
@@ -120,7 +120,7 @@ Table 層級的模式切換,不是 column 層級。跟 AG Grid / Airtable 的
|
|
|
120
120
|
|
|
121
121
|
### 六之二、Column 寬度 API + 不變條件(2026-05-06 v14.3)
|
|
122
122
|
|
|
123
|
-
**命名**:`meta.width` / `meta.minWidth` / `meta.maxWidth`(px)。**不用 TanStack `size`** — DS 內 `size` 既定為 `'sm'|'md'|'lg'` density(49+ 處),避 namespace 衝突。內部 pre-process copy 到 TanStack root,resize feature 正常。No-resize default:`width` = reserve(cell ≥ width,flex 可 grow,不可 shrink)。`enableColumnResize=true`:`width` = 初始,`minWidth` = 拖拉下限(default 80)。**不變條件(invariants,L2 test + hook 守)**:(1) cell width = column width(跟 padding/state/mode 無關)(2)
|
|
123
|
+
**命名**:`meta.width` / `meta.minWidth` / `meta.maxWidth`(px)。**不用 TanStack `size`** — DS 內 `size` 既定為 `'sm'|'md'|'lg'` density(49+ 處),避 namespace 衝突。內部 pre-process copy 到 TanStack root,resize feature 正常。No-resize default:`width` = reserve(cell ≥ width,flex 可 grow,不可 shrink)。`enableColumnResize=true`:`width` = 初始,`minWidth` = 拖拉下限(default 80)。**不變條件(invariants,L2 test + hook 守)**:(1) cell width = column width(跟 padding/state/mode 無關)(2) view↔edit cell width 0 delta (3) view↔edit cell height 0 delta(textarea `field-sizing:content`)(4) Field 填滿 cell 高度(1px 容差於 cell.border-r)(5) No-resize column ≥ meta.width。對應 `scripts/data-table-invariants.mjs`(script 內 I1-I3 label 字串仍用 `display↔edit` — 2026-07-16 FieldMode display→view 更名前的歷史命名,語意同 view↔edit)。改 `columnSizeStyle` / 切 layout 必跑 invariant test 才 commit。
|
|
124
124
|
|
|
125
125
|
### 六之三、Runtime perf budget canonical(2026-05-14 codex+Layer A)
|
|
126
126
|
|
|
@@ -164,7 +164,7 @@ SSOT → `patterns/element-anatomy/inline-action.spec.md`「Real case 表」+ Pr
|
|
|
164
164
|
|------|-----------|
|
|
165
165
|
| Header cell internal(sort / ⌄ menu / filter funnel / pin)| `ItemInlineActionButton` `size="md"`(對齊 AG Grid / Material / Airtable / Notion / Polaris) | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
166
166
|
| **Multi-sort header(≥2 columns sorted)** | **隱藏 header arrow + 取消排序 dropdown option**(K7,2026-05-04)— 無 order 編號的單個 arrow 在 multi-sort 是 partial info → 反而混淆;user 走 SortManager panel 看完整 priority(SSOT)。0/1 sort 仍秀 arrow 完整資訊。理由:現行 DS 不顯 sort order 編號,跟 Airtable / Linear / Atlassian / Carbon 純箭頭派一致;multi-sort 時這派需 SortManager fallback(world-class 共識) |
|
|
167
|
-
| Body cell internal(
|
|
167
|
+
| Body cell internal(view endAction / clear / edit indicator)| Field family endAction(自動繼承)。**View 態零恆顯型別 icon(2026-07-08 A 案)**:editable affordance = hover outline(SSOT → field.spec.md L4/L6,`nakedCellEditableDisplayHover`);boolean = live Checkbox(AG Grid 同);url = hover Pencil(click-opens-link 與 edit 衝突的功能性入口,非型別 indicator)。**cell 空值 = 全空白**(2026-07-08 B 案,SSOT → field-controls.spec.md「null / undefined 值」surface 分流表) |
|
|
168
168
|
| Row dedicated action column | Button `xs iconOnly` 24px(見「九、Row Actions」) |
|
|
169
169
|
| Toolbar | Button(action-bar 共識) |
|
|
170
170
|
|
|
@@ -180,7 +180,7 @@ Cell 已 `flex items-center`,consumer render 直接 inline-flex + gap-2。Icon s
|
|
|
180
180
|
|
|
181
181
|
### 十一、Cell 單行截斷原則
|
|
182
182
|
|
|
183
|
-
固定行高下 cell 單行,空間不足:純文字 `text-overflow: ellipsis`;Tag 文字內部 truncate(Tag bg 跟縮);multiSelect 動態 `+N`;Person avatar 不縮 name truncate;Link truncate。每個
|
|
183
|
+
固定行高下 cell 單行,空間不足:純文字 `text-overflow: ellipsis`;Tag 文字內部 truncate(Tag bg 跟縮);multiSelect 動態 `+N`;Person avatar 不縮 name truncate;Link truncate。每個 view 態元件自管 truncation,Cell `overflow-hidden` 僅 safety net。截斷必顯 `...`(禁硬裁無 ellipsis)。截斷 hover 顯 tooltip。autoRowHeight wrap 模式不適用(可換行撐 row 高)。
|
|
184
184
|
|
|
185
185
|
### 十二、可推導值用 `calc()` 表達(不硬寫結果)— 上游動,下游自動跟著算
|
|
186
186
|
|
|
@@ -305,7 +305,7 @@ type FilterTreeNested = { mode: 'nested'; conjunction: 'and'|'or'; children: Fil
|
|
|
305
305
|
|
|
306
306
|
### 三、Operator × ValueShape SSOT
|
|
307
307
|
|
|
308
|
-
`filter-operators.ts` 的 `OPERATOR_REGISTRY: Record<ColumnType, OperatorSpec[]>` 是唯一 truth。Panel 完全 data-driven:field 選 → load op set → 選 op → 由 `valueShape` dispatch picker(`filter-value-picker.tsx
|
|
308
|
+
`filter-operators.ts` 的 `OPERATOR_REGISTRY: Record<ColumnType, OperatorSpec[]>` 是唯一 truth。Panel 完全 data-driven:field 選 → load op set → 選 op → 由 `valueShape` dispatch picker(`data-table-filter-value-picker.tsx`,@internal;2026-07-14 file-size 拆檔自 panel)。`is_set` / `is_not_set` / `is_true` / `is_false`(`ValueShape='none'`)不渲 picker。
|
|
309
309
|
|
|
310
310
|
ValueShape ↔ DS picker 對照(canonical 2026-05-02):
|
|
311
311
|
|
|
@@ -442,9 +442,9 @@ Row drag + column reorder + TreeView 共用 `lib/drag-visual.ts`:source `opacity
|
|
|
442
442
|
|
|
443
443
|
## Overlay + cell error SSOT(Phase 9)
|
|
444
444
|
|
|
445
|
-
**Overlay**:viewport `position:fixed inset:0` layer。`getCellRect()` 從 `getBoundingClientRect()` 取 float coords no rounding。Paint:hover/selected ring `outline outline-offset:-1px` in-place(range outer ring 已 2026-05-10 retire — range 視覺只剩 cell-bg `--primary-subtle` `[data-range-cell]`,bg 已足以標示範圍、外框冗餘);active editor host portal opaque `<div>` z 3(cell 保持
|
|
445
|
+
**Overlay**:viewport `position:fixed inset:0` layer。`getCellRect()` 從 `getBoundingClientRect()` 取 float coords no rounding。Paint:hover/selected ring `outline outline-offset:-1px` in-place(range outer ring 已 2026-05-10 retire — range 視覺只剩 cell-bg `--primary-subtle` `[data-range-cell]`,bg 已足以標示範圍、外框冗餘);active editor host portal opaque `<div>` z 3(cell 保持 view 態)。**Viewport clip**(Issue 6):body panel 加 `data-datatable-panel="left|center|right"`;`getCellGeometry()` return cell+panel rect;`<ClipMask>` panel rect `overflow:hidden`,內部 `toRelRect()` 轉 mask-relative(hover/selected ring 按 panel clip,不畫出 pin boundary)。Active editor host **不 clip**。對齊 AG Grid `cellsForRangeSet` / Glide / Notion sticky-cell mask。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
446
446
|
|
|
447
|
-
**Cell errors**(Issue 9):`cellErrors?: Record<string, string|string[]>` prop key `${rowId}:${colId}`。Cell
|
|
447
|
+
**Cell errors**(Issue 9):`cellErrors?: Record<string, string|string[]>` prop key `${rowId}:${colId}`。Cell view 態渲 error 14px `text-error` 下方 gap-1;array→`<ul><li>`;single→`<span>`。`aria-describedby` + `aria-invalid` + `<span role="alert">`。`overflow:visible` 當有 error(搭 `autoRowHeight`)。**Per-row state SSOT** cell-render wrapper(`items-X` 等)必 consume `effectiveAutoRowForCell`,禁 global `autoRowHeight`(audit `audit-data-table-row-mode-ssot.mjs` 強制)。**Edit-clears-own-cell** 自動清視覺,consumer onCellCommit validate 後回填。**a11y caveat**:≥ 5 同時 `role="alert"` 第一次 paint AT 噪音 → consumer 可考 `role="status"` fallback。對齊 AG Grid `cellClassRules='ag-cell-error'` + Material X errorMessage + Airtable validation。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
448
448
|
|
|
449
449
|
---
|
|
450
450
|
|
|
@@ -492,7 +492,7 @@ DataTable 是 composite multi-section 元件,**不套 SizeMatrix / StateBehavior
|
|
|
492
492
|
|
|
493
493
|
**Keyboard 行為**(目前實作 — `tableKeyboardHandler`):
|
|
494
494
|
- ↑↓←→:cell-to-cell navigation **僅 `spreadsheetMode` opt-in 時生效**;selection 尚未建立時按方向鍵自動選取第一個 visible cell(鍵盤可直接進入 spreadsheet 導覽,無需滑鼠 click — 對齊 Excel / Google Sheets / AG Grid「focus grid → first cell active」,2026-07-05 D4 補);預設模式方向鍵無作用
|
|
495
|
-
- Enter / F2:spreadsheet 模式下進 cell editing(cell 可編輯 + 非 boolean/url
|
|
495
|
+
- Enter / F2:spreadsheet 模式下進 cell editing(cell 可編輯 + 非 boolean/url 時);**Enter 確認後維持原格不下移**(2026-07-05 user 拍板;10 家實查:Excel 系 7 家下移、AG Grid 預設維持原格 — 採 AG Grid 派,數據 → `.claude/logs/deep-audit-2026-07-03/enter-commit-navigation-benchmark.json`;未來連續輸入需求可重議 opt-in);**edit 退出(commit / Esc)後 selection 還原至該 cell、焦點還給 table root**(editor unmount 後焦點掉到 body 才收回,不搶 user 點擊的新焦點 — 對齊 spreadsheet RFC Contract 11 + Excel / AG Grid,2026-07-05 D4 補)
|
|
496
496
|
- Cmd/Ctrl+A:`mode="multi"` selection 時選全可見列(扣 disabled)
|
|
497
497
|
- Esc:取消 editing(spreadsheet)/ 清 selection(selection mode);**IME 組字中的 Enter / Esc 不觸發 commit / cancel**(cell editor 帶 `isComposing` guard,2026-07-05 D4 補 — 中文選字 Enter 不誤提交半截組字)
|
|
498
498
|
- Tab:進入表格後操作排序與勾選;portal edit(`experimentalActiveEditorController`)中 Tab / Shift+Tab = commit 當前 draft + 移至下一個 editable cell 進 edit(2026-07-05 D4 補 commit — 原本換格丟 draft)
|