@qijenchen/design-system 0.1.0-beta.83 → 0.1.0-beta.85
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/CLAUDE.md +8 -8
- package/README.md +3 -2
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +1 -1
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +22 -2
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +4 -4
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -2
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +12 -3
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +13 -5
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +7 -1
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +8 -3
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Chart/chart.d.ts.map +1 -1
- package/dist/components/Chart/chart.js +1 -0
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +1 -1
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +8 -4
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +1 -1
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +10 -3
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +5 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +30 -13
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +53 -62
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +10 -4
- 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 +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.js +154 -0
- package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +285 -0
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +140 -0
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +5 -6
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +36 -15
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DataTable/filter-operators.js +140 -0
- package/dist/components/DataTable/filter-operators.js.map +1 -0
- package/dist/components/DataTable/filter-tree.js +312 -0
- package/dist/components/DataTable/filter-tree.js.map +1 -0
- package/dist/components/DataTable/index.d.ts +3 -0
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/index.js +12 -1
- package/dist/components/DataTable/index.js.map +1 -1
- package/dist/components/DataTable/lib/column-meta.js +25 -0
- package/dist/components/DataTable/lib/column-meta.js.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +3 -1
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +7 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +105 -74
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +20 -3
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +38 -20
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +45 -5
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +19 -0
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-edit-keys.d.ts +21 -0
- package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
- package/dist/components/Field/field-edit-keys.js +19 -0
- package/dist/components/Field/field-edit-keys.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +20 -1
- 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 +3 -2
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +38 -39
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +2 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Field/index.d.ts.map +1 -1
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +1 -1
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts +1 -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 +7 -2
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
- package/dist/components/FileViewer/image-renderer.js +22 -1
- package/dist/components/FileViewer/image-renderer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +5 -3
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/index.d.ts +2 -0
- package/dist/components/InlineEdit/index.d.ts.map +1 -0
- package/dist/components/InlineEdit/index.js +5 -0
- package/dist/components/InlineEdit/index.js.map +1 -0
- package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
- package/dist/components/InlineEdit/inline-edit.js +164 -0
- package/dist/components/InlineEdit/inline-edit.js.map +1 -0
- package/dist/components/Input/input.d.ts +6 -11
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +43 -13
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +2 -2
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +6 -5
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts +14 -2
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js +25 -3
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +3 -3
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +6 -5
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/pagination.js +1 -1
- package/dist/components/Pagination/pagination.js.map +1 -1
- package/dist/components/PeoplePicker/index.js +7 -1
- package/dist/components/PeoplePicker/index.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +23 -10
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +6 -3
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +19 -14
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/Popover/popover.d.ts.map +1 -1
- package/dist/components/Popover/popover.js +3 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +2 -2
- package/dist/components/ProfileCard/profile-card.js +3 -3
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +15 -9
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +6 -3
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/Select/select.d.ts +46 -5
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +109 -28
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +3 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +8 -1
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
- package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
- package/dist/components/SelectionControl/boolean-value.js +23 -0
- package/dist/components/SelectionControl/boolean-value.js.map +1 -0
- package/dist/components/SelectionControl/index.d.ts +1 -0
- package/dist/components/SelectionControl/index.d.ts.map +1 -1
- package/dist/components/SelectionControl/index.js +2 -0
- package/dist/components/SelectionControl/index.js.map +1 -1
- package/dist/components/Sheet/index.js +2 -1
- package/dist/components/Sheet/sheet.d.ts +7 -1
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js +5 -2
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +9 -4
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +8 -10
- 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.map +1 -1
- package/dist/components/Switch/switch.d.ts +6 -6
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -2
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +15 -1
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +2 -2
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +50 -42
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
- package/dist/components/TimePicker/time-columns.js +42 -38
- package/dist/components/TimePicker/time-columns.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -6
- 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 +7 -5
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +56 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +211 -12
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +115 -58
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -108
- package/dist/index.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.js +15 -0
- package/dist/tokens/categorical-color.js.map +1 -1
- package/dist/tokens/motion/motion.d.ts +7 -6
- package/dist/tokens/motion/motion.d.ts.map +1 -1
- package/dist/tokens/motion/motion.js +6 -6
- package/dist/tokens/motion/motion.js.map +1 -1
- package/dist/tokens/motion/overlay-motion.d.ts +19 -0
- package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
- package/dist/tokens/motion/overlay-motion.js +9 -0
- package/dist/tokens/motion/overlay-motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.js +5 -0
- package/dist/tokens/uiSize/icon-size.js.map +1 -0
- package/ds-canonical/fork/governance.lock +31 -19
- package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
- package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
- package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/fork/manifest.json +15 -0
- package/ds-canonical/fork/preamble.md +20 -18
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
- package/ds-canonical/hooks/README.md +1 -1
- package/ds-canonical/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
- package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
- package/ds-canonical/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
- package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
- package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
- package/ds-canonical/hooks/stop_self_audit.sh +31 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
- package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
- package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
- package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
- package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
- package/ds-canonical/references/build-ui-canonicals.md +2 -1
- package/ds-canonical/references/failure-class-registry.json +145 -0
- package/ds-canonical/references/governance-audit-coverage.md +33 -0
- package/ds-canonical/references/item-anatomy-recipe.md +2 -2
- package/ds-canonical/references/scenario-definition.md +6 -9
- package/ds-canonical/references/ssot-consultation.md +2 -2
- package/ds-canonical/references/ssot-index.md +5 -4
- package/ds-canonical/references/story-baseline-registry.json +8 -2
- package/ds-canonical/references/structural-token-retention.md +6 -9
- package/ds-canonical/rules/meta-patterns.md +8 -8
- package/ds-canonical/rules/self-verify.md +4 -3
- package/ds-canonical/rules/story-rules.md +2 -2
- package/ds-canonical/rules/ui-development.md +2 -2
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
- package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
- package/ds-canonical/skills/governance-health/SKILL.md +1 -1
- package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
- package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
- package/ds-canonical/skills/new-component/SKILL.md +5 -5
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
- package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
- package/ds-canonical/skills/story-writing/SKILL.md +3 -3
- package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
- package/ds-story-manifest.json +29 -20
- package/llms-full.txt +22 -1
- package/llms.txt +5 -4
- package/package.json +7 -3
- package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
- package/src/components/Accordion/accordion.stories.tsx +16 -1
- package/src/components/Alert/alert.principles.stories.tsx +1 -1
- package/src/components/Alert/alert.spec.md +8 -10
- package/src/components/Alert/alert.stories.tsx +28 -28
- package/src/components/Alert/alert.tsx +1 -1
- package/src/components/AppShell/_demo-helpers.tsx +6 -3
- package/src/components/AppShell/app-shell.spec.md +4 -4
- package/src/components/AppShell/app-shell.tsx +28 -2
- package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
- package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
- package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
- package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
- package/src/components/Avatar/avatar.spec.md +2 -2
- package/src/components/Avatar/avatar.stories.tsx +8 -6
- package/src/components/Avatar/avatar.tsx +13 -5
- package/src/components/Badge/badge.principles.stories.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -0
- package/src/components/Badge/badge.stories.tsx +4 -2
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
- package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.tsx +18 -3
- package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
- package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
- package/src/components/Calendar/calendar.spec.md +5 -4
- package/src/components/Calendar/calendar.stories.tsx +7 -4
- package/src/components/Calendar/calendar.tsx +26 -7
- package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
- package/src/components/Carousel/carousel.spec.md +2 -2
- package/src/components/Carousel/carousel.tsx +11 -3
- package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
- package/src/components/Chart/chart.principles.stories.tsx +1 -1
- package/src/components/Chart/chart.stories.tsx +2 -8
- package/src/components/Chart/chart.tsx +3 -0
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
- package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.spec.md +13 -26
- package/src/components/Checkbox/checkbox.stories.tsx +11 -8
- package/src/components/Checkbox/checkbox.tsx +18 -13
- package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
- package/src/components/Chip/chip.principles.stories.tsx +1 -1
- package/src/components/Chip/chip.spec.md +5 -4
- package/src/components/Chip/chip.tsx +5 -1
- package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
- package/src/components/CircularProgress/circular-progress.spec.md +3 -3
- package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
- package/src/components/Coachmark/coachmark.spec.md +5 -5
- package/src/components/Coachmark/coachmark.stories.tsx +3 -1
- package/src/components/Coachmark/coachmark.tsx +10 -3
- package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
- package/src/components/Combobox/combobox.tsx +53 -19
- package/src/components/Command/command.anatomy.stories.tsx +2 -2
- package/src/components/Command/command.principles.stories.tsx +1 -1
- package/src/components/Command/command.stories.tsx +42 -10
- package/src/components/DataTable/cell-registry.tsx +86 -63
- package/src/components/DataTable/column-types.ts +10 -1
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
- package/src/components/DataTable/data-table-filter-group.tsx +231 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +16 -430
- package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
- package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
- package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
- package/src/components/DataTable/data-table.spec.md +33 -13
- package/src/components/DataTable/data-table.stories.tsx +16 -17
- package/src/components/DataTable/data-table.tsx +107 -61
- package/src/components/DataTable/filter-operators.spec.md +3 -3
- package/src/components/DataTable/index.ts +3 -0
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
- package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DateGrid/date-grid.tsx +3 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
- package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
- package/src/components/DatePicker/date-picker.spec.md +3 -3
- package/src/components/DatePicker/date-picker.stories.tsx +4 -5
- package/src/components/DatePicker/date-picker.tsx +99 -45
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +3 -3
- package/src/components/DescriptionList/description-list.stories.tsx +7 -6
- package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
- package/src/components/Dialog/dialog.spec.md +9 -0
- package/src/components/Dialog/dialog.stories.tsx +66 -5
- package/src/components/Dialog/dialog.tsx +60 -25
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
- package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
- package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
- package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
- package/src/components/Empty/empty.spec.md +2 -2
- package/src/components/Field/field-context.ts +69 -5
- package/src/components/Field/field-controls.spec.md +62 -8
- package/src/components/Field/field-edit-keys.ts +66 -0
- package/src/components/Field/field-types.ts +58 -9
- package/src/components/Field/field-wrapper.tsx +50 -42
- package/src/components/Field/field.anatomy.stories.tsx +9 -6
- package/src/components/Field/field.spec.md +1 -1
- package/src/components/Field/field.stories.tsx +1 -1
- package/src/components/Field/field.tsx +2 -1
- package/src/components/Field/form-validation.spec.md +3 -3
- package/src/components/Field/index.ts +1 -0
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
- package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
- package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
- package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
- package/src/components/FileItem/file-item.spec.md +5 -8
- package/src/components/FileItem/file-item.stories.tsx +36 -25
- package/src/components/FileItem/file-item.tsx +8 -6
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
- package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
- package/src/components/FileUpload/file-upload.spec.md +1 -1
- package/src/components/FileUpload/file-upload.tsx +1 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
- package/src/components/FileViewer/file-viewer.spec.md +30 -12
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
- package/src/components/FileViewer/file-viewer.tsx +12 -4
- package/src/components/FileViewer/image-renderer.tsx +35 -7
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
- package/src/components/HoverCard/hover-card.spec.md +5 -5
- package/src/components/HoverCard/hover-card.stories.tsx +16 -16
- package/src/components/HoverCard/hover-card.tsx +5 -3
- package/src/components/InlineEdit/index.ts +5 -0
- package/src/components/InlineEdit/inline-edit.spec.md +149 -0
- package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
- package/src/components/InlineEdit/inline-edit.tsx +287 -0
- package/src/components/Input/input.anatomy.stories.tsx +8 -7
- package/src/components/Input/input.principles.stories.tsx +2 -12
- package/src/components/Input/input.spec.md +13 -18
- package/src/components/Input/input.tsx +69 -22
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.tsx +11 -10
- package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
- package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
- package/src/components/Menu/menu-item.spec.md +22 -15
- package/src/components/Menu/menu-item.stories.tsx +39 -11
- package/src/components/Menu/menu-item.tsx +38 -4
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.spec.md +16 -3
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
- package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
- package/src/components/NumberInput/number-input.spec.md +4 -4
- package/src/components/NumberInput/number-input.tsx +19 -12
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
- package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
- package/src/components/Pagination/pagination.spec.md +1 -1
- package/src/components/Pagination/pagination.stories.tsx +2 -6
- package/src/components/Pagination/pagination.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
- package/src/components/PeoplePicker/people-picker.spec.md +6 -6
- package/src/components/PeoplePicker/people-picker.tsx +56 -16
- package/src/components/PeoplePicker/person-display.tsx +32 -16
- package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
- package/src/components/Popover/popover.tsx +3 -1
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
- package/src/components/ProfileCard/profile-card.spec.md +3 -3
- package/src/components/ProfileCard/profile-card.tsx +6 -6
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
- package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
- package/src/components/RadioGroup/radio-group.tsx +41 -15
- package/src/components/Rating/rating.spec.md +11 -3
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +7 -3
- package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +17 -4
- package/src/components/Select/select.anatomy.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +29 -17
- package/src/components/Select/select.stories.tsx +33 -0
- package/src/components/Select/select.tsx +190 -36
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
- package/src/components/SelectMenu/select-menu.spec.md +15 -7
- package/src/components/SelectMenu/select-menu.tsx +16 -3
- package/src/components/SelectionControl/boolean-value.tsx +39 -0
- package/src/components/SelectionControl/index.ts +1 -0
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.spec.md +3 -3
- package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
- package/src/components/Separator/separator.spec.md +2 -2
- package/src/components/Separator/separator.stories.tsx +6 -27
- package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.spec.md +2 -2
- package/src/components/Sheet/sheet.tsx +9 -5
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
- package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
- package/src/components/Sidebar/sidebar.spec.md +13 -15
- package/src/components/Sidebar/sidebar.stories.tsx +8 -7
- package/src/components/Sidebar/sidebar.tsx +37 -25
- package/src/components/Skeleton/skeleton.stories.tsx +4 -11
- package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
- package/src/components/Slider/slider.principles.stories.tsx +2 -2
- package/src/components/Slider/slider.spec.md +5 -5
- package/src/components/Slider/slider.tsx +3 -1
- package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +1 -1
- package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
- package/src/components/Switch/switch.principles.stories.tsx +4 -4
- package/src/components/Switch/switch.spec.md +8 -8
- package/src/components/Switch/switch.stories.tsx +9 -24
- package/src/components/Switch/switch.tsx +17 -13
- package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
- package/src/components/Tabs/tabs.spec.md +1 -1
- package/src/components/Tabs/tabs.tsx +21 -1
- package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
- package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
- package/src/components/Textarea/textarea.spec.md +4 -4
- package/src/components/Textarea/textarea.tsx +72 -46
- package/src/components/TimePicker/time-columns.tsx +6 -2
- package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
- package/src/components/TimePicker/time-picker.spec.md +3 -3
- package/src/components/TimePicker/time-picker.tsx +16 -10
- package/src/components/Toast/toast.stories.tsx +7 -4
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
- package/src/components/Tooltip/tooltip.spec.md +1 -1
- package/src/components/Tooltip/tooltip.stories.tsx +4 -39
- package/src/components/Tooltip/tooltip.tsx +8 -6
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
- package/src/components/TreeView/tree-view.spec.md +42 -11
- package/src/components/TreeView/tree-view.stories.tsx +1 -0
- package/src/components/TreeView/tree-view.tsx +322 -17
- package/src/index.ts +588 -60
- package/src/patterns/action-bar/action-bar.spec.md +9 -0
- package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
- package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
- package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
- package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
- package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
- package/src/styles/tokens.css +3 -0
- package/src/tokens/README.md +1 -1
- package/src/tokens/color/color.spec.md +4 -4
- package/src/tokens/color/color.stories.tsx +3 -3
- package/src/tokens/density/density.stories.tsx +16 -3
- package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
- package/src/tokens/motion/motion.css +33 -21
- package/src/tokens/motion/motion.spec.md +32 -15
- package/src/tokens/motion/motion.stories.tsx +58 -5
- package/src/tokens/motion/motion.ts +7 -6
- package/src/tokens/motion/overlay-motion.ts +26 -0
- package/src/tokens/orphan-tokens.spec.md +4 -4
- package/src/tokens/token-system.spec.md +1 -0
- package/src/tokens/uiSize/uiSize.css +1 -1
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
- package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
- package/src/tokens/utility-registry.json +160 -23
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
-
import React from 'react'
|
|
3
2
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
4
3
|
import { AspectRatio } from './aspect-ratio'
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* AspectRatio 展示——固定長寬比容器,常用於圖片 / 截圖 / illustration 鎖比例。
|
|
8
|
-
* 展示範例對標世界級產品的真實情境(
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* 展示範例對標世界級產品的真實情境(Stripe product 卡、YouTube cinematic banner),
|
|
8
|
+
* consumer 包 <img className="w-full h-full object-cover" /> 是標準用法。
|
|
9
|
+
* 全比例對照矩陣由設計規格層 StandardRatios owns。設計規則詳見 `aspect-ratio.spec.md`。
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
const meta: Meta = {
|
|
@@ -17,37 +16,11 @@ const meta: Meta = {
|
|
|
17
16
|
export default meta
|
|
18
17
|
type Story = StoryObj
|
|
19
18
|
|
|
20
|
-
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
const Figure = ({
|
|
23
|
-
children, caption,
|
|
24
|
-
}: { children: React.ReactNode; caption: string }) => (
|
|
25
|
-
<figure className="flex flex-col gap-2">
|
|
26
|
-
{children}
|
|
27
|
-
<figcaption className="text-footnote text-fg-muted">{caption}</figcaption>
|
|
28
|
-
</figure>
|
|
29
|
-
)
|
|
30
|
-
|
|
31
19
|
// ── Stories ───────────────────────────────────────────────────────────────────
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<div className="max-w-[720px]">
|
|
37
|
-
<h3 className="text-body font-bold text-foreground mb-1">Airbnb listing hero</h3>
|
|
38
|
-
<p className="text-caption text-fg-muted mb-5 max-w-[600px] leading-relaxed">
|
|
39
|
-
寬螢幕影片、feature 截圖、listing cover 標配——16/9 是最主流的 web hero ratio(Vercel、Airbnb、Linear hero section)。
|
|
40
|
-
</p>
|
|
41
|
-
<AspectRatio ratio={16 / 9} className="bg-muted rounded-lg overflow-hidden">
|
|
42
|
-
<img
|
|
43
|
-
src="https://picsum.photos/seed/airbnb-hero/800/450"
|
|
44
|
-
alt="Beachfront cottage in Santorini"
|
|
45
|
-
className="w-full h-full object-cover"
|
|
46
|
-
/>
|
|
47
|
-
</AspectRatio>
|
|
48
|
-
</div>
|
|
49
|
-
),
|
|
50
|
-
}
|
|
20
|
+
// HeroBanner16x9 / SquareAvatar1x1 / CommonRatios retired 2026-07-14 per audit Dim 24(story 重複性):
|
|
21
|
+
// 比例是數值 prop 非 affordance,逐值 story 無獨立教學原則;全比例對照矩陣已由
|
|
22
|
+
// anatomy StandardRatios(aspect-ratio.anatomy.stories.tsx,5 ratio 含 21/9 / 3/4)owns。
|
|
23
|
+
// 展示層保留真實業務場景:ProductPhoto4x3(教 CLS 防坍塌)+ Ultrawide21x9(cinematic 寬幅情境)。
|
|
51
24
|
|
|
52
25
|
export const ProductPhoto4x3: Story = {
|
|
53
26
|
name: '4/3 產品照片 + 防版面跳動對照',
|
|
@@ -94,29 +67,6 @@ export const ProductPhoto4x3: Story = {
|
|
|
94
67
|
),
|
|
95
68
|
}
|
|
96
69
|
|
|
97
|
-
export const SquareAvatar1x1: Story = {
|
|
98
|
-
name: '1:1 社群方形貼文',
|
|
99
|
-
render: () => (
|
|
100
|
-
<div className="max-w-[600px]">
|
|
101
|
-
<h3 className="text-body font-bold text-foreground mb-1">Instagram-style 方形貼文</h3>
|
|
102
|
-
<p className="text-caption text-fg-muted mb-5 max-w-[600px] leading-relaxed">
|
|
103
|
-
方形貼文預覽、avatar、icon preview 標配——1/1 讓 feed grid 對齊一致。
|
|
104
|
-
</p>
|
|
105
|
-
<div className="grid grid-cols-3 gap-1">
|
|
106
|
-
{['coffee', 'mountain', 'city', 'sunset', 'plant', 'food'].map(seed => (
|
|
107
|
-
<AspectRatio key={seed} ratio={1} className="bg-muted overflow-hidden">
|
|
108
|
-
<img
|
|
109
|
-
src={`https://picsum.photos/seed/${seed}/400/400`}
|
|
110
|
-
alt={seed}
|
|
111
|
-
className="w-full h-full object-cover"
|
|
112
|
-
/>
|
|
113
|
-
</AspectRatio>
|
|
114
|
-
))}
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
),
|
|
118
|
-
}
|
|
119
|
-
|
|
120
70
|
export const Ultrawide21x9: Story = {
|
|
121
71
|
name: '21:9 影院橫幅',
|
|
122
72
|
render: () => (
|
|
@@ -136,35 +86,3 @@ export const Ultrawide21x9: Story = {
|
|
|
136
86
|
),
|
|
137
87
|
}
|
|
138
88
|
|
|
139
|
-
export const CommonRatios: Story = {
|
|
140
|
-
name: '常用 比例 一覽',
|
|
141
|
-
render: () => (
|
|
142
|
-
<div className="flex flex-col gap-8 max-w-[720px]">
|
|
143
|
-
<p className="text-caption text-fg-muted max-w-[600px] leading-relaxed">
|
|
144
|
-
DS 標準 ratio 視覺對照——選擇對應情境的數值。
|
|
145
|
-
</p>
|
|
146
|
-
<div className="grid grid-cols-2 gap-4">
|
|
147
|
-
<Figure caption="16/9 — 寬螢幕 hero / 影片">
|
|
148
|
-
<AspectRatio ratio={16 / 9} className="bg-muted rounded-md overflow-hidden">
|
|
149
|
-
<img src="https://picsum.photos/seed/r16-9/640/360" alt="" className="w-full h-full object-cover" />
|
|
150
|
-
</AspectRatio>
|
|
151
|
-
</Figure>
|
|
152
|
-
<Figure caption="4/3 — 產品照 / 截圖">
|
|
153
|
-
<AspectRatio ratio={4 / 3} className="bg-muted rounded-md overflow-hidden">
|
|
154
|
-
<img src="https://picsum.photos/seed/r4-3/600/450" alt="" className="w-full h-full object-cover" />
|
|
155
|
-
</AspectRatio>
|
|
156
|
-
</Figure>
|
|
157
|
-
<Figure caption="1/1 — 方形 / avatar">
|
|
158
|
-
<AspectRatio ratio={1} className="bg-muted rounded-md overflow-hidden">
|
|
159
|
-
<img src="https://picsum.photos/seed/r1-1/400/400" alt="" className="w-full h-full object-cover" />
|
|
160
|
-
</AspectRatio>
|
|
161
|
-
</Figure>
|
|
162
|
-
<Figure caption="3/4 — 直式 portrait">
|
|
163
|
-
<AspectRatio ratio={3 / 4} className="bg-muted rounded-md overflow-hidden">
|
|
164
|
-
<img src="https://picsum.photos/seed/r3-4/450/600" alt="" className="w-full h-full object-cover" />
|
|
165
|
-
</AspectRatio>
|
|
166
|
-
</Figure>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
),
|
|
170
|
-
}
|
|
@@ -164,7 +164,8 @@ export const Overview = {
|
|
|
164
164
|
</div>
|
|
165
165
|
<div className="flex gap-8">
|
|
166
166
|
<div className="flex flex-col items-center gap-2">
|
|
167
|
-
|
|
167
|
+
{/* circle = 人物 → 真實人像(2026-07-08 demo 人像真實化);square = 實體 → icon */}
|
|
168
|
+
<Avatar size={40} src="https://i.pravatar.cc/80?u=alice-chen" alt="Alice" shape="circle" />
|
|
168
169
|
<span className="text-[11px] font-mono text-fg-muted">circle(預設)</span>
|
|
169
170
|
<span className="text-[10px] text-fg-muted">rounded-full</span>
|
|
170
171
|
</div>
|
|
@@ -644,6 +645,9 @@ export const StateBehavior = {
|
|
|
644
645
|
<H3>Fallback chain(src 失敗 → icon → alt → User)</H3>
|
|
645
646
|
<Desc>Avatar 不是互動元件,沒有 hover / focus / active。實際「狀態」是內容降級——src 載入失敗時自動依優先順序往下回退,確保永遠不會出現破圖。</Desc>
|
|
646
647
|
</div>
|
|
648
|
+
{/* 刻意示範 fallback chain:失敗 URL / 無 src 各列**必須**維持原樣(降級行為規格,
|
|
649
|
+
2026-07-08 demo 人像真實化 sweep 豁免保留;ColorMatrix / SizeMatrix 的 Text 列同理 —
|
|
650
|
+
color / text-mode 軸只在無圖時可見) */}
|
|
647
651
|
<div className="overflow-x-auto">
|
|
648
652
|
<table className="border-collapse text-caption">
|
|
649
653
|
<thead><tr><Th>來源</Th><Th>渲染</Th><Th>條件</Th></tr></thead>
|
|
@@ -679,7 +683,7 @@ export const StateBehavior = {
|
|
|
679
683
|
<div className="flex items-center gap-6">
|
|
680
684
|
{(['online', 'away', 'busy', 'offline'] as const).map(s => (
|
|
681
685
|
<div key={s} className="flex flex-col items-center gap-2">
|
|
682
|
-
<Avatar size={40}
|
|
686
|
+
<Avatar size={40} src="https://i.pravatar.cc/80?u=ada-chen" alt="Ada" status={s} />
|
|
683
687
|
<span className="text-[11px] font-mono text-fg-muted">{s}</span>
|
|
684
688
|
</div>
|
|
685
689
|
))}
|
|
@@ -695,7 +699,7 @@ export const Accessibility = {
|
|
|
695
699
|
render: () => (
|
|
696
700
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
697
701
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
698
|
-
<p className="whitespace-pre-line">{"・alt 必傳:即使有圖片,alt 同時是「圖片載入失敗時的文字 fallback」與「螢幕報讀時的身份說明」。人員頭像的 alt 建議含姓名與在線狀態(例:「陳冠霖(在線)」),組織 / 專案頭像用品牌或專案名;極少數純裝飾用途才用空字串。\n\n・沒有 alt 時的降級:圖片模式會自動降級為首字或 icon,不會留下沒有任何報讀內容的空頭像。\n\n・在線狀態點不另發報讀:右下角的狀態小點不會被螢幕報讀單獨朗讀,在線狀態整合進頭像本身的 alt 文字。這樣一長串成員名單就不會同時朗讀一堆「在線 / 離線」造成讀屏洪水。\n\n・hover 名片可用鍵盤抵達:當頭像帶有 hoverCard 時,頭像本身會變成可用 Tab
|
|
702
|
+
<p className="whitespace-pre-line">{"・alt 必傳:即使有圖片,alt 同時是「圖片載入失敗時的文字 fallback」與「螢幕報讀時的身份說明」。人員頭像的 alt 建議含姓名與在線狀態(例:「陳冠霖(在線)」),組織 / 專案頭像用品牌或專案名;極少數純裝飾用途才用空字串。\n\n・沒有 alt 時的降級:圖片模式會自動降級為首字或 icon,不會留下沒有任何報讀內容的空頭像。\n\n・在線狀態點不另發報讀:右下角的狀態小點不會被螢幕報讀單獨朗讀,在線狀態整合進頭像本身的 alt 文字。這樣一長串成員名單就不會同時朗讀一堆「在線 / 離線」造成讀屏洪水。\n\n・hover 名片可用鍵盤抵達:當頭像帶有 hoverCard 時,頭像本身會變成可用 Tab 聚焦的圖像(role=img)並顯示聚焦框,鍵盤使用者也能打開名片浮層(頭像刻意不宣告成按鈕 / aria-haspopup,對齊 Radix / GitHub hover card 的零 popup ARIA 慣例)。"}</p>
|
|
699
703
|
</div>
|
|
700
704
|
),
|
|
701
705
|
}
|
|
@@ -86,14 +86,15 @@ export const UsageGuidance: Story = {
|
|
|
86
86
|
note="判斷法:「這代表『誰』還是『做什麼』?」誰 / 什麼實體 → Avatar;做什麼 / 某個概念 → Icon"
|
|
87
87
|
>
|
|
88
88
|
<div className="border border-divider rounded-lg bg-surface py-1">
|
|
89
|
-
|
|
89
|
+
{/* 人員 → 真實人像;團隊 / 組織 → 首字 + 色彩(非人臉,letter mark 是 Slack workspace idiom)*/}
|
|
90
|
+
<MenuItem avatar={{ src: 'https://i.pravatar.cc/48?u=ada-chen', alt: 'Ada Chen' }}>Ada Chen 的留言</MenuItem>
|
|
90
91
|
<MenuItem avatar={{ alt: 'Engineering Team', color: 'blue' }}>Engineering Team 專案</MenuItem>
|
|
91
92
|
</div>
|
|
92
93
|
{/* 視覺圖例(legend),非 list item */}
|
|
93
94
|
<div className="flex items-center gap-3 flex-wrap mt-2">
|
|
94
95
|
{/* @anatomy-exempt-next */}
|
|
95
96
|
<div className="flex items-center gap-2">
|
|
96
|
-
<Avatar alt="Ada Chen" size={24} />
|
|
97
|
+
<Avatar src="https://i.pravatar.cc/48?u=ada-chen" alt="Ada Chen" size={24} />
|
|
97
98
|
<span className="text-footnote text-fg-muted">人員</span>
|
|
98
99
|
</div>
|
|
99
100
|
<div className="flex items-center gap-2">
|
|
@@ -124,6 +125,8 @@ export const FallbackRule: Story = {
|
|
|
124
125
|
title="有 src → 顯示圖片;沒有 src / 圖片載入失敗 → 顯示 initials"
|
|
125
126
|
note="Fallback 用 `alt` 取首字母(一律取第一個字元並轉大寫,不分中英)。背景色由 `color` prop 決定"
|
|
126
127
|
>
|
|
128
|
+
{/* 刻意示範 initials fallback:後三顆**必須**無 src(fallback 順序示範,
|
|
129
|
+
2026-07-08 demo 人像真實化 sweep 豁免保留) */}
|
|
127
130
|
<div className="flex items-center gap-3">
|
|
128
131
|
<Avatar alt="Ada Chen" size={40} src="https://i.pravatar.cc/80?img=1" />
|
|
129
132
|
<Avatar alt="Ada Chen" size={40} />
|
|
@@ -145,10 +148,10 @@ export const WithBadgeOverlayRule: Story = {
|
|
|
145
148
|
note="用 Avatar 的 `status` prop(不是手刻 `<Badge dot>`)—— 顏色走 presence semantic token(`--status-online` 等,獨立於 success / error / warning),位置固定 avatar 右下角,尺寸程式化 28%"
|
|
146
149
|
>
|
|
147
150
|
<div className="flex items-center gap-4">
|
|
148
|
-
<Avatar alt="Ada" size={40} status="online" />
|
|
149
|
-
<Avatar alt="Alex" size={40} status="busy" />
|
|
150
|
-
<Avatar alt="Ben" size={40} status="away" />
|
|
151
|
-
<Avatar alt="Bella" size={40} status="offline" />
|
|
151
|
+
<Avatar src="https://i.pravatar.cc/80?u=ada-chen" alt="Ada" size={40} status="online" />
|
|
152
|
+
<Avatar src="https://i.pravatar.cc/80?u=alex-wang" alt="Alex" size={40} status="busy" />
|
|
153
|
+
<Avatar src="https://i.pravatar.cc/80?u=ben-liu" alt="Ben" size={40} status="away" />
|
|
154
|
+
<Avatar src="https://i.pravatar.cc/80?u=bella-wu" alt="Bella" size={40} status="offline" />
|
|
152
155
|
</div>
|
|
153
156
|
<Label>↑ online / busy / away / offline ── 狀態點本身不另發語音標籤,在線狀態整合進頭像的 alt 文字(例 alt="Ada(在線)"),避免一長串成員名單同時朗讀造成讀屏洪水</Label>
|
|
154
157
|
</Rule>
|
|
@@ -158,9 +161,9 @@ export const WithBadgeOverlayRule: Story = {
|
|
|
158
161
|
note="用 Avatar 的 `badgeCount` prop(不是手刻 `<Badge count>`)—— 內部消費 DS Badge critical variant + surface ring,max=99 自動處理 99+"
|
|
159
162
|
>
|
|
160
163
|
<div className="flex items-center gap-4">
|
|
161
|
-
<Avatar alt="Ada" size={40} badgeCount={3} />
|
|
162
|
-
<Avatar alt="Alex" size={40} badgeCount={12} />
|
|
163
|
-
<Avatar alt="Ben" size={40} badgeCount={128} />
|
|
164
|
+
<Avatar src="https://i.pravatar.cc/80?u=ada-chen" alt="Ada" size={40} badgeCount={3} />
|
|
165
|
+
<Avatar src="https://i.pravatar.cc/80?u=alex-wang" alt="Alex" size={40} badgeCount={12} />
|
|
166
|
+
<Avatar src="https://i.pravatar.cc/80?u=ben-liu" alt="Ben" size={40} badgeCount={128} />
|
|
164
167
|
</div>
|
|
165
168
|
<Label>↑ count 3 / 12 / 128(超過 99 顯示 "99+")</Label>
|
|
166
169
|
</Rule>
|
|
@@ -170,9 +173,9 @@ export const WithBadgeOverlayRule: Story = {
|
|
|
170
173
|
note="兩者是**不同角、不同語義**的 slot(presence=這個人的線上狀態,右下;count=此對話未讀量,右上),對齊 `badge.spec.md`「Avatar 可疊 status + count」canonical + Slack / Teams / iMessage / LINE 標配。**signal crowding 只禁「同一角疊兩個同類 indicator」**(如右上同時 count + dot),不禁不同角不同語義的兩個訊號"
|
|
171
174
|
>
|
|
172
175
|
<div className="flex items-center gap-4">
|
|
173
|
-
<Avatar alt="Ada" size={40} status="online" badgeCount={3} />
|
|
174
|
-
<Avatar alt="Alex" size={40} status="busy" />
|
|
175
|
-
<Avatar alt="Ben" size={40} badgeCount={12} />
|
|
176
|
+
<Avatar src="https://i.pravatar.cc/80?u=ada-chen" alt="Ada" size={40} status="online" badgeCount={3} />
|
|
177
|
+
<Avatar src="https://i.pravatar.cc/80?u=alex-wang" alt="Alex" size={40} status="busy" />
|
|
178
|
+
<Avatar src="https://i.pravatar.cc/80?u=ben-liu" alt="Ben" size={40} badgeCount={12} />
|
|
176
179
|
</div>
|
|
177
180
|
<Label>↑ Ada 同時 presence(右下)+ count(右上)並存;Alex 只 presence;Ben 只 count</Label>
|
|
178
181
|
</Rule>
|
|
@@ -189,13 +192,14 @@ export const HoverCardIntegrationRule: Story = {
|
|
|
189
192
|
note="ProfileCard 是 DS 設計準則 人員 hover 內容元件(avatar + name + subtitle + actions + status + fields 統一佈局)。Avatar 的 hoverCard prop 接 ProfileCard,不可手刻 JSX — 手刻會漂移出 ProfileCard 對齊 / 間距 / status token 規則"
|
|
190
193
|
>
|
|
191
194
|
<Avatar
|
|
195
|
+
src="https://i.pravatar.cc/80?u=ada-chen"
|
|
192
196
|
alt="Ada Chen"
|
|
193
197
|
size={40}
|
|
194
198
|
hoverCard={
|
|
195
199
|
<ProfileCard
|
|
196
200
|
name="Ada Chen"
|
|
197
201
|
subtitle="Design Engineer · 台北"
|
|
198
|
-
avatar={{ alt: 'Ada Chen' }}
|
|
202
|
+
avatar={{ src: 'https://i.pravatar.cc/80?u=ada-chen', alt: 'Ada Chen' }}
|
|
199
203
|
status="online"
|
|
200
204
|
statusMessage="Out of Office: Back on Monday!"
|
|
201
205
|
actions={<ProfileCardDefaultActions />}
|
|
@@ -216,7 +220,7 @@ export const HoverCardIntegrationRule: Story = {
|
|
|
216
220
|
>
|
|
217
221
|
<div className="flex items-start gap-8">
|
|
218
222
|
<div className="flex flex-col gap-2">
|
|
219
|
-
<Avatar alt="Alex Wang" size={48}
|
|
223
|
+
<Avatar src="https://i.pravatar.cc/96?u=alex-wang" alt="Alex Wang" size={48}
|
|
220
224
|
hoverCard={
|
|
221
225
|
<ProfileCard name="Alex Wang" subtitle="Engineer · 已離職" onViewMore={() => {}} />
|
|
222
226
|
}
|
|
@@ -230,7 +234,7 @@ export const HoverCardIntegrationRule: Story = {
|
|
|
230
234
|
<div className="border border-divider rounded-lg bg-surface py-1 w-full">
|
|
231
235
|
<MenuItem
|
|
232
236
|
size="lg"
|
|
233
|
-
avatar={{ alt: 'Alex Wang' }}
|
|
237
|
+
avatar={{ src: 'https://i.pravatar.cc/64?u=alex-wang', alt: 'Alex Wang' }}
|
|
234
238
|
description={<span className="text-error">已離職</span>}
|
|
235
239
|
>
|
|
236
240
|
Alex Wang
|
|
@@ -163,7 +163,7 @@ Avatar 堆疊的「+N」hover 也出 **HoverCard**(不是 Tooltip)——列
|
|
|
163
163
|
| `circle`(預設) | 人物(照片、姓名) |
|
|
164
164
|
| `square` | 實體(專案、組織、App、品牌) |
|
|
165
165
|
|
|
166
|
-
**判斷標準:「這個 avatar 代表一個人,還是一個東西?」** 圓角由 `.tsx` inline style 決定(無 cva
|
|
166
|
+
**判斷標準:「這個 avatar 代表一個人,還是一個東西?」** 圓角由 `.tsx` inline style 決定(無 cva),消費 radius token:`circle` = `var(--radius-full)`、`square` = `var(--radius-md)`(avatar.tsx `radius` ternary;不硬寫裸值,token 調整時自動跟隨)。
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -244,7 +244,7 @@ Avatar `badgeCount` 內部消費 DS `<Badge variant="critical" max={99}>`,加上
|
|
|
244
244
|
- **無 `alt` 時 fallback**:image 模式自動降級 initials / icon;一律不靜默渲染無 SR 標的元素。
|
|
245
245
|
- **Status dot SR 處理**:status dot 內部 span `aria-hidden`(presence 訊號整合進 parent `alt`),避免 `role="status"` live region 在 member list 造成 SR 洪水(詳「Status dot a11y」段)。
|
|
246
246
|
- **`badgeCount` 語意**:內部消費 `<Badge variant="critical">`,由 Avatar 傳入 `aria-label="N unread"` 提供計數語義(Badge 本身只有 `role="status"`,不自產 aria-label);`badgeCount <= 0` 不渲染避免空 announce。
|
|
247
|
-
- **HoverCard 整合**:Avatar 帶 `hoverCard` prop 時自動 `tabIndex=0` + `role="img"` + `aria-label`(取 `alt`)+ `focus-visible:ring-2`,確保 keyboard user 能 Tab 進入觸發 ProfileCard popover;**不掛 `role="button"` / `aria-haspopup`**(2026-07-06 拆除;role="img" 為 2026-07-07 axe 補修,詳「Keyboard 可達 canonical」段)。
|
|
247
|
+
- **HoverCard 整合**:Avatar 帶 `hoverCard` prop 時自動 `tabIndex=0` + `role="img"` + `aria-label`(取 `alt`;**與 `badgeCount` 並用時 count 併入同一 aria-label** — `role="img"` 使子孫 presentational、內層 Badge 計數語義被壓平,故外層 label = `${alt}, ${badgeAriaLabel ?? 'N unread'}`,對齊 Slack 單一 accessible name 做法,2026-07-14 補修)+ `focus-visible:ring-2`,確保 keyboard user 能 Tab 進入觸發 ProfileCard popover;**不掛 `role="button"` / `aria-haspopup`**(2026-07-06 拆除;role="img" 為 2026-07-07 axe 補修,詳「Keyboard 可達 canonical」段)。
|
|
248
248
|
- **Image alt 語意**:meaningful image(person photo / brand logo)用實質 `alt`;decorative-only(極少)走 `alt=""`,但 Avatar 本質是身份識別,decorative 用法應改用 Icon 元件。
|
|
249
249
|
|
|
250
250
|
---
|
|
@@ -24,6 +24,8 @@ export const Modes = {
|
|
|
24
24
|
</p>
|
|
25
25
|
</div>
|
|
26
26
|
<div className="flex items-center gap-6">
|
|
27
|
+
{/* 刻意示範內容模式優先序:Text fallback / 預設 User icon 兩項**必須**無 src(fallback 行為
|
|
28
|
+
示範 story,2026-07-08 demo 人像真實化 sweep 豁免保留) */}
|
|
27
29
|
{[
|
|
28
30
|
{ label: 'Image', el: <Avatar size={40} src="https://i.pravatar.cc/80?u=a" alt="Alice" /> },
|
|
29
31
|
{ label: 'Icon', el: <Avatar size={40} icon={Building2} color="blue" /> },
|
|
@@ -95,13 +97,13 @@ export const InContext = {
|
|
|
95
97
|
<div className="flex flex-col gap-2">
|
|
96
98
|
<span className="text-caption font-medium text-fg-secondary">無 description(inline)</span>
|
|
97
99
|
<div className="w-[280px] border border-divider rounded-lg py-1 bg-surface">
|
|
98
|
-
<MenuItem avatar={{ src: "https://i.pravatar.cc/48?u=
|
|
100
|
+
<MenuItem avatar={{ src: "https://i.pravatar.cc/48?u=alice-chen", alt: "Alice" }}>
|
|
99
101
|
Alice Chen
|
|
100
102
|
</MenuItem>
|
|
101
|
-
<MenuItem avatar={{ alt: "Bob", color: "blue" }}>
|
|
103
|
+
<MenuItem avatar={{ src: "https://i.pravatar.cc/48?u=bob-wang", alt: "Bob", color: "blue" }}>
|
|
102
104
|
Bob Wang
|
|
103
105
|
</MenuItem>
|
|
104
|
-
<MenuItem avatar={{ alt: "Carol", color: "purple" }}>
|
|
106
|
+
<MenuItem avatar={{ src: "https://i.pravatar.cc/48?u=carol-lee", alt: "Carol", color: "purple" }}>
|
|
105
107
|
Carol Lee
|
|
106
108
|
</MenuItem>
|
|
107
109
|
</div>
|
|
@@ -110,19 +112,19 @@ export const InContext = {
|
|
|
110
112
|
<span className="text-caption font-medium text-fg-secondary">有 description(block)</span>
|
|
111
113
|
<div className="w-[320px] border border-divider rounded-lg py-1 bg-surface">
|
|
112
114
|
<MenuItem
|
|
113
|
-
avatar={{ src: "https://i.pravatar.cc/64?u=
|
|
115
|
+
avatar={{ src: "https://i.pravatar.cc/64?u=alice-chen", alt: "Alice" }}
|
|
114
116
|
description="前端工程師"
|
|
115
117
|
>
|
|
116
118
|
Alice Chen
|
|
117
119
|
</MenuItem>
|
|
118
120
|
<MenuItem
|
|
119
|
-
avatar={{ alt: "Carol", color: "magenta" }}
|
|
121
|
+
avatar={{ src: "https://i.pravatar.cc/64?u=carol-lee", alt: "Carol", color: "magenta" }}
|
|
120
122
|
description="產品設計師"
|
|
121
123
|
>
|
|
122
124
|
Carol Lee
|
|
123
125
|
</MenuItem>
|
|
124
126
|
<MenuItem
|
|
125
|
-
avatar={{ alt: "Dave", color: "turquoise" }}
|
|
127
|
+
avatar={{ src: "https://i.pravatar.cc/64?u=dave-lin", alt: "Dave", color: "turquoise" }}
|
|
126
128
|
description="跨部門協作專案"
|
|
127
129
|
>
|
|
128
130
|
Dave Lin
|
|
@@ -5,7 +5,7 @@ import type { LucideIcon } from 'lucide-react'
|
|
|
5
5
|
import { cn } from '@/lib/utils'
|
|
6
6
|
import { CAT_SUBTLE_TOKENS, CAT_SOLID_TOKENS, type CategoricalColor } from '@/design-system/tokens/categorical-color'
|
|
7
7
|
import { HoverCard, HoverCardTrigger, HoverCardContent } from '@/design-system/components/HoverCard/hover-card'
|
|
8
|
-
import {
|
|
8
|
+
import { MOTION_DELAY_RICH_MS, MOTION_DELAY_CLOSE_MS } from '@/design-system/tokens/motion/motion'
|
|
9
9
|
import { Badge } from '@/design-system/components/Badge/badge'
|
|
10
10
|
import { useResolvedFieldDisabled, useTableIsScrolling } from '@/design-system/components/Field/field-context'
|
|
11
11
|
|
|
@@ -174,7 +174,10 @@ const AvatarInner = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
|
174
174
|
const fontSizePx = Math.round(numSize * 0.5)
|
|
175
175
|
const variantKey: VariantKey = solid ? 'solid' : 'subtle'
|
|
176
176
|
const colors = COLOR_MAP[variantKey]?.[color] ?? COLOR_MAP.subtle.neutral
|
|
177
|
-
|
|
177
|
+
// 2026-07-14 dim-20 修:inline style 不能用 rounded-* class,但可消費 radius token
|
|
178
|
+
// (radius.spec.md:18 canonical「所有 4px 圓角一律用 rounded-md」+ :86 禁硬寫值;
|
|
179
|
+
// token 改值 Avatar 跟隨 — M17 SSOT 傳播)。
|
|
180
|
+
const radius = shape === 'circle' ? 'var(--radius-full)' : 'var(--radius-md)'
|
|
178
181
|
|
|
179
182
|
// 決定內容
|
|
180
183
|
const showImage = src && !imgError
|
|
@@ -249,14 +252,19 @@ const AvatarInner = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
|
249
252
|
// 是 ARIA 禁用組合(axe aria-prohibited-attr,serious;2026-07-06 拆 role="button" 後裸露)。
|
|
250
253
|
// Avatar 語義本質 = 身份圖像 → `role="img"` 讓 aria-label 合法、子孫自動 presentational、
|
|
251
254
|
// 且不對 AT 承諾任何互動行為 — 與「拆假承諾」拍板意圖一致(emoji span / MUI Avatar img alt 同款語義)。
|
|
255
|
+
// a11y:role="img" 讓子孫 presentational → 內層 Badge 的 count 語義被壓平,SR 讀不到。
|
|
256
|
+
// 解:badgeCount 併入外層 aria-label(對齊 Slack「單一 accessible name 含未讀數」做法)。
|
|
252
257
|
const focusableProps = hoverCard
|
|
253
258
|
? {
|
|
254
259
|
tabIndex: 0,
|
|
255
260
|
role: 'img',
|
|
256
|
-
'aria-label':
|
|
261
|
+
'aria-label':
|
|
262
|
+
typeof badgeCount === 'number' && badgeCount > 0
|
|
263
|
+
? `${alt ?? 'View profile'}, ${badgeAriaLabel ?? `${badgeCount} unread`}`
|
|
264
|
+
: (alt ?? 'View profile'),
|
|
257
265
|
}
|
|
258
266
|
: {}
|
|
259
|
-
// 2026-05-31:focus ring 圓角跟隨 shape(circle→rounded-full / square→rounded-md,對齊 body 的 `radius` 變數
|
|
267
|
+
// 2026-05-31:focus ring 圓角跟隨 shape(circle→rounded-full / square→rounded-md,對齊 body 的 `radius` 變數 var(--radius-full)/var(--radius-md)),
|
|
260
268
|
// 原寫死 rounded-full 會讓方形 avatar(實體)配 hoverCard 時出現圓形 ring。hoverCard 為通用行為(任意內容),
|
|
261
269
|
// 方形 avatar 合法可配(內容非 ProfileCard 而已),故 ring 必跟形狀。
|
|
262
270
|
const focusableClass = hoverCard
|
|
@@ -312,7 +320,7 @@ const AvatarInner = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
|
312
320
|
if (!hoverCard || isTableScrolling) return baseEl
|
|
313
321
|
|
|
314
322
|
return (
|
|
315
|
-
<HoverCard openDelay={
|
|
323
|
+
<HoverCard openDelay={MOTION_DELAY_RICH_MS} closeDelay={MOTION_DELAY_CLOSE_MS}>
|
|
316
324
|
<HoverCardTrigger asChild>
|
|
317
325
|
{baseEl}
|
|
318
326
|
</HoverCardTrigger>
|
|
@@ -85,7 +85,7 @@ export const UsageGuidance: Story = {
|
|
|
85
85
|
size="sm"
|
|
86
86
|
iconOnly
|
|
87
87
|
startIcon={MessageSquare}
|
|
88
|
-
aria-label="訊息 (150
|
|
88
|
+
aria-label="訊息 (150 則)"
|
|
89
89
|
overlayBadge={<Badge count={150} max={99} variant="critical" />}
|
|
90
90
|
/>
|
|
91
91
|
<Label>3 vs 42 vs 99+ 觸發不同 urgency 感</Label>
|
|
@@ -189,6 +189,8 @@ Badge count 模式的數字使用 `text-[10px]`(10px,與 typography 系統最
|
|
|
189
189
|
|
|
190
190
|
**實作**:固定高度小於 Field 元件(保持輔助層級);個位數時為正圓,多位數時變膠囊——由 count 長度自動決定形狀。具體 token / class 見 `.tsx` cva。
|
|
191
191
|
|
|
192
|
+
**空值 / 零值**:`count` 不傳(`undefined`/`null`)→ 整顆不渲染(badge.tsx `count == null → return null`);`count={0}` → 照實渲染「0」。0 = 無訊號(多數通知場景)→ consumer 在 0 時不傳 count;0 有意義(報表計數)才傳。本 DS 不做 `showZero` 開關(Ant [ant.design/components/badge](https://ant.design/components/badge) / MUI [mui.com/material-ui/api/badge](https://mui.com/material-ui/api/badge/) 皆 `showZero` 預設 false = 零值預設隱藏;本 DS 以「不傳 count」表達同語意,零值語意由 consumer 資料層決定,元件不猜)。
|
|
193
|
+
|
|
192
194
|
### Dot — 存在性指示
|
|
193
195
|
|
|
194
196
|
**何時用**:「有東西」本身就是訊號,具體數量不重要或無意義。
|
|
@@ -48,8 +48,10 @@ export const Dot: Story = {
|
|
|
48
48
|
name: '圓點模式',
|
|
49
49
|
render: () => (
|
|
50
50
|
<div className="flex items-center gap-4">
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
{/* dot 無文字 → 必帶 aria-label(badge.spec.md 禁止事項:「dot 模式不帶 aria-label——
|
|
52
|
+
無文字的 dot 對 screen reader 完全不存在」) */}
|
|
53
|
+
<Badge dot variant="critical" aria-label="有緊急待處理事項" />
|
|
54
|
+
<Badge dot variant="high" aria-label="有新通知" />
|
|
53
55
|
<span className="text-caption text-fg-muted">6×6px attention 點 —— 只 critical / high(單一注意點,不分 medium/low)</span>
|
|
54
56
|
</div>
|
|
55
57
|
),
|
|
@@ -274,11 +274,13 @@ export const LongPathRule: Story = {
|
|
|
274
274
|
|
|
275
275
|
<Rule
|
|
276
276
|
title="❌ 不折疊、讓長路徑橫向撐破版面"
|
|
277
|
-
note="
|
|
277
|
+
note="Breadcrumb 單行不換行(flex-nowrap),窄容器或 mobile 上完整路徑會溢出邊界、被裁切或逼出橫向捲動,體驗比中段折疊還糟。折疊是主動的資訊階層處理"
|
|
278
278
|
>
|
|
279
|
-
|
|
279
|
+
{/* maxItems={99} 停用 auto-collapse:負例要示範「不折疊」時六層真的撐破窄容器。
|
|
280
|
+
若用預設 maxItems=4,compositionalContent 會把中段折成 ⋯,反而變成正例 → demo 失效。 */}
|
|
281
|
+
<div className="max-w-sm border border-border rounded-md p-3 overflow-x-auto">
|
|
280
282
|
<Breadcrumb>
|
|
281
|
-
<BreadcrumbList>
|
|
283
|
+
<BreadcrumbList maxItems={99}>
|
|
282
284
|
<BreadcrumbItem><BreadcrumbLink href="#">組織</BreadcrumbLink></BreadcrumbItem>
|
|
283
285
|
<BreadcrumbSeparator />
|
|
284
286
|
<BreadcrumbItem><BreadcrumbLink href="#">部門</BreadcrumbLink></BreadcrumbItem>
|
|
@@ -293,7 +295,7 @@ export const LongPathRule: Story = {
|
|
|
293
295
|
</BreadcrumbList>
|
|
294
296
|
</Breadcrumb>
|
|
295
297
|
</div>
|
|
296
|
-
<Label warn>↑
|
|
298
|
+
<Label warn>↑ 窄容器塞不下六層,單行溢出邊界(需橫向捲動才看得完),不如折疊中段</Label>
|
|
297
299
|
</Rule>
|
|
298
300
|
</div>
|
|
299
301
|
),
|
|
@@ -56,12 +56,13 @@ export const InteractiveEllipsis: Story = {
|
|
|
56
56
|
name: '可互動省略',
|
|
57
57
|
render: () => (
|
|
58
58
|
<div className="flex flex-col gap-4">
|
|
59
|
+
{/* 內部實作(對 consumer 不可見):BreadcrumbEllipsis 永遠 render <button> + DropdownMenuTrigger
|
|
60
|
+
asChild 注入 dropdown 行為;hover 走 neutral(fg-muted → foreground + neutral hover bg,消費
|
|
61
|
+
ItemInlineActionButton),刻意與 BreadcrumbLink 的 primary-hover 語言區隔。 */}
|
|
59
62
|
<div className="text-caption text-fg-muted max-w-xl">
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
+ neutral hover bg,消費 ItemInlineActionButton),與 BreadcrumbLink 的
|
|
64
|
-
primary-hover 區隔。對齊 Material / Atlassian / Ant Design 作法。
|
|
63
|
+
點 <code>⋯</code> 會開選單,列出被折疊起來的中間層級。滑鼠移上去時 <code>⋯</code> 用中性灰的高亮
|
|
64
|
+
(和一般連結的主色高亮刻意分開,讓「展開選單」和「跳到某一層」兩種動作一眼可辨),對齊 Material /
|
|
65
|
+
Atlassian / Ant Design 的做法。
|
|
65
66
|
</div>
|
|
66
67
|
<Breadcrumb>
|
|
67
68
|
<BreadcrumbList>
|
|
@@ -127,7 +127,8 @@ const BREADCRUMB_TEXT_CLASS: Record<BreadcrumbSize, string> = {
|
|
|
127
127
|
lg: 'text-body-lg',
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
// Separator /
|
|
130
|
+
// Separator chevron + BreadcrumbLink/Item start icon 尺寸 — 對齊 uiSize.spec.md「Icon Size Tier」(field-height-sm/md→16,lg→20)。
|
|
131
|
+
// 注意:BreadcrumbEllipsis 不消費此常數,固定 md(16px icon,見 BreadcrumbEllipsis 定義),size='lg' 時不隨 chevron 放大到 20
|
|
131
132
|
// 2026-05-18 改 per user 拍板「A 先改 16/16/20」+「做完」approval:
|
|
132
133
|
// 撤回 text-flow 例外設計,Breadcrumb chevron 跟其他 chrome icon 同 tier。
|
|
133
134
|
// World-class 對齊:Atlassian Breadcrumb chevron 16 default / Material 3 / Ant Design 同。
|
|
@@ -598,7 +599,7 @@ export const breadcrumbMeta = {
|
|
|
598
599
|
|
|
599
600
|
},
|
|
600
601
|
sizes: {
|
|
601
|
-
// 值源 = code SSOT:
|
|
602
|
+
// 值源 = code SSOT:BREADCRUMB_TEXT_CLASS(sm/md=text-body, lg=text-body-lg)+ BREADCRUMB_ICON_SIZE(sm/md=16, lg=20)。
|
|
602
603
|
// Breadcrumb 是文字列無固定高度 token,故不列 height(對照 Tag meta 有自身 h-* 才列)。
|
|
603
604
|
sm: { iconSize: 16, typography: 'body' },
|
|
604
605
|
md: { iconSize: 16, typography: 'body' },
|
|
@@ -159,7 +159,9 @@ interface BulkActionBarLabels {
|
|
|
159
159
|
count: (n: number) => string // default 「已選 {n} 項」
|
|
160
160
|
clear: string // default 「清除選取」(X aria-label)
|
|
161
161
|
hiddenSuffix: (hidden: number) => string // default 「· {hidden} 個被 filter 隱藏」
|
|
162
|
-
|
|
162
|
+
ariaLabel?: string // root role="group" 的 aria-label(2026-07-06 新主 key;未傳 fallback toolbarAriaLabel)
|
|
163
|
+
/** @deprecated 2026-07-06 role 已降級 "group"(見 a11y 段),改用 ariaLabel;此 key 保留 backward-compat,值仍作 fallback。default 「批次操作」 */
|
|
164
|
+
toolbarAriaLabel: string
|
|
163
165
|
}
|
|
164
166
|
```
|
|
165
167
|
|
|
@@ -177,7 +179,7 @@ interface BulkActionBarLabels {
|
|
|
177
179
|
|
|
178
180
|
## a11y 預設
|
|
179
181
|
|
|
180
|
-
- BulkActionBar 整體用 `role="
|
|
182
|
+
- BulkActionBar 整體用 `role="group"` + `aria-label`(default `"批次操作"`,由 `labels.ariaLabel ?? labels.toolbarAriaLabel` 決定,可 override)。**降級 rationale(2026-07-06 user 拍板)**:原宣告 `role="toolbar"` 但未實作 APG toolbar 方向鍵 roving 契約(AT 告知「工具列」但方向鍵無反應 = 空承諾);改 `role="group"` 語意誠實,Tab 序照 DOM(見下)。Gmail / Linear bulk bar 實務同款。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
181
183
|
- count 文字用 `aria-live="polite"` + `aria-atomic="true"`(selection 變更時 SR 整句重讀「已選 3 項」)
|
|
182
184
|
- Clear button:`aria-label="清除選取"`
|
|
183
185
|
- Hint banner 用 `role="status"` + `aria-live="polite"`(state 切換時通知)
|
|
@@ -195,7 +195,7 @@ export const PrimaryRule: Story = {
|
|
|
195
195
|
title="✅ 卡片清單 CTA 用 tertiary"
|
|
196
196
|
note="重複出現的 CTA 應使用 tertiary,避免頁面充斥填滿按鈕,稀釋 primary 的信號強度"
|
|
197
197
|
>
|
|
198
|
-
{['
|
|
198
|
+
{['官網改版', '行動裝置 App', '設計系統'].map(name => (
|
|
199
199
|
<div key={name} className="border border-border rounded-lg px-4 py-3 flex items-center gap-3 min-w-40">
|
|
200
200
|
<span className="text-body flex-1">{name}</span>
|
|
201
201
|
<Button variant="tertiary" size="xs">開啟</Button>
|
|
@@ -368,7 +368,7 @@ const ICON_ONLY_BASE = 'aspect-square p-0 min-w-0 gap-0'
|
|
|
368
368
|
|
|
369
369
|
Button 自動加 **`data-unbounded="true"`** attribute 當 **`variant === 'text'` OR `dismiss === true`** 任一成立。這是 DS-wide 視覺邊界 marker,讓容器(如 SurfaceHeader)可用 CSS selector 對無視覺邊界 button 套 layout 調整。
|
|
370
370
|
|
|
371
|
-
**實際應用**:`SurfaceHeader`
|
|
371
|
+
**實際應用**:`SurfaceHeader` 內建 CSS rule(SSOT 在 `overlay-surface.tsx` `CHROME_UNBOUNDED_SLOT`,此處僅引述不重述完整公式;`SurfaceFooter` 不套此 rule):
|
|
372
372
|
```css
|
|
373
373
|
[&_[data-unbounded]]:my-[calc((var(--chrome-slot-h,calc(var(--font-body-lg-size)*1.5))-var(--field-height-sm))/2)]
|
|
374
374
|
```
|
|
@@ -413,7 +413,7 @@ Button 自動加 **`data-unbounded="true"`** attribute 當 **`variant === 'text'
|
|
|
413
413
|
- ❌ `startIcon` 不得放超過一個
|
|
414
414
|
- ❌ `link` variant 不得嵌入段落文字——用 HTML `<a>` 代替
|
|
415
415
|
- ❌ 不得直接使用 `variant="destructive"` 或 `variant="ghost"`——shadcn 內部 alias,僅供框架元件使用
|
|
416
|
-
- ❌ `danger` 僅支援 `primary`、`secondary`、`text`——`tertiary` + danger
|
|
416
|
+
- ❌ `danger` 僅支援 `primary`、`secondary`、`text`——`tertiary` + danger 無對應 compoundVariant,會靜默渲染成一般 tertiary(灰、無紅色 danger 視覺,並非等同 secondary),`link` + danger 語義矛盾(連結暗示導覽,非破壞)
|
|
417
417
|
- ❌ `pressed` 不得用於多選一——應使用 Segmented Control
|
|
418
418
|
- ❌ `pressed` 不得套用於 `primary` / `link`——主要操作不應 toggle、link 語意為導覽
|
|
419
419
|
- ❌ `iconOnly` 不可與 `endIcon` 或 `badge` 並用——會破壞正方形結構
|
|
@@ -396,6 +396,17 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
396
396
|
|
|
397
397
|
const resolvedDanger = dangerProp || (variantProp as string) === 'destructive'
|
|
398
398
|
|
|
399
|
+
// Dev-mode warning:danger 僅 primary / secondary / text 有 compoundVariant。
|
|
400
|
+
// tertiary / link + danger 無匹配 compound → **靜默渲染成一般 tertiary / link**(灰、無紅色
|
|
401
|
+
// danger 視覺)— consumer 可能出「不紅的刪除鍵」而不自知。Spec SSOT:button.spec.md
|
|
402
|
+
// 「禁止事項」danger 條(2026-07-14 deep-audit 補 warn,對齊既有 overlayBadge / iconOnly warn pattern)。
|
|
403
|
+
if (process.env.NODE_ENV !== 'production' && resolvedDanger && (resolvedVariant === 'tertiary' || resolvedVariant === 'link')) {
|
|
404
|
+
// eslint-disable-next-line no-console
|
|
405
|
+
console.warn(
|
|
406
|
+
`[DS Button] \`danger\` 不支援 variant="${resolvedVariant}"(無對應 compoundVariant,會靜默渲染成一般 ${resolvedVariant},無紅色 danger 視覺)。危險操作請改用 primary(立即不可逆)/ secondary(可反悔)/ text(低度)。SSOT:button.spec.md「禁止事項」danger 條。`
|
|
407
|
+
)
|
|
408
|
+
}
|
|
409
|
+
|
|
399
410
|
// ButtonGroup context:vertical group 自動注入 fullWidth
|
|
400
411
|
const groupCtx = React.useContext(ButtonGroupContext)
|
|
401
412
|
const resolvedFullWidth = fullWidth || !!groupCtx.fullWidth
|
|
@@ -561,11 +572,15 @@ export const buttonMeta = {
|
|
|
561
572
|
lg: { fieldHeight: 36, iconSize: 20, typography: 'body-lg' },
|
|
562
573
|
},
|
|
563
574
|
// 'pressed' = toggle on 持續態(data-[state=on],emphasis 淡藍底/neutral 灰底;2026-07-07 meta 詞彙統一補列)
|
|
564
|
-
|
|
575
|
+
// 'loading' = CircularProgress spinner 取代 startIcon + aria-busy + click guard(2026-07-14 deep-audit
|
|
576
|
+
// 補列,原漏 → auto-compile 生成矩陣缺 loading;對齊 anatomy StateBehavior Loading 行 + tsx loading 分支)
|
|
577
|
+
states: ['default', 'hover', 'active', 'pressed', 'loading', 'focus-visible', 'disabled'],
|
|
565
578
|
tokens: {
|
|
566
579
|
// 2026-07-04 audit 補齊:原只列 primary variant 家族;按 buttonVariants cva 真實 class 補
|
|
567
|
-
// secondary/tertiary/text/link/danger 消費的 token(auto-compile token 矩陣依此)
|
|
568
|
-
|
|
580
|
+
// secondary/tertiary/text/link/danger 消費的 token(auto-compile token 矩陣依此)。
|
|
581
|
+
// 2026-07-14 deep-audit 二次補齊(掃 cva 全 bg-* class):+ neutral-selected-hover / neutral-selected-active
|
|
582
|
+
// (neutral pressedTone compound 消費)+ error / error-hover / error-active(primary+danger bg-error 系)
|
|
583
|
+
bg: ['--primary', '--primary-hover', '--primary-active', '--primary-subtle', '--bg-disabled', '--surface', '--neutral-hover', '--neutral-active', '--neutral-selected', '--neutral-selected-hover', '--neutral-selected-active', '--error', '--error-hover', '--error-active'],
|
|
569
584
|
fg: ['--on-emphasis', '--fg-disabled', '--foreground', '--primary', '--error', '--error-hover', '--error-active'],
|
|
570
585
|
ring: ['--ring'],
|
|
571
586
|
},
|