@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.87
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-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 +3 -4
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
- 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/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 -13
- 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 +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_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +19 -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 +12 -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-panel.tsx +6 -6
- 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 -7
- package/src/components/DataTable/data-table.stories.tsx +39 -29
- package/src/components/DataTable/data-table.tsx +90 -67
- package/src/components/DataTable/filter-operators.spec.md +2 -0
- 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 +10 -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/Empty/empty.spec.md +0 -1
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +46 -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 +5 -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 +4 -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 +10 -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 +4 -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 +13 -10
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +19 -0
- package/src/patterns/action-bar/action-bar.spec.md +1 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.spec.md +4 -0
- 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 +4 -4
- package/src/tokens/color/primitives.css +9 -2
- package/src/tokens/motion/motion.spec.md +6 -7
- 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 +5 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -65,7 +65,7 @@ declare module '@tanstack/react-table' {
|
|
|
65
65
|
wrap?: boolean
|
|
66
66
|
/**
|
|
67
67
|
* Max visible lines before ellipsis(2026-05-14 I9 per codex verdict + user 拍板)。
|
|
68
|
-
* Only effective when `autoRowHeight + wrap=true`。
|
|
68
|
+
* Only effective when `autoRowHeight + wrap=true`。view 用 `line-clamp-N`,edit textarea
|
|
69
69
|
* 高度 match clamp。對齊 Notion 「Truncate」row toggle / AG Grid `cellClassRules` 上限 row height。
|
|
70
70
|
* Default = undefined(無 clamp,完整 wrap)。
|
|
71
71
|
*/
|
|
@@ -162,22 +162,9 @@ declare module '@tanstack/react-table' {
|
|
|
162
162
|
* Esc cancel / blur or Enter commit。Commit 觸發 `onCellCommit`。
|
|
163
163
|
*/
|
|
164
164
|
editable?: boolean | ((row: TData) => boolean)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
* - `true`:cell 永遠 disabled
|
|
169
|
-
* - `false` / undef(default):cell normal
|
|
170
|
-
* - `(row) => boolean`:per-row 動態(e.g. row.archived 或 row.locked 才 disabled)
|
|
171
|
-
*
|
|
172
|
-
* 視覺(per `color.spec.md` `--bg-disabled` component-state token):
|
|
173
|
-
* - TD 外殼:`bg-disabled` + `cursor-not-allowed` + 抑制 hover ring
|
|
174
|
-
* - Cell content(Field family):`mode='disabled'` → 各 Field type 內部走具體 disabled token
|
|
175
|
-
* - edit entry 抑制:disabled cell 點擊不進 edit(對齊 `editable && !disabled` invariant)
|
|
176
|
-
*
|
|
177
|
-
* 跟 `editable=false` 區分:editable=false = readonly(可看不可編);disabled = 不可操作 state。
|
|
178
|
-
* 對齊 MUI X `isCellEditable` + cellClassName / AG Grid `cellClassRules` / Notion locked properties。
|
|
179
|
-
*/
|
|
180
|
-
disabled?: boolean | ((row: TData) => boolean)
|
|
165
|
+
// 2026-07-16 round16:cell `disabled` 已廢除。世界級 grid(MUI X isCellEditable / AG Grid editable /
|
|
166
|
+
// Handsontable readOnly)皆無 disabled cell 態 — 鎖定用 `editable:(row)=>false`(可看不可編、不灰化),
|
|
167
|
+
// 非 disabled 灰化態。原 `disabled?: boolean | ((row)=>boolean)` + bg-disabled TD 灰化全移除(全庫 0 消費)。
|
|
181
168
|
/**
|
|
182
169
|
* Locked column — column reorder 不可拖,Notion 「primary column」 pattern。
|
|
183
170
|
* 對齊 SKU / ID 等不可移欄位。
|
|
@@ -27,8 +27,7 @@ import { Eye, EyeOff, Lock, GripVertical, Search, RotateCcw, X as XIcon } from '
|
|
|
27
27
|
import { Button } from '@/design-system/components/Button/button'
|
|
28
28
|
import { ButtonDivider } from '@/design-system/components/Button/button-group'
|
|
29
29
|
import { Input } from '@/design-system/components/Input/input'
|
|
30
|
-
import {
|
|
31
|
-
import { PopoverHeader, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
|
|
30
|
+
import { PopoverHeader, PopoverBody, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
|
|
32
31
|
import { ItemPrefix, ItemLabel, ItemInlineActionButton, ROW_PADDING_BY_SIZE } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
33
32
|
import { cn } from '@/lib/utils'
|
|
34
33
|
import { DndContext, closestCenter, type DragEndEvent } from '@dnd-kit/core'
|
|
@@ -130,8 +129,19 @@ export function DataTableColumnVisibilityPanel({
|
|
|
130
129
|
onColumnOrderChange!(next)
|
|
131
130
|
}
|
|
132
131
|
|
|
132
|
+
// 2026-07-18 決策16 錯誤史(明記以免再犯):原本這個 panel 是 Fragment + fixed `ScrollArea max-h-72`,
|
|
133
|
+
// 與 sibling FilterPanel/SortManager(root-div + viewport-aware SurfaceBody)不一致。我給過**兩個都錯**
|
|
134
|
+
// 的辯護理由 —— (1)「PopoverHeader 用 -mx 負邊距、包 root 會破壞」= 錯(SurfaceHeader 用正 px-loose+border-b,
|
|
135
|
+
// 無 -mx);(2)「sibling 自刻 header 不用 primitive」= 錯(三 panel 皆消費 SurfaceHeader/PopoverHeader primitive)。
|
|
136
|
+
// 真正差異只是 body/scroll 策略。multi-agent SSOT consistency 稽核定案:**是 drift,該統一**(fixed 288px cap
|
|
137
|
+
// 在高螢幕多欄下劣於 sibling 的 viewport-adaptive;且是唯一不能當 template 複製的 panel)。故下方已改成 canonical shape。
|
|
133
138
|
return (
|
|
134
|
-
|
|
139
|
+
// 決策16 定案(2026-07-18,SSOT consistency 稽核後):對齊 sibling FilterPanel/SortManager 的
|
|
140
|
+
// overlay-surface canonical shape —— root `<div flex flex-col h-full min-h-0>`(M25 viewport-aware
|
|
141
|
+
// scroll chain)+ viewport-adaptive `PopoverBody`(取代原 fixed `ScrollArea max-h-72`)。三個
|
|
142
|
+
// DataTable state-panel 收斂成同一形狀,body 隨視窗高度自適應(高螢幕多欄不再硬卡 288px)。
|
|
143
|
+
// 寬度仍由 consumer 的 `<PopoverContent w-72>` 提供(panel root w-full 撐滿)。
|
|
144
|
+
<div className="flex flex-col h-full min-h-0 w-full">
|
|
135
145
|
<PopoverHeader hideClose>
|
|
136
146
|
<div className="flex items-center gap-1 w-full min-w-0">
|
|
137
147
|
<PopoverTitle className="flex-1">欄位顯示</PopoverTitle>
|
|
@@ -151,17 +161,20 @@ export function DataTableColumnVisibilityPanel({
|
|
|
151
161
|
</div>
|
|
152
162
|
</PopoverHeader>
|
|
153
163
|
{searchable && (
|
|
154
|
-
<div className="px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
|
|
164
|
+
<div className="shrink-0 px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
|
|
155
165
|
<Input
|
|
156
166
|
size="md"
|
|
157
167
|
placeholder="搜尋欄位…"
|
|
168
|
+
aria-label="搜尋欄位"
|
|
158
169
|
value={search}
|
|
159
170
|
onChange={(e) => setSearch(e.target.value)}
|
|
160
171
|
startIcon={Search}
|
|
161
172
|
/>
|
|
162
173
|
</div>
|
|
163
174
|
)}
|
|
164
|
-
|
|
175
|
+
{/* viewport-adaptive body(List-as-region idiom:PopoverBody !px-0 !py-0 撤 chrome padding,
|
|
176
|
+
內層 py-2 給垂直呼吸、row 自帶 px-loose 水平 padding)。取代原 fixed ScrollArea max-h-72。 */}
|
|
177
|
+
<PopoverBody className="!px-0 !py-0">
|
|
165
178
|
<div className="py-2 flex flex-col" style={{ '--item-prefix-slot': '16px' } as React.CSSProperties}>
|
|
166
179
|
{dndEnabled ? (
|
|
167
180
|
<DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
|
@@ -196,13 +209,13 @@ export function DataTableColumnVisibilityPanel({
|
|
|
196
209
|
))
|
|
197
210
|
)}
|
|
198
211
|
</div>
|
|
199
|
-
</
|
|
212
|
+
</PopoverBody>
|
|
200
213
|
<PopoverFooter className="justify-start">
|
|
201
214
|
<Button variant="tertiary" size="sm" onClick={handleBulkToggle}>
|
|
202
215
|
{allVisible ? '全部隱藏' : '顯示全部'}
|
|
203
216
|
</Button>
|
|
204
217
|
</PopoverFooter>
|
|
205
|
-
|
|
218
|
+
</div>
|
|
206
219
|
)
|
|
207
220
|
}
|
|
208
221
|
|
|
@@ -126,8 +126,9 @@ const newEmptyGroup = (): FilterGroup => ({
|
|
|
126
126
|
// ── Component Props ─────────────────────────────────────────────────────
|
|
127
127
|
|
|
128
128
|
export interface DataTableFilterPanelProps<TData> {
|
|
129
|
-
|
|
130
|
-
mode
|
|
129
|
+
// 2026-07-18 決策17:移除獨立 `mode` prop(單一真相源 = `value.mode` discriminant)——
|
|
130
|
+
// 舊設計 mode + value.mode 兩來源型別允許矛盾(mode='nested' 配 flat value → CTA 錯文案 + 死操作);
|
|
131
|
+
// 無外部消費者傳 mode(grep 0),全由 value.mode 推導。對齊 MUI X GridFilterModel / AG Grid 單一 model。
|
|
131
132
|
/** 可被 filter 的 columns */
|
|
132
133
|
columns: ColumnDef<TData, any>[]
|
|
133
134
|
/** 當前 FilterTree(controlled) */
|
|
@@ -151,7 +152,6 @@ export interface DataTableFilterPanelProps<TData> {
|
|
|
151
152
|
|
|
152
153
|
// 內部 fn — generic + ref 轉發。export 走 cast(對齊 DataTable 同 pattern)
|
|
153
154
|
function DataTableFilterPanelInner<TData>({
|
|
154
|
-
mode,
|
|
155
155
|
columns,
|
|
156
156
|
value,
|
|
157
157
|
onChange,
|
|
@@ -314,7 +314,7 @@ function DataTableFilterPanelInner<TData>({
|
|
|
314
314
|
// 必加 `min-h-0` 才能讓 panel 在 PopoverContent max-h cap 下正確 shrink + body scroll。
|
|
315
315
|
<div ref={ref} className={cn(
|
|
316
316
|
'flex flex-col h-full min-h-0',
|
|
317
|
-
mode === 'nested'
|
|
317
|
+
value.mode === 'nested'
|
|
318
318
|
? 'w-[min(760px,calc(100vw-2rem))]'
|
|
319
319
|
: 'w-[min(640px,calc(100vw-2rem))]',
|
|
320
320
|
className,
|
|
@@ -387,9 +387,9 @@ function DataTableFilterPanelInner<TData>({
|
|
|
387
387
|
<div>
|
|
388
388
|
<Button
|
|
389
389
|
variant="tertiary" size="sm" startIcon={Plus}
|
|
390
|
-
onClick={mode === 'flat' ? addFlatCondition : addGroup}
|
|
390
|
+
onClick={value.mode === 'flat' ? addFlatCondition : addGroup}
|
|
391
391
|
>
|
|
392
|
-
{mode === 'nested' ? '加入篩選器' : '加篩選'}
|
|
392
|
+
{value.mode === 'nested' ? '加入篩選器' : '加篩選'}
|
|
393
393
|
</Button>
|
|
394
394
|
</div>
|
|
395
395
|
</SurfaceBody>
|
|
@@ -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
|
|
|
@@ -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)
|
|
@@ -511,6 +511,7 @@ DataTable 是 composite multi-section 元件,**不套 SizeMatrix / StateBehavior
|
|
|
511
511
|
- `carousel.spec.md`
|
|
512
512
|
- `circular-progress.spec.md`
|
|
513
513
|
- `description-list.spec.md`
|
|
514
|
+
- `filter-operators.spec.md`
|
|
514
515
|
- `opacity.spec.md`
|
|
515
516
|
- `pagination.spec.md`
|
|
516
517
|
- `scroll-area.spec.md`
|