@qijenchen/design-system 0.1.0-beta.85 → 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-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 +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 +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 +7 -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 +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/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 +9 -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 +13 -10
- 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 +4 -4
- 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 +5 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -3,9 +3,9 @@ component: TreeView
|
|
|
3
3
|
family: 1
|
|
4
4
|
variants: {}
|
|
5
5
|
sizes:
|
|
6
|
-
sm: { when: "緊湊清單(與 md
|
|
6
|
+
sm: { when: "緊湊清單(與 md 同視覺,保留供密度語意)" }
|
|
7
7
|
md: { when: "default 一般導覽樹" } # ★ default
|
|
8
|
-
lg: { when: "touch / 大字級
|
|
8
|
+
lg: { when: "touch / 大字級" }
|
|
9
9
|
traits:
|
|
10
10
|
- hasInteractiveStates
|
|
11
11
|
- isStructural
|
|
@@ -41,7 +41,7 @@ TreeView 本身只負責三件事:
|
|
|
41
41
|
|
|
42
42
|
- **階層結構資料**:檔案管理器資料夾樹、部門組織架構、專案 / 子專案 / 任務、權限群組
|
|
43
43
|
- **Sidebar 內的分層導覽**:workspace > channel > thread、product > category > item
|
|
44
|
-
-
|
|
44
|
+
- **可展開收合的階層清單**:程式碼檔案樹、JSON viewer、DOM inspector(遞迴巢狀結構;平面章節如 FAQ / 設定分組屬 Accordion,見「何時不用」)
|
|
45
45
|
- **任意多層**:從 1 層到 N 層深度都由同一個 TreeView 承載
|
|
46
46
|
|
|
47
47
|
## 何時不用
|
|
@@ -49,8 +49,8 @@ TreeView 本身只負責三件事:
|
|
|
49
49
|
| 場景 | 改用 | 原因 |
|
|
50
50
|
|------|------|------|
|
|
51
51
|
| 平面資料(無階層)| `DataTable` / 自訂 list | TreeView 為階層而設計,沒 children 的平面用 list |
|
|
52
|
-
|
|
|
53
|
-
|
|
|
52
|
+
| 平面章節折疊(FAQ / 設定分組,無階層)| `Accordion`(`type="single"` 互斥 / `type="multiple"` 多開)| TreeView 是遞迴階層 node;平面章節不論單開或多開都屬 Accordion 範疇(accordion.spec.md「何時用」列 FAQ 為主要用途)|
|
|
53
|
+
| 純視覺分段 / 設計時可列舉的 1 層固定選單 | `SidebarGroup` / `SidebarMenu` | Sidebar 主選單只接受 1 層可列舉項目;任何真階層(深度 > 1、runtime 可新增、user data)一律 TreeView(見 sidebar.spec.md「判斷規則」)|
|
|
54
54
|
| 選單式展開(點完就關)| `DropdownMenu` + sub-menu | DropdownMenu 的 sub menu 是 temporary,TreeView 是 persistent |
|
|
55
55
|
| 階層選擇但需要搜尋 / 快速找 | 自訂 tree + search filter(未來 TreeView 可加 search prop)| 基本 TreeView 不含 search |
|
|
56
56
|
|
|
@@ -182,7 +182,7 @@ Chevron 是**展開/收合控件**,不是 prefix icon:`fg-muted`(指示色,hover
|
|
|
182
182
|
|
|
183
183
|
| 元素 | Role | 屬性 |
|
|
184
184
|
|---|---|---|
|
|
185
|
-
| TreeView 容器 | `role="tree"` |
|
|
185
|
+
| TreeView 容器 | `role="tree"` | **`aria-label` 或 `aria-labelledby`(擇一必填 — accessible name)**,`aria-multiselectable`(多選時) |
|
|
186
186
|
| TreeItem 外層 | `role="treeitem"` | `aria-expanded`(expandable 才有),`aria-selected`,`aria-level` |
|
|
187
187
|
| TreeItem children 容器 | `role="group"` | — |
|
|
188
188
|
|
|
@@ -393,6 +393,8 @@ TreeView 真實展示需要**多層巢狀結構**才有意義(單節點無法體
|
|
|
393
393
|
|
|
394
394
|
**ARIA / Pattern**:自建 ARIA tree(非沿用 Radix 預設)。容器 `role="tree"`(多選時加 `aria-multiselectable`),每個 node `role="treeitem"` + `aria-expanded`(expandable 才有)/ `aria-selected` / `aria-level`,皆由元件手動設定(`tree-view.tsx` TreeItem render)。Radix `collapsible` 僅用於 children 展開 / 收合的高度動畫,**不提供** tree 的 role / aria / 鍵盤導覽(Radix 沒有 Tree primitive,見「定位」段)。對齊 [WAI-ARIA TreeView pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/)。`aria-setsize` / `aria-posinset` **刻意省略**:APG 規定只有當節點未全數 render 進 DOM(lazy load)或 DOM 序 ≠ 閱讀序時才必需;本元件全可見節點皆在 DOM(`querySelectorAll('[role="treeitem"]:not([hidden])')`)且 DOM 序 = 閱讀序,故非必需。
|
|
395
395
|
|
|
396
|
+
**Accessible name(必填契約)**:`role="tree"` 的名稱無法從子節點內容推導,consumer **必須**提供 `aria-label`(直接字串)或 `aria-labelledby`(指向可見標題的 id)其中之一——有可見標題時優先 `aria-labelledby`,無則用 `aria-label`。兩者皆缺 → 螢幕閱讀器只讀出「tree」無法辨識用途(WAI-ARIA APG 要求 `role="tree"` 具 accessible name)。`tree-view.tsx` 於 `process.env.NODE_ENV !== 'production'` 時 `console.warn` 提示,避免上線後才發現無名稱樹(對齊 Button / Tag 的 dev-only 誤用警告 idiom)。
|
|
397
|
+
|
|
396
398
|
**Keyboard 行為**(自建 handler,`tree-view.tsx` handleKeyDown):
|
|
397
399
|
|
|
398
400
|
- Tab — 焦點進入整棵 tree(單一 tab stop)
|
|
@@ -137,10 +137,10 @@ export const LongLabel: Story = {
|
|
|
137
137
|
<div className="flex flex-col gap-2">
|
|
138
138
|
<span className="text-caption font-medium text-fg-muted">預設 truncate</span>
|
|
139
139
|
<div className="w-[220px] border border-divider rounded-lg bg-surface overflow-hidden py-2">
|
|
140
|
-
<TreeView aria-label="
|
|
141
|
-
<TreeItem id="proj" icon={Folder} label="
|
|
142
|
-
<TreeItem id="f1" icon={FileText} label="
|
|
143
|
-
<TreeItem id="f2" icon={FileText} label="
|
|
140
|
+
<TreeView aria-label="產品設計檔案樹(截斷)" defaultExpandedIds={['proj']}>
|
|
141
|
+
<TreeItem id="proj" icon={Folder} label="2026 產品品牌識別設計提案">
|
|
142
|
+
<TreeItem id="f1" icon={FileText} label="首頁主視覺設計稿-桌面版-v3.fig" />
|
|
143
|
+
<TreeItem id="f2" icon={FileText} label="logo.svg" />
|
|
144
144
|
</TreeItem>
|
|
145
145
|
</TreeView>
|
|
146
146
|
</div>
|
|
@@ -148,10 +148,10 @@ export const LongLabel: Story = {
|
|
|
148
148
|
<div className="flex flex-col gap-2">
|
|
149
149
|
<span className="text-caption font-medium text-fg-muted">label 換行(移除 truncate)</span>
|
|
150
150
|
<div className="w-[220px] border border-divider rounded-lg bg-surface overflow-hidden py-2">
|
|
151
|
-
<TreeView aria-label="
|
|
152
|
-
<TreeItem id="proj2" icon={Folder} label={<span className="break-words whitespace-normal"
|
|
153
|
-
<TreeItem id="f3" icon={FileText} label={<span className="break-words whitespace-normal"
|
|
154
|
-
<TreeItem id="f4" icon={FileText} label="
|
|
151
|
+
<TreeView aria-label="產品設計檔案樹(換行)" defaultExpandedIds={['proj2']}>
|
|
152
|
+
<TreeItem id="proj2" icon={Folder} label={<span className="break-words whitespace-normal">2026 產品品牌識別設計提案完整版</span>}>
|
|
153
|
+
<TreeItem id="f3" icon={FileText} label={<span className="break-words whitespace-normal">首頁主視覺設計稿-桌面版與行動版對照-v3-最終定稿.fig</span>} />
|
|
154
|
+
<TreeItem id="f4" icon={FileText} label="logo.svg" />
|
|
155
155
|
</TreeItem>
|
|
156
156
|
</TreeView>
|
|
157
157
|
</div>
|
|
@@ -263,38 +263,4 @@ export const DragAndDrop: Story = {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
// @story-trait-rationale: AllSizes retired per F migration(2026-05-15)— anatomy.stories.tsx SizeMatrix auto-compile owns size showcase。
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
export const IndentAlignment: Story = {
|
|
269
|
-
name: '縮排結構對齊驗證',
|
|
270
|
-
render: () => (
|
|
271
|
-
<div className="flex flex-col gap-4">
|
|
272
|
-
<div className="flex flex-col gap-1">
|
|
273
|
-
<h3 className="text-h6 font-semibold">indentStep = chevronSize + gap-2</h3>
|
|
274
|
-
<p className="text-caption text-fg-muted max-w-xl">
|
|
275
|
-
子 chevron 應對齊父 icon 的起始位置,子 icon 應對齊父 label 的起始位置。
|
|
276
|
-
這裡混合有 / 無 children 的 node 驗證 chevron placeholder 佔位(leaf 無條件留等寬空白);
|
|
277
|
-
icon 無自動佔位——無 icon 的 node(README.md / public)label 起點前移,屬「Icon 使用策略」
|
|
278
|
-
的混用反例,此處僅作 indent 結構驗證。
|
|
279
|
-
</p>
|
|
280
|
-
</div>
|
|
281
|
-
<div className="w-[300px] border border-divider rounded-lg bg-surface overflow-hidden py-2">
|
|
282
|
-
<TreeView aria-label="專案檔案樹" defaultExpandedIds={['src', 'components', 'public']}>
|
|
283
|
-
<TreeItem id="src" icon={Folder} label="src">
|
|
284
|
-
<TreeItem id="app" icon={FileCode} label="App.tsx" />
|
|
285
|
-
<TreeItem id="readme" label="README.md" />
|
|
286
|
-
</TreeItem>
|
|
287
|
-
<TreeItem id="public" label="public">
|
|
288
|
-
<TreeItem id="favicon" icon={Image} label="favicon.ico" />
|
|
289
|
-
</TreeItem>
|
|
290
|
-
<TreeItem id="components" icon={Folder} label="components">
|
|
291
|
-
<TreeItem id="button" icon={Folder} label="Button">
|
|
292
|
-
<TreeItem id="button-tsx" icon={FileCode} label="Button.tsx" />
|
|
293
|
-
<TreeItem id="button-test" label="Button.test.tsx" />
|
|
294
|
-
</TreeItem>
|
|
295
|
-
</TreeItem>
|
|
296
|
-
</TreeView>
|
|
297
|
-
</div>
|
|
298
|
-
</div>
|
|
299
|
-
),
|
|
300
|
-
}
|
|
266
|
+
// @story-trait-rationale: IndentAlignment retired per Dim 24 dedup(2026-07-17)— indentStep=chevronSize+gap-2 幾何三重重複(showcase / anatomy IndentMatrix / principles IndentRule)。geometry 歸 anatomy.stories.tsx IndentMatrix、縮排原則 + icon 混用反例(唯一在此的內容)已遷入 principles.stories.tsx IndentRule;showcase 層不重複教 geometry(同 AllSizes / States 退役先例)。
|
|
@@ -293,6 +293,25 @@ const TreeView = React.forwardRef<HTMLDivElement, TreeViewProps>(
|
|
|
293
293
|
},
|
|
294
294
|
ref
|
|
295
295
|
) => {
|
|
296
|
+
// ── Accessible name dev-warn(2026-07-18:兌現 spec「Accessible name 必填契約」段承諾 —
|
|
297
|
+
// 原 spec 宣稱有此 console.warn 但 code 缺,spec-code drift;補上使兩者一致)──
|
|
298
|
+
// role="tree" 名稱無法從子節點推導,缺 aria-label / aria-labelledby → SR 只讀「tree」。
|
|
299
|
+
// 對齊 Button / Tag 的 dev-only 誤用警告 idiom;production 不觸發。
|
|
300
|
+
const ariaLabel = props['aria-label']
|
|
301
|
+
const ariaLabelledby = props['aria-labelledby']
|
|
302
|
+
React.useEffect(() => {
|
|
303
|
+
if (
|
|
304
|
+
process.env.NODE_ENV !== 'production' &&
|
|
305
|
+
ariaLabel == null &&
|
|
306
|
+
ariaLabelledby == null
|
|
307
|
+
) {
|
|
308
|
+
console.warn(
|
|
309
|
+
'[DS] TreeView:role="tree" 缺 accessible name — 請傳 aria-label(直接字串)或 aria-labelledby(指向可見標題 id)其一。' +
|
|
310
|
+
'兩者皆缺時螢幕閱讀器只讀出「tree」無法辨識用途(WAI-ARIA APG 要求 role="tree" 具 accessible name)。',
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
}, [ariaLabel, ariaLabelledby])
|
|
314
|
+
|
|
296
315
|
// ── Expand state(受控 / 非受控) ──
|
|
297
316
|
const [internalExpanded, setInternalExpanded] = React.useState(
|
|
298
317
|
() => new Set(defaultExpandedIds)
|
|
@@ -776,6 +795,23 @@ const TreeView = React.forwardRef<HTMLDivElement, TreeViewProps>(
|
|
|
776
795
|
isKeyboardRef.current = true
|
|
777
796
|
if (!treeRef.current) return
|
|
778
797
|
|
|
798
|
+
// ── 互動 descendant 自理鍵盤(先於導覽 / 重排分支)──
|
|
799
|
+
// 公開 inlineActions / inlineActionsSlot 經 <ItemInlineAction> 渲染的原生 <button>
|
|
800
|
+
// (及 consumer slot 內的 link / field / role=button)是各自獨立的 tab stop(spec
|
|
801
|
+
// A11y「單一 tab stop」段)。其 Enter/Space/方向鍵應由該控件自理——若冒泡到容器
|
|
802
|
+
// handleKeyDown,下方 Enter/Space 分支的 e.preventDefault()+select() 會吃掉 button
|
|
803
|
+
// 原生啟動並誤選 tree node。虛擬焦點模型下 tree 導覽/重排只在事件來自容器本身時處理
|
|
804
|
+
// (DOM focus 停在 tree 容器;treeitem row / chevron / checkbox 皆 tabIndex=-1)。
|
|
805
|
+
const keyTarget = e.target as HTMLElement | null
|
|
806
|
+
if (keyTarget && keyTarget !== e.currentTarget) {
|
|
807
|
+
const interactive = keyTarget.closest<HTMLElement>(
|
|
808
|
+
'a[href], button, input, select, textarea, [contenteditable="true"], [tabindex]:not([tabindex="-1"])'
|
|
809
|
+
)
|
|
810
|
+
// interactive === e.currentTarget:唯一可聚焦祖先是 tree 容器(tabIndex=0 單一 tab
|
|
811
|
+
// stop 進出點)→ 屬非互動 descendant,照常走 tree 導覽。
|
|
812
|
+
if (interactive && interactive !== e.currentTarget) return
|
|
813
|
+
}
|
|
814
|
+
|
|
779
815
|
// ── 鍵盤重排:Cmd/Ctrl+Shift+方向鍵(2026-07-14 v1,詳 spec「鍵盤重排」)──
|
|
780
816
|
// 必排在下方「無焦點時方向鍵先聚焦第一項」分支之前(該分支不分 modifier 攔 Arrow*);
|
|
781
817
|
// 非 modifier 導覽路徑(下方 switch)完全不變。
|
package/src/index.ts
CHANGED
|
@@ -76,7 +76,6 @@ export {
|
|
|
76
76
|
Button,
|
|
77
77
|
ButtonDivider,
|
|
78
78
|
ButtonGroup,
|
|
79
|
-
ButtonGroupContext,
|
|
80
79
|
buttonVariants,
|
|
81
80
|
} from './components/Button/index'
|
|
82
81
|
export type {
|
|
@@ -192,8 +191,8 @@ export {
|
|
|
192
191
|
DescriptionList,
|
|
193
192
|
} from './components/DescriptionList/index'
|
|
194
193
|
export type {
|
|
195
|
-
DescriptionDirection,
|
|
196
194
|
DescriptionItemProps,
|
|
195
|
+
DescriptionListOrientation,
|
|
197
196
|
DescriptionListProps,
|
|
198
197
|
} from './components/DescriptionList/index'
|
|
199
198
|
export {
|
|
@@ -228,7 +227,6 @@ export {
|
|
|
228
227
|
DropdownMenuSubContent,
|
|
229
228
|
DropdownMenuSubTrigger,
|
|
230
229
|
DropdownMenuTrigger,
|
|
231
|
-
floatingLayerClass,
|
|
232
230
|
} from './components/DropdownMenu/index'
|
|
233
231
|
export type {
|
|
234
232
|
DropdownMenuItemProps,
|
|
@@ -246,7 +244,6 @@ export {
|
|
|
246
244
|
FieldError,
|
|
247
245
|
FieldGroup,
|
|
248
246
|
FieldLabel,
|
|
249
|
-
getMenuListMinHeight,
|
|
250
247
|
useFormValidation,
|
|
251
248
|
} from './components/Field/index'
|
|
252
249
|
export type {
|
|
@@ -417,7 +414,6 @@ export {
|
|
|
417
414
|
SheetPortal,
|
|
418
415
|
SheetTitle,
|
|
419
416
|
SheetTrigger,
|
|
420
|
-
handleSheetOpenAutoFocus,
|
|
421
417
|
sheetVariants,
|
|
422
418
|
} from './components/Sheet/index'
|
|
423
419
|
export {
|
|
@@ -548,13 +544,10 @@ export {
|
|
|
548
544
|
ItemAvatar,
|
|
549
545
|
ItemContent,
|
|
550
546
|
ItemIcon,
|
|
551
|
-
ItemInlineAction,
|
|
552
|
-
ItemInlineActionButton,
|
|
553
547
|
ItemLabel,
|
|
554
548
|
ItemPrefix,
|
|
555
549
|
ItemSuffix,
|
|
556
550
|
ROW_PADDING_BY_SIZE,
|
|
557
|
-
RowSizeProvider,
|
|
558
551
|
getUniformPrefixSlotStyle,
|
|
559
552
|
itemPrefixAlignVariants,
|
|
560
553
|
useRowSize,
|
|
@@ -564,8 +557,6 @@ export type {
|
|
|
564
557
|
ItemAvatarProps,
|
|
565
558
|
ItemContentProps,
|
|
566
559
|
ItemIconProps,
|
|
567
|
-
ItemInlineActionButtonProps,
|
|
568
|
-
ItemInlineActionProps,
|
|
569
560
|
ItemSuffixHoverGroup,
|
|
570
561
|
ItemSuffixProps,
|
|
571
562
|
RowSize,
|
|
@@ -598,6 +589,18 @@ export type {
|
|
|
598
589
|
// - components/SelectionControl
|
|
599
590
|
// - patterns/horizontal-overflow
|
|
600
591
|
// - patterns/overlay-surface
|
|
592
|
+
// 另有 public 元件內個別標 @internal jsDoc 的符號亦排除 front-door(2026-07-18 決策3;subpath 仍有):
|
|
593
|
+
// - components/Button:ButtonGroupContext
|
|
594
|
+
// - components/DropdownMenu:floatingLayerClass
|
|
595
|
+
// - components/Field:FieldVariantInternal
|
|
596
|
+
// - components/Field:WithFieldVariantInternal
|
|
597
|
+
// - components/Field:getMenuListMinHeight
|
|
598
|
+
// - components/Sheet:handleSheetOpenAutoFocus
|
|
599
|
+
// - patterns/element-anatomy:ItemInlineAction
|
|
600
|
+
// - patterns/element-anatomy:ItemInlineActionButton
|
|
601
|
+
// - patterns/element-anatomy:ItemInlineActionButtonProps
|
|
602
|
+
// - patterns/element-anatomy:ItemInlineActionProps
|
|
603
|
+
// - patterns/element-anatomy:RowSizeProvider
|
|
601
604
|
|
|
602
605
|
// ─── Tokens(JS mirrors — token SSOT 程式面)──────────────────────────────
|
|
603
606
|
export * from './tokens/categorical-color'
|
package/src/lib/drag-visual.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* ## Pattern
|
|
8
8
|
*
|
|
9
|
-
* - **Source element**(被拖中的 row/column):`opacity-
|
|
9
|
+
* - **Source element**(被拖中的 row/column):`opacity-disabled`(= var(--opacity-disabled) 0.45 半透,user 仍看得到原位;2026-05-06 v14.5.2 由 opacity-30 改)
|
|
10
10
|
* — 不是 `opacity:0` 全隱形,因 user 拖太遠看不到「源頭」會迷失方向。對齊 TreeView 最早 v1 + Notion / Atlassian / Linear。
|
|
11
11
|
* - **Ghost preview**(浮動 follow cursor):透過 dnd-kit `<DragOverlay>` portal,clone source 的 outerHTML
|
|
12
12
|
* strip transform/transition/opacity → render 在 portal 層,visually 跟 cursor 走。
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* - `bg-primary`:semantic state token(`--primary`)— 跟 focus state ring color 同 source(M23 一致)
|
|
27
27
|
* - `bg-primary-subtle`:semantic primary subtle(`--primary-subtle`)— inside-drop dim background
|
|
28
28
|
* - `h-0.5` / `w-0.5`:Tailwind size token = 2px(對齊 hairline divider thickness 概念)
|
|
29
|
-
* - `opacity-
|
|
29
|
+
* - `opacity-disabled`:DS token var(--opacity-disabled)= 0.45(半透但仍清楚看到 outline;見下方 v14.5.2 note)
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
import type * as React from 'react'
|
package/src/lib/utils.ts
CHANGED
|
@@ -92,3 +92,22 @@ const twMerge = extendTailwindMerge({
|
|
|
92
92
|
export function cn(...inputs: ClassValue[]) {
|
|
93
93
|
return twMerge(clsx(inputs))
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
// ── line-clamp 安全對照(2026-07-18 決策4)────────────────────────────────────
|
|
97
|
+
// 動態 `line-clamp-${n}` / `line-clamp-[${n}]` = Tailwind 掃不到具體值 → silent 失效(失敗記憶索引:
|
|
98
|
+
// 「Tailwind v4 動態 class」陷阱)。此 map 全靜態字串 → Tailwind 可掃。canonical 上限 1-6(spec maxLines/
|
|
99
|
+
// descriptionClamp ≤6);超界值 dev-warn + clamp 回 6(不 crash、不靜默失效)。null/0/undefined → 不 clamp。
|
|
100
|
+
const LINE_CLAMP: Record<number, string> = {
|
|
101
|
+
1: 'line-clamp-1', 2: 'line-clamp-2', 3: 'line-clamp-3',
|
|
102
|
+
4: 'line-clamp-4', 5: 'line-clamp-5', 6: 'line-clamp-6',
|
|
103
|
+
}
|
|
104
|
+
export function lineClampClass(n: number | undefined | null): string | undefined {
|
|
105
|
+
if (n == null || n <= 0) return undefined
|
|
106
|
+
const rounded = Math.round(n)
|
|
107
|
+
if (rounded !== n || n > 6) {
|
|
108
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
|
|
109
|
+
console.warn(`[DS] line-clamp 值 ${n} 超出 canonical 範圍 1-6(或非整數)→ clamp 回 6。請傳 1-6 整數。`)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return LINE_CLAMP[Math.min(6, Math.max(1, rounded))]
|
|
113
|
+
}
|
|
@@ -168,7 +168,7 @@ Q3. Row 多大?
|
|
|
168
168
|
#### Content-role vs action-role 分層(附補充原理)
|
|
169
169
|
|
|
170
170
|
Row 內元件分兩類,**size 規則不同**:
|
|
171
|
-
- **Content-role**(display 資料):`<Input mode="
|
|
171
|
+
- **Content-role**(display 資料):`<Input mode="view">` / Badge / Avatar / Tag → size 對應 row tier(sm row → sm)
|
|
172
172
|
- **Action-role**(互動觸發):row action icon → **固定 ≤ 24**,不參與 content size-pair
|
|
173
173
|
|
|
174
174
|
Row action 的 affordance 是「次要功能」,不是 primary CTA。Button chrome 過度強調;用 **Button xs 24 固定** 提供 command affordance 但不侵蝕 content hierarchy。
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import type { LucideIcon } from "lucide-react"
|
|
5
5
|
import { cva } from "class-variance-authority"
|
|
6
|
-
import { cn } from "@/lib/utils"
|
|
6
|
+
import { cn, lineClampClass } from "@/lib/utils"
|
|
7
7
|
import { Avatar, type AvatarProps } from "@/design-system/components/Avatar/avatar"
|
|
8
8
|
import {
|
|
9
9
|
Tooltip,
|
|
@@ -392,7 +392,7 @@ export const ItemContent = React.forwardRef<HTMLDivElement, ItemContentProps>(
|
|
|
392
392
|
? "text-[length:var(--font-body-size)]"
|
|
393
393
|
: ""
|
|
394
394
|
|
|
395
|
-
const clampClass = descriptionClamp
|
|
395
|
+
const clampClass = lineClampClass(descriptionClamp) ?? ""
|
|
396
396
|
|
|
397
397
|
return (
|
|
398
398
|
<div
|
|
@@ -558,6 +558,7 @@ ItemAvatar.displayName = "ItemAvatar"
|
|
|
558
558
|
//
|
|
559
559
|
// 接受任何 button props 並 spread(讓 Radix Slot 可以 merge onClick / data-state 等)
|
|
560
560
|
|
|
561
|
+
/** @internal — internal ItemInlineActionButton 的 props;隨其元件同走 subpath,不進 root barrel front-door。 */
|
|
561
562
|
export interface ItemInlineActionButtonProps
|
|
562
563
|
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
|
|
563
564
|
/** Lucide icon 元件 */
|
|
@@ -662,6 +663,7 @@ ItemInlineActionButton.displayName = "ItemInlineActionButton"
|
|
|
662
663
|
// 需要接 Radix asChild(例如 collapsible trigger)時改用 `ItemInlineActionButton`,
|
|
663
664
|
// 那層沒有 Tooltip 包裝,Root 就是 button,可直接塞進 Radix Slot。
|
|
664
665
|
|
|
666
|
+
/** @internal — internal ItemInlineAction 的 props;隨其元件同走 subpath,不進 root barrel front-door。 */
|
|
665
667
|
export interface ItemInlineActionProps {
|
|
666
668
|
action: InlineActionConfig
|
|
667
669
|
/** Size 覆寫(見 `ItemInlineActionButtonProps.size`)——Field Controls / Tag 必傳 */
|
|
@@ -270,6 +270,15 @@ ChromeHeader / SurfaceHeader 新增 `tabsSlot?: ReactNode` prop。提供時自
|
|
|
270
270
|
|
|
271
271
|
**不開**:`density?: 'md'|'lg'` 自由 prop(M21 違反 — 任意 density 等於 cva-on-pattern,該由 density context 決定)。`lockDensity="lg"` 原為 fullscreen viewer escape hatch,但 **2026-06-15 起無 consumer 使用** — FileViewer 改為全 surface 繼承 page density(原本只鎖兩個 header、沒鎖 body → 左緣不對齊,圖二 bug)。density lock 一律設在 **surface 根**而非 header primitive(見 `density.spec.md` anti-pattern)。其餘 consumer 走 `inherit`(跟 page density)。**Grep evidence**(historical 錨,migration 已完成):migration 前 `Sidebar` + `FileViewer Toolbar/InfoPanel` 各自手刻同一 signature `flex items-center gap-2 shrink-0 h-[var(--chrome-header-height)] border-b border-divider px-[var(--layout-space-loose)]`(production 重複 contract,非 premature abstraction)→ 過 M21 prop variant test 3 條(`<Sidebar>` 等近親 grep / 3 家世界級 page-header primitive / value 結構不同)→ 抽成本 primitive。**現況**:全部已消費 `<ChromeHeader>`(`sidebar.tsx:479` / `file-viewer.tsx:340` Toolbar + `:474` InfoPanel),grep 全 repo 已無此手刻 signature(除 `chrome-header.tsx` primitive 本身)。
|
|
272
272
|
|
|
273
|
+
### 空 children / action state 契約(rendering contract)
|
|
274
|
+
|
|
275
|
+
**空 children**:`ChromeHeaderProps extends React.HTMLAttributes<HTMLElement>`,故 `children` 型別上 optional;但**實作恆渲染固定高度 row**(single-row `h-[var(--chrome-header-height)]` + `border-b`,`chrome-header.tsx:167-183`;`tabsSlot` 模式 row 1 亦恆渲染,`:113-122`)。因此:
|
|
276
|
+
|
|
277
|
+
- **沒有 title / actions 時不要渲染 ChromeHeader**——空 children 只會留一條固定高度 + border 的空白 chrome row(`tabsSlot` 模式更明顯:tabs 上方多整行空白標題列)。consumer 條件渲染,有內容才掛 header,而非傳空殼。
|
|
278
|
+
- **只有 tabs、無獨立標題列**的場景 → 用 standalone `<Tabs size="lg">`(tab 高 = chrome-header-height,見「選哪個 header」表 C 列),**不要**空 children + `tabsSlot` 硬撐。
|
|
279
|
+
|
|
280
|
+
**Action loading / disabled 歸屬**:ChromeHeader 只負責 slot 排版,**不擁有**注入 action 的非同步狀態。header 內 Button / 控件的 `loading` / `disabled` 由 consumer 注入的元件自帶(如 `<Button loading>` 自畫 spinner),ChromeHeader 層**無** loading / disabled prop。故本 primitive 的 **Loading 驗證 = N/A**(排版 primitive,無自身 async state)。
|
|
281
|
+
|
|
273
282
|
### Layer 4 — Hook mechanical
|
|
274
283
|
|
|
275
284
|
`chrome_header_dispatcher.sh` 依序 dispatch **4 個 lib helper**(完整清單 SSOT = dispatcher 本身,避免 spec drift):
|
|
@@ -68,9 +68,13 @@ export const SingleRow = () => (
|
|
|
68
68
|
<Separator orientation="vertical" className="h-6 mx-1" />
|
|
69
69
|
<Button iconOnly dismiss size="sm" startIcon={X} aria-label="關閉" />
|
|
70
70
|
</ChromeHeader>
|
|
71
|
-
<div className="p-6 text-body text-fg-secondary"
|
|
71
|
+
<div className="flex flex-col gap-2 p-6 text-body text-fg-secondary">
|
|
72
|
+
<p className="text-caption text-fg-muted">陳雅婷 更新於 2026/04/18 · 12 頁 · 2.4 MB</p>
|
|
73
|
+
<p>本季合併營收 NT$4.82 億,較上季成長 8.2%;毛利率維持 41%。附錄含各區域損益與現金流量表。</p>
|
|
74
|
+
</div>
|
|
72
75
|
</Panel>
|
|
73
76
|
)
|
|
77
|
+
SingleRow.storyName = '單列(標題 + 動作列)'
|
|
74
78
|
|
|
75
79
|
/** 2. withTabs — header 含分頁列(對標 FileViewer InfoPanel / 設定頁 header)。
|
|
76
80
|
* 傳 tabsSlot 自動進 column 結構:row1 = 標題列、row2 = TabsList 全寬畫線。 */
|
|
@@ -92,17 +96,29 @@ export const WithTabs = () => (
|
|
|
92
96
|
<Button iconOnly dismiss size="sm" startIcon={X} aria-label="關閉" />
|
|
93
97
|
</ChromeHeader>
|
|
94
98
|
<TabsContent value="overview">
|
|
95
|
-
<div className="p-6 text-body text-fg-secondary"
|
|
99
|
+
<div className="flex flex-col gap-1 p-6 text-body text-fg-secondary">
|
|
100
|
+
<p>負責人:林思妤 · 期程:2026/03–2026/06 · 狀態:設計中</p>
|
|
101
|
+
<p>將既有品牌識別全面翻新——logo、配色與元件庫,預計 Q2 上線。</p>
|
|
102
|
+
</div>
|
|
96
103
|
</TabsContent>
|
|
97
104
|
<TabsContent value="activity">
|
|
98
|
-
<div className="p-6 text-body text-fg-secondary"
|
|
105
|
+
<div className="flex flex-col gap-1 p-6 text-body text-fg-secondary">
|
|
106
|
+
<p>陳柏宇 上傳了「新版 logo 提案 v3」· 2 小時前</p>
|
|
107
|
+
<p>林思妤 將狀態改為「設計中」· 昨天</p>
|
|
108
|
+
<p>Aisha Khan 留言:配色再往暖色調微調 · 3 天前</p>
|
|
109
|
+
</div>
|
|
99
110
|
</TabsContent>
|
|
100
111
|
<TabsContent value="files">
|
|
101
|
-
<div className="p-6 text-body text-fg-secondary"
|
|
112
|
+
<div className="flex flex-col gap-1 p-6 text-body text-fg-secondary">
|
|
113
|
+
<p>品牌識別規範_v3.pdf · 8.1 MB</p>
|
|
114
|
+
<p>logo 原始檔.ai · 24 MB</p>
|
|
115
|
+
<p>配色對照表.xlsx · 320 KB</p>
|
|
116
|
+
</div>
|
|
102
117
|
</TabsContent>
|
|
103
118
|
</Tabs>
|
|
104
119
|
</Panel>
|
|
105
120
|
)
|
|
121
|
+
WithTabs.storyName = '含分頁列'
|
|
106
122
|
|
|
107
123
|
/** Overview — header anatomy 兩型疊起來一次看完,每型上方標清「何時用 + 對標既有元件」。
|
|
108
124
|
* 注:ChromeHeader 另有 `leadingRail` slot,但它專為「跟 sidebar 收合 icon 對齊」而生(寬 = sidebar 收合寬),
|
|
@@ -136,7 +152,16 @@ export const Overview = () => (
|
|
|
136
152
|
<h2 className="flex-1 truncate text-body-lg font-medium text-foreground">編輯專案設定</h2>
|
|
137
153
|
<Button iconOnly dismiss size="sm" startIcon={X} aria-label="關閉" />
|
|
138
154
|
</SurfaceHeader>
|
|
139
|
-
<div className="p-6 text-body text-fg-secondary"
|
|
155
|
+
<div className="flex flex-col gap-3 p-6 text-body text-fg-secondary">
|
|
156
|
+
<div className="flex flex-col gap-0.5">
|
|
157
|
+
<span className="text-caption text-fg-muted">專案名稱</span>
|
|
158
|
+
<span className="text-foreground">Acme 品牌改版專案</span>
|
|
159
|
+
</div>
|
|
160
|
+
<div className="flex flex-col gap-0.5">
|
|
161
|
+
<span className="text-caption text-fg-muted">可見範圍</span>
|
|
162
|
+
<span className="text-foreground">團隊成員(12 人)</span>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
140
165
|
</div>
|
|
141
166
|
</section>
|
|
142
167
|
<section className="flex flex-col gap-2">
|
|
@@ -148,3 +173,4 @@ export const Overview = () => (
|
|
|
148
173
|
</section>
|
|
149
174
|
</div>
|
|
150
175
|
)
|
|
176
|
+
Overview.storyName = '總覽'
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* **機械防線**:`scripts/categorical-color-invariants.mjs` I1(release:preflight 已 chain)強制 map 的 key X 的值含 `--color-X-`(名實一致,禁 offset;原引 hook 名不存在,2026-07-04 修)。
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
/** 12 個 categorical
|
|
27
|
+
/** 12 個 categorical 色相。⚠️ 順序 = **categorical 指派序**(圖表系列鄰色最大區辨:blue→green→deep-orange→yellow→red…),**非** primitives.css 檔內宣告序 — 兩者本就不同,map 以名為 key 故功能無涉;**禁**為「對齊」重排(重排 = 圖表系列換色 = 視覺 breaking)。 */
|
|
28
28
|
export const CATEGORICAL_HUES = [
|
|
29
29
|
'blue',
|
|
30
30
|
'green',
|
|
@@ -64,8 +64,8 @@ export const CAT_SUBTLE: Record<CategoricalHue, string> = {
|
|
|
64
64
|
/**
|
|
65
65
|
* solid 模式 class:step-6 底 + on-emphasis 配對文字。
|
|
66
66
|
* 文字色依「step-6 底亮度」分桶(WCAG ≥3:1 大粗字門檻,2026-06-04 user「以最低為原則」):
|
|
67
|
-
* - 夠深的色底 → `text-on-emphasis`(白):blue / deep-orange / red /
|
|
68
|
-
* - 太亮的色底 → `text-on-emphasis-dark`(深):yellow / amber / orange / lime(白字連 3:1
|
|
67
|
+
* - 夠深的色底 → `text-on-emphasis`(白):blue / deep-orange / red / indigo / purple / magenta
|
|
68
|
+
* - 太亮的色底 → `text-on-emphasis-dark`(深):yellow / amber / orange / lime / turquoise(白字連 3:1 都不過;turquoise 2026-07-16 dark 色相修正後 L=0.68 白字 2.77 → 切深字,兩 mode 5.65/6.47 全過)
|
|
69
69
|
* - ★ green 例外:白字 2.47 連 3:1 都不過,但 user 拍板維持白字(綠底白字慣見觀感)= documented exception。
|
|
70
70
|
* 對比為 oklch→相對亮度實測(scripts/categorical-color-invariants.mjs 機械驗,green 列 exempt)。
|
|
71
71
|
*/
|
|
@@ -78,7 +78,7 @@ export const CAT_SOLID: Record<CategoricalHue, string> = {
|
|
|
78
78
|
orange: 'bg-[var(--color-orange-6)] text-on-emphasis-dark',
|
|
79
79
|
amber: 'bg-[var(--color-amber-6)] text-on-emphasis-dark',
|
|
80
80
|
lime: 'bg-[var(--color-lime-6)] text-on-emphasis-dark',
|
|
81
|
-
turquoise: 'bg-[var(--color-turquoise-6)] text-on-emphasis',
|
|
81
|
+
turquoise: 'bg-[var(--color-turquoise-6)] text-on-emphasis-dark',
|
|
82
82
|
indigo: 'bg-[var(--color-indigo-6)] text-on-emphasis',
|
|
83
83
|
purple: 'bg-[var(--color-purple-6)] text-on-emphasis',
|
|
84
84
|
magenta: 'bg-[var(--color-magenta-6)] text-on-emphasis',
|
|
@@ -125,7 +125,7 @@ export const CAT_SOLID_TOKENS: Record<CategoricalHue, { bg: string; text: string
|
|
|
125
125
|
orange: { bg: 'var(--color-orange-6)', text: 'var(--on-emphasis-dark)' },
|
|
126
126
|
amber: { bg: 'var(--color-amber-6)', text: 'var(--on-emphasis-dark)' },
|
|
127
127
|
lime: { bg: 'var(--color-lime-6)', text: 'var(--on-emphasis-dark)' },
|
|
128
|
-
turquoise: { bg: 'var(--color-turquoise-6)', text: 'var(--on-emphasis)' },
|
|
128
|
+
turquoise: { bg: 'var(--color-turquoise-6)', text: 'var(--on-emphasis-dark)' },
|
|
129
129
|
indigo: { bg: 'var(--color-indigo-6)', text: 'var(--on-emphasis)' },
|
|
130
130
|
purple: { bg: 'var(--color-purple-6)', text: 'var(--on-emphasis)' },
|
|
131
131
|
magenta: { bg: 'var(--color-magenta-6)', text: 'var(--on-emphasis)' },
|
|
@@ -272,8 +272,8 @@ Tag、Avatar 等需要多色區分的場景(專案標籤、團隊分類等)
|
|
|
272
272
|
|
|
273
273
|
填色底上的文字色**依底色明暗成對**提供(世界級共識:Material `on-primary` family、Radix `--accent-contrast`、Polaris `text-{x}-on-bg-fill` —— 都是「成對 on-color token」,不是單一固定白):
|
|
274
274
|
|
|
275
|
-
- `--on-emphasis = oklch(1 0 0)`(純白,dark mode 不反轉)—— 用於**夠深的飽和色底**(白字達 WCAG 門檻):primitive 6 階深色 / `--primary` / `--error` 等,及 categorical blue/deep-orange/red/
|
|
276
|
-
- `--on-emphasis-dark = var(--black-a85)`(深字,dark mode 不反轉)—— 用於**太亮的色底**(白字對比不足):categorical **yellow / amber / orange / lime
|
|
275
|
+
- `--on-emphasis = oklch(1 0 0)`(純白,dark mode 不反轉)—— 用於**夠深的飽和色底**(白字達 WCAG 門檻):primitive 6 階深色 / `--primary` / `--error` 等,及 categorical blue/deep-orange/red/indigo/purple/magenta(turquoise 2026-07-16 移入深字組)。
|
|
276
|
+
- `--on-emphasis-dark = var(--black-a85)`(深字,dark mode 不反轉)—— 用於**太亮的色底**(白字對比不足):categorical **yellow / amber / orange / lime / turquoise**(turquoise 2026-07-16 dark 色相修正後加入)。
|
|
277
277
|
|
|
278
278
|
**合規門檻(2026-06-04 user 拍板「以最低為原則」)= WCAG large/bold 3:1**(solid chip / avatar 的字視為大粗字)。底色 step-6 白字達 3:1 → 用 `--on-emphasis`;不達 → 用 `--on-emphasis-dark`。
|
|
279
279
|
|
|
@@ -367,7 +367,7 @@ Badge 使用語義色的 text token(`--info-text`、`--error-text`),不直
|
|
|
367
367
|
|
|
368
368
|
**step-7 vs semantic active 的區別**:兩者在 light mode 都指向 step-7,但 dark mode 行為不同。semantic active(如 `--primary-active`)在 dark mode 反轉為 step-5(壓暗模擬按壓感),而 primitive step-7 在 dark mode 仍維持高對比方向。簡言之:active 服務於互動回饋,step-7 服務於閱讀對比,兩者目的不同,dark mode 方向相反。
|
|
369
369
|
|
|
370
|
-
**例外:step-6 滿版底色上的「亮色 hue」文字用 `--on-emphasis-dark`(`black-a85`,深色)**——yellow / amber / orange / lime 亮度極高,白字(`--on-emphasis`)連 WCAG 3:1 都不過,必須深色文字(見上「`--on-emphasis` 配對」段)。此例外只在底色是 step-6 時觸發,step-1 subtle 底色上仍用 step-7。(green-6 白字亦不過 3:1,但列 documented exception 維持白字。)
|
|
370
|
+
**例外:step-6 滿版底色上的「亮色 hue」文字用 `--on-emphasis-dark`(`black-a85`,深色)**——yellow / amber / orange / lime / turquoise 亮度極高,白字(`--on-emphasis`)連 WCAG 3:1 都不過,必須深色文字(見上「`--on-emphasis` 配對」段)。此例外只在底色是 step-6 時觸發,step-1 subtle 底色上仍用 step-7。(green-6 白字亦不過 3:1,但列 documented exception 維持白字。)
|
|
371
371
|
|
|
372
372
|
### Subtle 背景(淡色填充)
|
|
373
373
|
|
|
@@ -501,7 +501,7 @@ Dark mode 覆寫:hover/active 方向反轉(hover → step-7,active → ste
|
|
|
501
501
|
在 `primitives.css` 定義 base-6 值(只需指定 L、C、H),相對公式自動推導 1-10 階。如已存在則跳過。
|
|
502
502
|
|
|
503
503
|
```css
|
|
504
|
-
--color-turquoise-6: oklch(0.
|
|
504
|
+
--color-turquoise-6: oklch(0.64 0.09 196); /* light 真值(primitives.css:183);dark 另於 dark 區塊定義 */
|
|
505
505
|
/* 1-5 / 7-10 自動由公式推導 */
|
|
506
506
|
```
|
|
507
507
|
|
|
@@ -285,7 +285,10 @@
|
|
|
285
285
|
--color-neutral-9-opaque: color-mix(in srgb, white var(--_na9), black);
|
|
286
286
|
|
|
287
287
|
/* Blue */
|
|
288
|
-
|
|
288
|
+
/* 2026-07-16 user 拍板:dark 主色對比升級 — 0.60→0.63(≈#2C84FF,對齊 Apple dark systemBlue)。
|
|
289
|
+
card/table/浮層 surface 上互動文字 4.07-4.10:1(AA ✗)→ 4.63-4.67:1(AA ✓);canvas 5.53:1。
|
|
290
|
+
其餘 1-10 階不手動指定,由本基準經下方既有相對公式自動推導(單一基準,設計語言不變)。 */
|
|
291
|
+
--color-blue-6: oklch(0.63 0.22 258);
|
|
289
292
|
--color-blue-1: oklch(from var(--color-blue-6) l c h / calc(0.12 / l));
|
|
290
293
|
--color-blue-2: oklch(from var(--color-blue-6) calc(l * 0.28) calc(c * 0.65) h);
|
|
291
294
|
--color-blue-3: oklch(from var(--color-blue-6) calc(l * 0.44) calc(c * 0.82) h);
|
|
@@ -369,7 +372,11 @@
|
|
|
369
372
|
--color-green-10: oklch(from var(--color-green-6) calc(l + (1 - l) * 0.75) calc(c * 0.14) h);
|
|
370
373
|
|
|
371
374
|
/* Turquoise */
|
|
372
|
-
|
|
375
|
+
/* 2026-07-16 user 拍板修正:原 oklch(0.57 0.10 225)為複製 spec 假想範例的錯值 — 全 12 色相唯一
|
|
376
|
+
dark 改色相(196→225 = 偏藍)、唯一 L 降(其餘全升)、唯一 C 升,三重違反設計語言。
|
|
377
|
+
修回 H=196(同 light,Apple systemBlue/Teal dark 同樣色相恆定);L 照 11 色相經驗律內插
|
|
378
|
+
(L≤0.58 → +0.05 / L≥0.70 → +0.03;0.64 居中 → +0.04)= 0.68;C 照 ×0.95 2dp 慣例 = 0.09。 */
|
|
379
|
+
--color-turquoise-6: oklch(0.68 0.09 196);
|
|
373
380
|
--color-turquoise-1: oklch(from var(--color-turquoise-6) l c h / calc(0.12 / l));
|
|
374
381
|
--color-turquoise-2: oklch(from var(--color-turquoise-6) calc(l * 0.28) calc(c * 0.65) h);
|
|
375
382
|
--color-turquoise-3: oklch(from var(--color-turquoise-6) calc(l * 0.44) calc(c * 0.82) h);
|
|
@@ -64,7 +64,7 @@ Tailwind 提供 `opacity-{5/10/20/30/40/50/60/70/80/90/95}` 百分比 ladder,但
|
|
|
64
64
|
|
|
65
65
|
## 消費者
|
|
66
66
|
|
|
67
|
-
直接套用 `opacity-disabled` 的元件(grep 驗證 2026-07-
|
|
67
|
+
直接套用 `opacity-disabled` 的元件(grep 驗證 2026-07-16;Textarea 已全面 token-swap 化移除):Avatar(Field disabled context self-dim)、Button(`aria-disabled` 分支)、MenuItem、Rating(disabled / loading 整塊)、Steps、Switch、DataTable(drag source 半透 + 整表 refresh loading reuse,經 `lib/drag-visual.ts`)、PersonDisplay(disabled 整塊,`person-display.tsx:137`)。
|
|
68
68
|
|
|
69
69
|
非消費者(曾誤列):Slider / Sidebar 走灰階 token swap;Chip 無 opacity 用例;Field wrapper blanket 已移除(Avatar self-dim 取代,見 field-wrapper.tsx 註解)。
|
|
70
70
|
|
|
@@ -44,7 +44,7 @@ benchmark:
|
|
|
44
44
|
|
|
45
45
|
**Why**:Material 3「Key Colors & Tones」+ Atlassian「Full color spectrum」共識 — palette 是設計師調色盤 SSOT,缺中間階就斷層,新元件需消費中間色時不該 hot-add。**全色階是 capability,不是 cost**。
|
|
46
46
|
|
|
47
|
-
**Regex**:`^--color-(amber|blue|
|
|
47
|
+
**Regex**:`^--color-(amber|blue|red|green|deep-orange|indigo|lime|orange|purple|yellow)-\d+$`
|
|
48
48
|
|
|
49
49
|
### 2. Magenta / Turquoise 專用 palette(14 token,structural)
|
|
50
50
|
|
|
@@ -40,6 +40,8 @@ Typography 由三個獨立維度組成,分開疊加:
|
|
|
40
40
|
| `text-caption` | 12px | 1.3 | 圖表附註、標籤文字、元件內次要說明 |
|
|
41
41
|
| `text-footnote`| 10px | 1.3 | 法律文字、來源標注(極少用)|
|
|
42
42
|
|
|
43
|
+
> **10px a11y 用途限制**(2026-07-17):`text-footnote` 僅限**非必要的附帶資訊**(法律細字、來源標注、storybook 註解)——目前全庫零正式元件消費,只用於 stories `<p>` 註解。**使用者需理解才能操作的資訊禁止只靠 10px**;任何 ≤12px 用途上線前須驗 200% 放大(WCAG 1.4.4)不裁切。視覺標題 ≠ 語義標題(一律用 `h1–h6`,WCAG 1.3.1)。
|
|
44
|
+
|
|
43
45
|
**h5(16px)vs body-lg(16px)/ h6(14px)vs body(14px)**:同尺寸配對的統一判別法——line-height 區分角色(標題 1.3 / 段落 1.5),使用端再疊 font-weight / color 強化標題層級,需有意識地選擇(詳「同尺寸但不同角色的選法」)。
|
|
44
46
|
|
|
45
47
|
|
|
@@ -121,6 +121,11 @@
|
|
|
121
121
|
--tab-height-md: 2.5rem; /* 40px */
|
|
122
122
|
--tab-height-lg: 3rem; /* 48px */
|
|
123
123
|
|
|
124
|
+
/* 2026-07-16 dim 52 補洞:lg block(上方)有 override --chrome-header-height 3.5rem,
|
|
125
|
+
md-reset 原漏重設 → lg 祖先下 subtree lock md 時 chrome header 仍 56px,破 W3
|
|
126
|
+
像素相等恆等式(md-lock subtree 必須與 root md 逐 token 相等)。值 = :root md default。 */
|
|
127
|
+
--chrome-header-height: 3rem; /* 48px — md default */
|
|
128
|
+
|
|
124
129
|
--tree-indent-sm: 1.5rem; /* 24px — md default */
|
|
125
130
|
--tree-indent-md: 1.5rem; /* 24px — md default */
|
|
126
131
|
--tree-indent-lg: 1.75rem; /* 28px — md default */
|
|
@@ -339,7 +339,7 @@ Overlay family 套 v5 `data-unbounded` slot trick(Button unbounded → SurfaceHe
|
|
|
339
339
|
|
|
340
340
|
## Chrome 左右 inline padding
|
|
341
341
|
|
|
342
|
-
→ SSOT `tokens/layoutSpace/layoutSpace.spec.md`「規則
|
|
342
|
+
→ SSOT `tokens/layoutSpace/layoutSpace.spec.md`「規則 6:Chrome 水平左右 padding(規則 1 specialization)」(統一 `--layout-space-loose`,M8 8 家世界級對照 + 禁止事項)。
|
|
343
343
|
|
|
344
344
|
---
|
|
345
345
|
|