@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
|
@@ -68,10 +68,22 @@ export interface MenuItemProps
|
|
|
68
68
|
children: React.ReactNode
|
|
69
69
|
/** 次要說明文字,顯示在 label 下方 */
|
|
70
70
|
description?: React.ReactNode
|
|
71
|
-
/** 左側 icon(LucideIcon),與 avatar 互斥 */
|
|
71
|
+
/** 左側 icon(LucideIcon),與 avatar / startContent 互斥 */
|
|
72
72
|
startIcon?: LucideIcon
|
|
73
|
-
/**
|
|
73
|
+
/** startIcon 的 className 透傳(2026-07-08 WM 戰役:status 類彩色 icon 需求;disabled 色仍勝出) */
|
|
74
|
+
startIconClassName?: string
|
|
75
|
+
/** 左側頭像資料(AvatarData),元件內部渲染 Avatar。與 startIcon / startContent 互斥 */
|
|
74
76
|
avatar?: AvatarData
|
|
77
|
+
/**
|
|
78
|
+
* 左側自訂內容(ReactNode),與 startIcon / avatar 互斥。與 `endContent` 對稱。
|
|
79
|
+
*
|
|
80
|
+
* **佔位與排列邏輯跟 startIcon 一模一樣**(2026-07-10 WM TypeIcon 彩色徽章需求):
|
|
81
|
+
* 渲染在同一個 prefix 對齊容器(`itemPrefixAlignVariants` SSOT)內 —— gap / 對齊 /
|
|
82
|
+
* shrink 全繼承,零平行 layout 邏輯,不可能與 startIcon 漂移。Consumer 唯一責任
|
|
83
|
+
* 是節點尺寸對齊 `ICON_SIZE[size]`(sm/md=16px、lg=20px;如 `size-4` 徽章)。
|
|
84
|
+
* 典型場景:類型徽章(彩底 + glyph)、status 圓點組合等 LucideIcon 表達不了的 leading 視覺。
|
|
85
|
+
*/
|
|
86
|
+
startContent?: React.ReactNode
|
|
75
87
|
/** 顯示 checkbox(多選模式由父層控制) */
|
|
76
88
|
checkbox?: boolean
|
|
77
89
|
/** Checkbox 選中狀態 */
|
|
@@ -132,7 +144,9 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
132
144
|
children,
|
|
133
145
|
description,
|
|
134
146
|
startIcon: StartIcon,
|
|
147
|
+
startIconClassName,
|
|
135
148
|
avatar,
|
|
149
|
+
startContent,
|
|
136
150
|
checkbox,
|
|
137
151
|
checked,
|
|
138
152
|
selected,
|
|
@@ -165,7 +179,7 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
165
179
|
? (`block-${sizeKey}` as const)
|
|
166
180
|
: 'inline'
|
|
167
181
|
|
|
168
|
-
const hasPrefix = !!StartIcon || !!avatar || checkbox
|
|
182
|
+
const hasPrefix = !!StartIcon || !!avatar || !!startContent || checkbox
|
|
169
183
|
|
|
170
184
|
// ── Header variant ──
|
|
171
185
|
if (header) {
|
|
@@ -221,11 +235,21 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
221
235
|
{hasPrefix && (
|
|
222
236
|
<div className={cn(itemPrefixAlignVariants({ align: prefixAlign }))}>
|
|
223
237
|
{checkbox && (
|
|
238
|
+
// 2026-07-14 a11y(axe nested-interactive):此 checkbox 是純視覺 indicator —— checked
|
|
239
|
+
// ARIA state 由外層 row 單一 owner 宣告(Radix menuitemcheckbox / cmdk option /
|
|
240
|
+
// select-all row role="checkbox",見上方「ARIA 單一 owner gate」)。Radix Checkbox 渲
|
|
241
|
+
// focusable <button role="checkbox">,巢狀在互動 row 內 = axe nested-interactive
|
|
242
|
+
// violation;tabIndex=-1 不夠(axe-core no-focusable-content 對 tabindex<0 仍回
|
|
243
|
+
// violation,僅 messageKey 換 notHidden)。aria-hidden 移出 AT tree(消 SR 內外雙重
|
|
244
|
+
// checkbox 宣告)+ inert 移除 focusability(axe focusDisabled 認 inert → clean pass)。
|
|
245
|
+
// inert:React 18 無 typing(React 19 才內建),以 spread cast 傳字串 attr。
|
|
224
246
|
<Checkbox
|
|
225
247
|
size={CHECKBOX_SIZE[sizeKey]}
|
|
226
248
|
checked={checked === true ? true : checked === 'indeterminate' ? 'indeterminate' : false}
|
|
227
249
|
disabled={disabled}
|
|
228
250
|
tabIndex={-1}
|
|
251
|
+
aria-hidden
|
|
252
|
+
{...({ inert: '' } as object)}
|
|
229
253
|
className="pointer-events-none"
|
|
230
254
|
/>
|
|
231
255
|
)}
|
|
@@ -233,7 +257,7 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
233
257
|
<StartIcon
|
|
234
258
|
data-prefix-type="icon"
|
|
235
259
|
size={iconPx}
|
|
236
|
-
className={cn('shrink-0', disabled && 'text-fg-disabled')}
|
|
260
|
+
className={cn('shrink-0', startIconClassName, disabled && 'text-fg-disabled')}
|
|
237
261
|
aria-hidden
|
|
238
262
|
/>
|
|
239
263
|
)}
|
|
@@ -247,6 +271,16 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
247
271
|
size={avatarPx}
|
|
248
272
|
/>
|
|
249
273
|
)}
|
|
274
|
+
{startContent && (
|
|
275
|
+
// 自訂 leading 節點:同容器 = 佔位/排列與 startIcon 一模一樣(見 props JSDoc)。
|
|
276
|
+
// disabled 用 opacity-disabled(對齊本元件 suffix slot 對自訂 ReactNode 的同款處理)。
|
|
277
|
+
<span
|
|
278
|
+
data-prefix-type="content"
|
|
279
|
+
className={cn('flex shrink-0 items-center', disabled && 'opacity-disabled')}
|
|
280
|
+
>
|
|
281
|
+
{startContent}
|
|
282
|
+
</span>
|
|
283
|
+
)}
|
|
250
284
|
</div>
|
|
251
285
|
)}
|
|
252
286
|
|
|
@@ -47,7 +47,7 @@ export const UsageGuidance: Story = {
|
|
|
47
47
|
<Section title="何時不用 + 替代">
|
|
48
48
|
<p>Notice 是 internal primitive,自身有 dismiss 按鈕 + <code>onDismiss</code> callback,但不管 dismiss 後的 mount / unmount 生命週期,也無 auto-dismiss 計時——需要這些行為改用以下 consumer:</p>
|
|
49
49
|
<ul>
|
|
50
|
-
<li><strong
|
|
50
|
+
<li><strong>需要 dismiss 後移除(永久 inline)</strong> → 用 <code>Alert</code>(內部消費 Notice + live region:error/warning role="alert"、其餘 role="status")。Alert 是 controlled-only:提供 <code>onDismiss</code> callback,consumer 在 callback 中更新狀態並自行 unmount,Alert 不會自行移除</li>
|
|
51
51
|
<li><strong>需要 auto-dismiss(短暫 toast)</strong> → 用 <code>Toast</code></li>
|
|
52
52
|
<li><strong>表單欄位錯誤訊息</strong> → 用 <code>Field</code> 內建 errorText,不用 Notice</li>
|
|
53
53
|
</ul>
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Notice
|
|
3
3
|
family: 2
|
|
4
|
-
|
|
4
|
+
# variant 語意 = status icon 選擇(見本文「Variant」表);world-class 對照見 frontmatter benchmark 清單
|
|
5
|
+
variants:
|
|
6
|
+
neutral:
|
|
7
|
+
when: "一般訊息、系統公告;無情緒色、不掛 status icon"
|
|
8
|
+
info:
|
|
9
|
+
when: "資訊提示(版本更新、流程說明);Info icon"
|
|
10
|
+
success:
|
|
11
|
+
when: "操作成功確認;CircleCheck icon"
|
|
12
|
+
warning:
|
|
13
|
+
when: "可恢復警告(未儲存變更、連線不穩);TriangleAlert icon"
|
|
14
|
+
error:
|
|
15
|
+
when: "錯誤(操作失敗、權限不足);XCircle icon"
|
|
5
16
|
sizes: {}
|
|
6
17
|
traits:
|
|
7
18
|
- isInternal
|
|
@@ -25,7 +36,7 @@ Notice 是純視覺 primitive,不是獨立使用的元件。消費者:
|
|
|
25
36
|
|
|
26
37
|
**Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。Notice 語意為 notification(非 row collection),但視覺排版遵循 Family 2 確保跨元件視覺一致。
|
|
27
38
|
|
|
28
|
-
**尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size**——不實作 Family 2 baseline 的 sm/md/lg,padding
|
|
39
|
+
**尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size**——不實作 Family 2 baseline 的 sm/md/lg,padding 預設不隨 density 變(`px-4 py-3` 固定;唯一例外:Alert `placement="fixed"` 水平 px 改 density-aware,詳「Padding」段)。通知用單一 prominent size 強化「搶注意」的目的性,對齊世界級共識(Material Banner/Snackbar、Polaris Banner、Atlassian InlineMessage、GitHub Flash)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
29
40
|
|
|
30
41
|
## Typography
|
|
31
42
|
|
|
@@ -49,6 +60,8 @@ Notice 是純視覺 primitive,不是獨立使用的元件。消費者:
|
|
|
49
60
|
|
|
50
61
|
不隨 density 變——Toast/Alert 是通知,不是工作區域元件。
|
|
51
62
|
|
|
63
|
+
**例外——Alert `placement="fixed"` 水平 px density-aware**:Alert 的 fixed placement 傳 `className='px-[var(--layout-space-loose)]'`(`alert.tsx` fixed 分支)覆寫 Notice 的 `px-4`,改用 density-aware 水平 padding(md=16 / lg=24px),讓 fixed alert 嵌在更大佈局時跟周圍 loose-padding 元素(Toolbar / BulkActionBar / DataTable)左右對齊。垂直 `py-3` 仍固定(notification banner family 垂直不隨 density)。故上方「px 固定」限 Notice 預設 / Toast / Alert inline placement;Alert fixed placement 是唯一 documented 例外。
|
|
64
|
+
|
|
52
65
|
## Layout
|
|
53
66
|
|
|
54
67
|
item-layout 4-slot:
|
|
@@ -89,7 +102,7 @@ CSS `color` 從 body 繼承的是**已解析的計算值**,不是 `var(--foreg
|
|
|
89
102
|
|
|
90
103
|
## 何時用 / 何時不用
|
|
91
104
|
|
|
92
|
-
**Notice 是 internal primitive
|
|
105
|
+
**Notice 是 internal primitive**——不進 root barrel front-door、不裸用;透過 `Alert` / `Toast` 等外層通知元件消費;consumer 需要時可經 per-component subpath 包裝並自行確認後使用(`.claude/rules/ui-development.md`「Root barrel front-door 排除」SSOT,internal ≠ 禁用)。
|
|
93
106
|
|
|
94
107
|
| 場景 | 正確做法 |
|
|
95
108
|
|------|---------|
|
|
@@ -231,7 +231,7 @@ export const Overview = {
|
|
|
231
231
|
<NumberInput mode="readonly" value={value} {...props} className="max-w-[200px]" />
|
|
232
232
|
</div>
|
|
233
233
|
<span className="text-caption font-mono text-fg-secondary">{label}</span>
|
|
234
|
-
{value === null && <span className="text-[11px] text-fg-muted">
|
|
234
|
+
{value === null && <span className="text-[11px] text-fg-muted">hyphen + text-foreground</span>}
|
|
235
235
|
</div>
|
|
236
236
|
))}
|
|
237
237
|
</div>
|
|
@@ -722,7 +722,7 @@ export const StateBehavior = {
|
|
|
722
722
|
{[
|
|
723
723
|
['value = 2490, prefix="$"', '2490(raw 數值)', '$2,490(格式化)'],
|
|
724
724
|
['value = 85.5, suffix="%", precision=1', '85.5(raw 數值)', '85.5%(格式化)'],
|
|
725
|
-
['value = null', '空白', '
|
|
725
|
+
['value = null', '空白', '- (hyphen, foreground)'],
|
|
726
726
|
['value = 12500, prefix="NT$"', '12500(raw 數值)', 'NT$12,500(格式化)'],
|
|
727
727
|
].map(([ctx, edit, display]) => (
|
|
728
728
|
<tr key={ctx}>
|
|
@@ -745,7 +745,7 @@ export const StateBehavior = {
|
|
|
745
745
|
<div key={m} className="flex flex-col gap-1 items-start">
|
|
746
746
|
<span className="text-[11px] text-fg-muted font-mono">{m}</span>
|
|
747
747
|
<div className="w-[160px]"><NumberInput mode={m} value={null} prefix="$" /></div>
|
|
748
|
-
<span className="text-[10px] text-fg-muted">{m === 'edit' ? '空白 input' : m === 'disabled' ? '
|
|
748
|
+
<span className="text-[10px] text-fg-muted">{m === 'edit' ? '空白 input' : m === 'disabled' ? 'hyphen - + fg-disabled(M24 state > emphasis)' : 'hyphen - + foreground'}</span>
|
|
749
749
|
</div>
|
|
750
750
|
))}
|
|
751
751
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @principles-rationale: UsageGuidance merges WhenToUse + WhenNotToUse into single 使用指引 story per refactor task (2026-04-26)
|
|
2
|
-
// @story-baseline: packages/design-system/src/components/DataTable/data-table.stories.tsx#
|
|
2
|
+
// @story-baseline: packages/design-system/src/components/DataTable/data-table.anatomy.stories.tsx#AlignmentRule
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import LinkTo from '@storybook/addon-links/react'
|
|
5
5
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
@@ -68,7 +68,7 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
|
|
|
68
68
|
`<NumberInput mode="display">` 在 table cell 和 Form readonly 共用 `formatNumber()` 格式化函式。
|
|
69
69
|
|
|
70
70
|
- 有值:格式化輸出(prefix + localized number + suffix)
|
|
71
|
-
- null / undefined
|
|
71
|
+
- null / undefined:半形 `-`(hyphen),`text-foreground`(disabled → fg-disabled)
|
|
72
72
|
|
|
73
73
|
## DataTable 整合
|
|
74
74
|
|
|
@@ -105,11 +105,11 @@ col.accessor('price', {
|
|
|
105
105
|
|
|
106
106
|
- **Disabled**:由 Field SSOT own(`Field/field-controls.spec.md` State machine 段)。視覺:wrapper bg → `bg-disabled`(neutral-2,`semantic.css` `--bg-disabled`)、formatted text → `text-fg-disabled`(M24 state>emphasis)。Display mode + disabled 維持格式化輸出但 token 切 disabled。
|
|
107
107
|
- **Loading**:NumberInput 不提供 loading state(`NumberInputProps` 無 `loading` prop、無 `CircularProgress` / `aria-busy` 邏輯)。數值輸入為同步操作,無 async fetch 語意;若需 async 場景(如遠端校驗)請走外層 Field validation + `endSlot` 自訂 spinner。
|
|
108
|
-
- **Empty(null / undefined / 空字串)**:Display mode
|
|
108
|
+
- **Empty(null / undefined / 空字串)**:Display / readonly mode 渲半形 `-`(hyphen + `text-foreground`,disabled → fg-disabled);Edit mode placeholder 走 default placeholder color。
|
|
109
109
|
- **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + wrapper `border-error`(hover 時 `border-error-hover`)+ 下方 error message)。
|
|
110
|
-
- **輸入中間態**(`-`、`1.`、`0.0` 等 parse 後 lossy 的 raw 字串,2026-07-05 D4 codify):edit mode 以 internal draft string 承載——輸入期間 DOM 顯示 draft 原字串(負號、尾點不被 controlled 回寫吃掉),parse 成功即時同步 `onChange(parsed)`;blur / Enter commit(清 draft、顯示回 committed value,不合法殘字自然還原)、Escape
|
|
110
|
+
- **輸入中間態**(`-`、`1.`、`0.0` 等 parse 後 lossy 的 raw 字串,2026-07-05 D4 codify):edit mode 以 internal draft string 承載——輸入期間 DOM 顯示 draft 原字串(負號、尾點不被 controlled 回寫吃掉),parse 成功即時同步 `onChange(parsed)`;blur / Enter commit(清 draft、顯示回 committed value,不合法殘字自然還原)、Escape 棄未提交 draft 字串、顯示回 committed value(NumberInput 為 live-commit,每次合法 parse 即 onChange,故非回復 pre-edit 原值;真 revert 需另存 snapshot,屬 API 擴充)。value 面語意不變:`''` / `'-'` 視為 `null`。對齊 Ant InputNumber / Adobe Spectrum NumberField internal draft canonical。 <!-- @benchmark-unverified -->
|
|
111
111
|
- **負數 / 超大數字**:`toLocaleString(locale)` 自動處理負號與千分位分組,無特殊 prop。
|
|
112
|
-
- **科學記號輸入**(`1e5`):`Number(raw)` parse 為 `100000`,非 NaN 即觸發 `onChange`(`number-input.tsx:
|
|
112
|
+
- **科學記號輸入**(`1e5`):`Number(raw)` parse 為 `100000`,非 NaN 即觸發 `onChange`(`number-input.tsx:150-152`)。
|
|
113
113
|
- **精度上限**:`precision` > 6 為禁止事項(浮點精度雜訊),極端精度走 `Input` + 自驗證。
|
|
114
114
|
- **RTL**:未實作方向鏡像(edit 靠左 / table cell 靠右皆以 LTR 設計);RTL 屬 DS-wide 決策,未定(與 Chip / Breadcrumb 同口徑)。
|
|
115
115
|
- **Dark mode / density**:走 Field SSOT,不獨立 own。
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import { type VariantProps } from 'class-variance-authority'
|
|
3
3
|
import { cn } from '@/lib/utils'
|
|
4
|
-
import type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'
|
|
4
|
+
import type { FieldMode, FieldVariant, FieldVariantInternal } from '@/design-system/components/Field/field-types'
|
|
5
5
|
import type { InlineActionConfig } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
6
|
-
import { fieldWrapperStyles, bareInputStyles
|
|
6
|
+
import { fieldWrapperStyles, bareInputStyles } from '@/design-system/components/Field/field-wrapper'
|
|
7
|
+
import { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'
|
|
7
8
|
import { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid } from '@/design-system/components/Field/field-context'
|
|
8
9
|
import { ItemInlineAction } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
9
10
|
|
|
@@ -38,17 +39,20 @@ function formatNumber(
|
|
|
38
39
|
// ── Types ───────────────────────────────────────────────────────────────────
|
|
39
40
|
|
|
40
41
|
export interface NumberInputProps
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
// `defaultValue` 一併 Omit(2026-07-14 dim-26):number-input.spec.md「controlled-only,不支援
|
|
43
|
+
// defaultValue」宣稱的型別面機械封鎖 — 原本仍在型別 surface 且經 {...props} spread 到已
|
|
44
|
+
// controlled 的 input(React value/defaultValue dev warning)。與 LinkInput(link-input.tsx)同款。
|
|
45
|
+
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'value' | 'defaultValue' | 'onChange' | 'type'>,
|
|
46
|
+
Omit<VariantProps<typeof fieldWrapperStyles>, 'mode' | 'variant' | 'width'>,
|
|
43
47
|
NumberFormatOptions {
|
|
44
48
|
/** Field display mode */
|
|
45
49
|
mode?: FieldMode
|
|
46
50
|
/**
|
|
47
51
|
* Visual chrome(正交於 mode);Phase B1(2026-05-05)新增。
|
|
48
52
|
* - `'default'`(預設)— 完整 Field wrapper chrome。
|
|
49
|
-
* - `
|
|
53
|
+
* (2026-07-09 `bare` variant 退役;naked = cell-as-input substrate,@internal)
|
|
50
54
|
*
|
|
51
|
-
* 透傳:在 `<Field variant="
|
|
55
|
+
* 透傳:在 `<Field variant="default">` 內自動繼承 context.variant;per-prop override context。
|
|
52
56
|
*/
|
|
53
57
|
variant?: FieldVariant
|
|
54
58
|
/** Error 狀態(正交於 mode)。 */
|
|
@@ -102,16 +106,19 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
102
106
|
const size = useResolvedFieldSize(sizeProp)
|
|
103
107
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
104
108
|
// chrome 透傳:per-prop override context;context 沒值則 'default'
|
|
105
|
-
const variant:
|
|
109
|
+
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
106
110
|
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode 統一解析(prop > 有效 disabled > fieldCtx.mode > readOnly > 'edit')
|
|
107
111
|
const resolvedMode: FieldMode = useResolvedFieldMode({ mode: modeProp, disabled, readOnly })
|
|
112
|
+
const emptyDisplay = useFieldEmptyDisplay()
|
|
108
113
|
|
|
109
114
|
// 2026-07-05 D4 draft state:controlled value 回寫會吃掉輸入中間態('-'、'1.'、'0.0' 等
|
|
110
115
|
// parse 後 lossy 的 raw 字串)— 例:已有值 5 全選打「-」→ onChange(null) 回寫把 DOM 重設
|
|
111
116
|
// 為空,負號被吃、無法打出 -5。修法對齊 Ant InputNumber / Adobe Spectrum NumberField 的
|
|
112
117
|
// internal draft string canonical:輸入期間 DOM 顯示以 local draft 優先,parse 成功即時同步
|
|
113
|
-
// onChange(parsed);blur / Enter commit 清 draft
|
|
114
|
-
//
|
|
118
|
+
// onChange(parsed);blur / Enter commit 清 draft、顯示回 committed value;Escape 棄未提交
|
|
119
|
+
// raw draft 字串、顯示回 committed value(NumberInput 為 live-commit:每次合法 parse 即
|
|
120
|
+
// onChange,故非回復 pre-edit 原值 — 真 revert 需另存 pre-edit snapshot,屬 API 擴充)。
|
|
121
|
+
// 宣告於 non-edit early return 之前(Rules-of-Hooks,
|
|
115
122
|
// 同 LinkInput 2026-07-04 修法)。
|
|
116
123
|
const [draft, setDraft] = React.useState<string | null>(null)
|
|
117
124
|
|
|
@@ -126,11 +133,11 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
126
133
|
className={cn(
|
|
127
134
|
'flex-1 min-w-0',
|
|
128
135
|
resolvedMode === 'disabled' && 'text-fg-disabled cursor-not-allowed',
|
|
129
|
-
// 2026-
|
|
130
|
-
value == null && resolvedMode
|
|
136
|
+
// 2026-07-09 空值符號前景 + M24:fieldEmptyColorClass = disabled→fg-disabled / else→foreground(同 readonly value 色)
|
|
137
|
+
value == null && fieldEmptyColorClass(resolvedMode),
|
|
131
138
|
)}
|
|
132
139
|
>
|
|
133
|
-
{value == null ?
|
|
140
|
+
{value == null ? emptyDisplay : formatNumber(value, { precision, prefix, suffix, locale })}
|
|
134
141
|
</span>
|
|
135
142
|
</div>
|
|
136
143
|
)
|
|
@@ -15,11 +15,11 @@ import { Tag } from '@/design-system/components/Tag/tag'
|
|
|
15
15
|
import { Avatar } from '@/design-system/components/Avatar/avatar'
|
|
16
16
|
import { ProfileCard, ProfileCardDefaultActions } from '@/design-system/components/ProfileCard/profile-card'
|
|
17
17
|
|
|
18
|
-
const personHover = (name: string) => (
|
|
18
|
+
const personHover = (name: string, src?: string) => (
|
|
19
19
|
<ProfileCard
|
|
20
20
|
name={name}
|
|
21
21
|
subtitle="Design|D-0042|EMP-1001"
|
|
22
|
-
avatar={{ alt: name }}
|
|
22
|
+
avatar={{ src, alt: name }}
|
|
23
23
|
status="online"
|
|
24
24
|
statusMessage="Out of Office: Back on Monday."
|
|
25
25
|
actions={<ProfileCardDefaultActions />}
|
|
@@ -31,6 +31,8 @@ const personHover = (name: string) => (
|
|
|
31
31
|
/>
|
|
32
32
|
)
|
|
33
33
|
const P = { A: 'Alan Chen', B: 'Betty Wu', C: 'Charlie Lee' } as const
|
|
34
|
+
// 真實人像(2026-07-08 sweep):u=EMP-100x 對齊 dialog.stories.tsx MEMBERS 同名人物(跨 story 同人同照)
|
|
35
|
+
const P_SRC = { A: 'https://i.pravatar.cc/48?u=EMP-1001', B: 'https://i.pravatar.cc/48?u=EMP-1002', C: 'https://i.pravatar.cc/48?u=EMP-1003' } as const
|
|
34
36
|
import { H3, Desc, Td, Th, Swatch } from '@/design-system/stories-helpers/anatomy/anatomy-utils'
|
|
35
37
|
|
|
36
38
|
const meta: Meta = {
|
|
@@ -322,11 +324,11 @@ function OverflowInspector() {
|
|
|
322
324
|
</tr>
|
|
323
325
|
<tr>
|
|
324
326
|
<Td mono>openDelay</Td>
|
|
325
|
-
<Td mono>500ms(
|
|
327
|
+
<Td mono>500ms(MOTION_DELAY_PLAIN_MS)</Td>
|
|
326
328
|
</tr>
|
|
327
329
|
<tr>
|
|
328
330
|
<Td mono>closeDelay</Td>
|
|
329
|
-
<Td mono>200ms(
|
|
331
|
+
<Td mono>200ms(MOTION_DELAY_CLOSE_MS)</Td>
|
|
330
332
|
</tr>
|
|
331
333
|
</tbody>
|
|
332
334
|
</table>
|
|
@@ -489,9 +491,9 @@ export const SizeMatrix: Story = {
|
|
|
489
491
|
<Td mono>sm</Td>
|
|
490
492
|
<Td>
|
|
491
493
|
<div className="flex items-center">
|
|
492
|
-
<Avatar alt={P.A} color="indigo" size={20} hoverCard={personHover(P.A)} />
|
|
494
|
+
<Avatar src={P_SRC.A} alt={P.A} color="indigo" size={20} hoverCard={personHover(P.A, P_SRC.A)} />
|
|
493
495
|
<span className="-ml-1.5">
|
|
494
|
-
<Avatar alt={P.B} color="magenta" size={20} hoverCard={personHover(P.B)} />
|
|
496
|
+
<Avatar src={P_SRC.B} alt={P.B} color="magenta" size={20} hoverCard={personHover(P.B, P_SRC.B)} />
|
|
495
497
|
</span>
|
|
496
498
|
<span className="-ml-1.5">
|
|
497
499
|
<OverflowIndicator count={3} shape="circle" size="sm">
|
|
@@ -519,7 +521,7 @@ export const SizeMatrix: Story = {
|
|
|
519
521
|
<Td mono>md</Td>
|
|
520
522
|
<Td>
|
|
521
523
|
<div className="flex items-center">
|
|
522
|
-
<Avatar alt={P.A} color="indigo" size={24} hoverCard={personHover(P.A)} />
|
|
524
|
+
<Avatar src={P_SRC.A} alt={P.A} color="indigo" size={24} hoverCard={personHover(P.A, P_SRC.A)} />
|
|
523
525
|
<span className="-ml-1.5">
|
|
524
526
|
<OverflowIndicator count={4} shape="circle" size="md">
|
|
525
527
|
<div className="p-1 text-caption">…</div>
|
|
@@ -543,7 +545,7 @@ export const Accessibility = {
|
|
|
543
545
|
render: () => (
|
|
544
546
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
545
547
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
546
|
-
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0
|
|
548
|
+
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0;不掛 role/aria-haspopup——無 activation 行為的宣告是對 AT 空承諾,2026-07-14 對齊 Avatar hoverCard canonical 拆除;2026-06-01 #13 由純 passive 改 focusable,修 WCAG 2.1.1 違反)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger 是 tab stop(focus-visible ring,鍵盤使用者可 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(人員 tag / ProfileCard)由各自內容元件負責 focus 管理。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。"}</p>
|
|
547
549
|
</div>
|
|
548
550
|
),
|
|
549
551
|
}
|
|
@@ -43,10 +43,10 @@ export const UsageGuidance: Story = {
|
|
|
43
43
|
<div className="prose prose-sm max-w-prose">
|
|
44
44
|
<p>處理超出空間的 2 種策略:</p>
|
|
45
45
|
<ul>
|
|
46
|
-
<li><strong>OverflowIndicator(本元件)</strong
|
|
47
|
-
<li><strong>ScrollArea</strong
|
|
46
|
+
<li><strong>OverflowIndicator(本元件)</strong>—項目數量已知且不多時,顯示前幾個、其餘折成 <code>+N</code>,點開看完整清單</li>
|
|
47
|
+
<li><strong>ScrollArea</strong>—項目數量未知或極多時,讓使用者捲動瀏覽全部</li>
|
|
48
48
|
</ul>
|
|
49
|
-
<p className="text-fg-muted"
|
|
49
|
+
<p className="text-fg-muted">判斷:項目數可數且少(≤ 100)→ OverflowIndicator;太多或未知數量 → ScrollArea。</p>
|
|
50
50
|
</div>
|
|
51
51
|
</div>
|
|
52
52
|
),
|
|
@@ -23,7 +23,7 @@ OverflowIndicator 是 **`+N` 溢出指示器 + HoverCard 顯示隱藏內容**—
|
|
|
23
23
|
|
|
24
24
|
## 何時用 / 何時不用
|
|
25
25
|
|
|
26
|
-
**OverflowIndicator 是 internal primitive
|
|
26
|
+
**OverflowIndicator 是 internal primitive**——不進 root barrel front-door、不裸用;由需要處理「溢出 +N」的元件消費;consumer 需要時可經 per-component subpath 包裝並自行確認後使用(`.claude/rules/ui-development.md`「Root barrel front-door 排除」SSOT,internal ≠ 禁用)。
|
|
27
27
|
|
|
28
28
|
| 場景 | 正確做法 |
|
|
29
29
|
|------|---------|
|
|
@@ -45,6 +45,8 @@ OverflowIndicator 是 **`+N` 溢出指示器 + HoverCard 顯示隱藏內容**—
|
|
|
45
45
|
|
|
46
46
|
Tooltip 純文字、不可互動、滑鼠離開 trigger 即消失——不適合承載這些需求。
|
|
47
47
|
|
|
48
|
+
**注意**:浮層內互動(tag dismiss / nested ProfileCard)為**滑鼠增強**——Radix HoverCard content 鍵盤不可達(見「A11y 預設」鍵盤限制),鍵盤等效操作由主列可見項承擔,勿把唯一操作入口放在浮層內。
|
|
49
|
+
|
|
48
50
|
### trigger 不用 Tag 元件
|
|
49
51
|
|
|
50
52
|
Tag 內建 truncation Tooltip 會跟 OverflowIndicator 的 HoverCard 衝突。改用 `tagVariants` 直接套樣式,保持視覺一致但不含 Tag 的額外行為。
|
|
@@ -120,7 +122,7 @@ OverflowIndicator 是 **composite**(HoverCard trigger + tag-styled `+N` span + H
|
|
|
120
122
|
|
|
121
123
|
**ARIA / Pattern**:對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。
|
|
122
124
|
|
|
123
|
-
**互動行為**:trigger 為 `+N` 計數 span,**keyboard-focusable**(`tabIndex=0
|
|
125
|
+
**互動行為**:trigger 為 `+N` 計數 span,**keyboard-focusable**(`tabIndex=0`;**不掛 `role="button"` / `aria-haspopup`**——2026-07-14 對齊 Avatar hoverCard canonical 2026-07-06 拆除:trigger 無 activation 行為,宣告 button/haspopup 卻按 Enter 無反應 = 對 AT 空承諾),HoverCard 在 hover 或 trigger 取得 focus 時自動展開——無「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。(2026-06-01 #13:原設計純 passive 不可聚焦 → 鍵盤使用者無法開啟 HoverCard 看溢出內容,違 WCAG 2.1.1;改 focusable)。**鍵盤限制**:HoverCard 內容(tag dismiss / nested ProfileCard)僅滑鼠可互動——Radix 把 content 內 tabbable node 設 `tabindex="-1"`(hover-card.spec.md「A11y 預設」),鍵盤等效操作由主列可見項承擔。
|
|
124
126
|
|
|
125
127
|
**Focus**:trigger 是 tab stop(keyboard 可達 + focus-visible ring,讓鍵盤使用者也能 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(如人員 tag / ProfileCard)由各自的內容元件負責 focus 管理。
|
|
126
128
|
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import type { ColumnDef } from '@tanstack/react-table'
|
|
2
3
|
import { OverflowIndicator } from './overflow-indicator'
|
|
3
4
|
import { Tag } from '@/design-system/components/Tag/tag'
|
|
4
5
|
import { Avatar } from '@/design-system/components/Avatar/avatar'
|
|
6
|
+
import { DataTable } from '@/design-system/components/DataTable/data-table'
|
|
5
7
|
import { ProfileCard, ProfileCardDefaultActions } from '@/design-system/components/ProfileCard/profile-card'
|
|
6
8
|
|
|
7
9
|
/** Person avatar hover canonical helper — 對齊 avatar.spec.md DS-wide rule:
|
|
8
10
|
* person avatar 必 hover → ProfileCard,必含 status / statusMessage / fields / actions / onViewMore
|
|
9
11
|
* (profile-card.spec.md 重要資訊 canonical;consumer 的 person 資料全備則全 render) */
|
|
10
|
-
const personHoverCard = (p: { name: string; role?: string; empId?: string }) => (
|
|
12
|
+
const personHoverCard = (p: { name: string; role?: string; empId?: string; avatarUrl?: string }) => (
|
|
11
13
|
<ProfileCard
|
|
12
14
|
name={p.name}
|
|
13
15
|
subtitle={p.role ? `${p.role}|${p.empId ?? 'EMP-0000'}` : 'Design|D-0042|EMP-1001'}
|
|
14
|
-
avatar={{ alt: p.name }}
|
|
16
|
+
avatar={{ src: p.avatarUrl, alt: p.name }}
|
|
15
17
|
status="online"
|
|
16
18
|
statusMessage="Out of Office: Back on Monday! For urgent matters please contact @Wei-Lun Cheng in the meantime."
|
|
17
19
|
actions={<ProfileCardDefaultActions />}
|
|
@@ -81,13 +83,15 @@ export const ComboboxTagOverflow: Story = {
|
|
|
81
83
|
Story 2:Avatar 人員 stack +N(shape="circle")
|
|
82
84
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
83
85
|
|
|
86
|
+
// 真實人像(2026-07-08 sweep):固定 u= key 保 determinism;中文名用拼音 key,跨 story 同人同照
|
|
87
|
+
// (對齊 hover-card.stories / selection-item.stories 同名人物)
|
|
84
88
|
const reviewers = [
|
|
85
|
-
{ name: 'Ada Chen', color: 'indigo' as const },
|
|
86
|
-
{ name: '張美真', color: 'magenta' as const },
|
|
87
|
-
{ name: '林伯彥', color: 'green' as const },
|
|
88
|
-
{ name: '黃怡君', color: 'turquoise' as const },
|
|
89
|
-
{ name: '王文彬', color: 'purple' as const },
|
|
90
|
-
{ name: '李思妤', color: 'yellow' as const },
|
|
89
|
+
{ name: 'Ada Chen', color: 'indigo' as const, avatarUrl: 'https://i.pravatar.cc/48?u=ada-chen' },
|
|
90
|
+
{ name: '張美真', color: 'magenta' as const, avatarUrl: 'https://i.pravatar.cc/48?u=zhang-meizhen' },
|
|
91
|
+
{ name: '林伯彥', color: 'green' as const, avatarUrl: 'https://i.pravatar.cc/48?u=lin-boyan' },
|
|
92
|
+
{ name: '黃怡君', color: 'turquoise' as const, avatarUrl: 'https://i.pravatar.cc/48?u=huang-yijun' },
|
|
93
|
+
{ name: '王文彬', color: 'purple' as const, avatarUrl: 'https://i.pravatar.cc/48?u=wang-wenbin' },
|
|
94
|
+
{ name: '李思妤', color: 'yellow' as const, avatarUrl: 'https://i.pravatar.cc/48?u=li-siyu' },
|
|
91
95
|
]
|
|
92
96
|
|
|
93
97
|
export const AvatarStackOverflow: Story = {
|
|
@@ -100,7 +104,7 @@ export const AvatarStackOverflow: Story = {
|
|
|
100
104
|
<div className="flex items-center">
|
|
101
105
|
{reviewers.slice(0, 3).map((p, i) => (
|
|
102
106
|
<span key={p.name} className={i > 0 ? '-ml-1.5' : ''}>
|
|
103
|
-
<Avatar alt={p.name} color={p.color} size={24} hoverCard={personHoverCard(p)} />
|
|
107
|
+
<Avatar src={p.avatarUrl} alt={p.name} color={p.color} size={24} hoverCard={personHoverCard(p)} />
|
|
104
108
|
</span>
|
|
105
109
|
))}
|
|
106
110
|
<span className="-ml-1.5">
|
|
@@ -108,7 +112,7 @@ export const AvatarStackOverflow: Story = {
|
|
|
108
112
|
<div className="flex flex-col gap-1 min-w-[160px] text-caption">
|
|
109
113
|
{reviewers.slice(3).map((p) => (
|
|
110
114
|
<div key={p.name} className="flex items-center gap-2">
|
|
111
|
-
<Avatar alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
115
|
+
<Avatar src={p.avatarUrl} alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
112
116
|
<span>{p.name}</span>
|
|
113
117
|
</div>
|
|
114
118
|
))}
|
|
@@ -163,76 +167,80 @@ const rows = [
|
|
|
163
167
|
{
|
|
164
168
|
title: '登入頁改版',
|
|
165
169
|
assignees: [
|
|
166
|
-
{ name: 'Ada Chen', color: 'indigo' as const },
|
|
167
|
-
{ name: '張美真', color: 'magenta' as const },
|
|
170
|
+
{ name: 'Ada Chen', color: 'indigo' as const, avatarUrl: 'https://i.pravatar.cc/48?u=ada-chen' },
|
|
171
|
+
{ name: '張美真', color: 'magenta' as const, avatarUrl: 'https://i.pravatar.cc/48?u=zhang-meizhen' },
|
|
168
172
|
],
|
|
169
173
|
},
|
|
170
174
|
{
|
|
171
175
|
title: 'Stripe 金流串接',
|
|
172
176
|
assignees: [
|
|
173
|
-
{ name: '林伯彥', color: 'green' as const },
|
|
174
|
-
{ name: '黃怡君', color: 'turquoise' as const },
|
|
175
|
-
{ name: '王文彬', color: 'purple' as const },
|
|
176
|
-
{ name: '李思妤', color: 'yellow' as const },
|
|
177
|
-
{ name: '吳冠霆', color: 'red' as const },
|
|
177
|
+
{ name: '林伯彥', color: 'green' as const, avatarUrl: 'https://i.pravatar.cc/48?u=lin-boyan' },
|
|
178
|
+
{ name: '黃怡君', color: 'turquoise' as const, avatarUrl: 'https://i.pravatar.cc/48?u=huang-yijun' },
|
|
179
|
+
{ name: '王文彬', color: 'purple' as const, avatarUrl: 'https://i.pravatar.cc/48?u=wang-wenbin' },
|
|
180
|
+
{ name: '李思妤', color: 'yellow' as const, avatarUrl: 'https://i.pravatar.cc/48?u=li-siyu' },
|
|
181
|
+
{ name: '吳冠霆', color: 'red' as const, avatarUrl: 'https://i.pravatar.cc/48?u=wu-guanting' },
|
|
178
182
|
],
|
|
179
183
|
},
|
|
180
184
|
{
|
|
181
185
|
title: '行銷活動著陸頁',
|
|
182
186
|
assignees: [
|
|
183
|
-
{ name: '蔡佳芸', color: 'blue' as const },
|
|
184
|
-
{ name: '陳俊宇', color: 'purple' as const },
|
|
185
|
-
{ name: '周思涵', color: 'magenta' as const },
|
|
187
|
+
{ name: '蔡佳芸', color: 'blue' as const, avatarUrl: 'https://i.pravatar.cc/48?u=tsai-chiayun' },
|
|
188
|
+
{ name: '陳俊宇', color: 'purple' as const, avatarUrl: 'https://i.pravatar.cc/48?u=chen-chunyu' },
|
|
189
|
+
{ name: '周思涵', color: 'magenta' as const, avatarUrl: 'https://i.pravatar.cc/48?u=chou-szuhan' },
|
|
186
190
|
],
|
|
187
191
|
},
|
|
188
192
|
]
|
|
189
193
|
|
|
194
|
+
// 2026-07-14 audit(R1 A.2):手刻 table markup → 消費真 <DataTable>(對齊 ProgressBar
|
|
195
|
+
// InlineTableCell 同款 consumer-自訂-cell 模式;columns 不設 meta.type 走自訂 cell)。
|
|
196
|
+
|
|
197
|
+
type AssigneeRow = (typeof rows)[number]
|
|
198
|
+
|
|
199
|
+
const assigneeColumns: ColumnDef<AssigneeRow>[] = [
|
|
200
|
+
{
|
|
201
|
+
id: 'title',
|
|
202
|
+
header: '任務',
|
|
203
|
+
cell: ({ row }) => row.original.title,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'assignees',
|
|
207
|
+
header: '負責人',
|
|
208
|
+
meta: { width: 180 },
|
|
209
|
+
cell: ({ row }) => {
|
|
210
|
+
const visible = row.original.assignees.slice(0, 2)
|
|
211
|
+
const hidden = row.original.assignees.slice(2)
|
|
212
|
+
return (
|
|
213
|
+
<div className="flex items-center">
|
|
214
|
+
{visible.map((p, i) => (
|
|
215
|
+
<span key={p.name} className={i > 0 ? '-ml-1.5' : ''}>
|
|
216
|
+
<Avatar src={p.avatarUrl} alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
217
|
+
</span>
|
|
218
|
+
))}
|
|
219
|
+
{hidden.length > 0 && (
|
|
220
|
+
<span className="-ml-1.5">
|
|
221
|
+
<OverflowIndicator count={hidden.length} shape="circle" size="sm">
|
|
222
|
+
<div className="flex flex-col gap-1 min-w-[140px]">
|
|
223
|
+
{hidden.map((p) => (
|
|
224
|
+
<div key={p.name} className="flex items-center gap-2">
|
|
225
|
+
<Avatar src={p.avatarUrl} alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
226
|
+
<span>{p.name}</span>
|
|
227
|
+
</div>
|
|
228
|
+
))}
|
|
229
|
+
</div>
|
|
230
|
+
</OverflowIndicator>
|
|
231
|
+
</span>
|
|
232
|
+
)}
|
|
233
|
+
</div>
|
|
234
|
+
)
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
]
|
|
238
|
+
|
|
190
239
|
export const TableRowAssignees: Story = {
|
|
191
240
|
name: 'DataTable 人員欄位',
|
|
192
241
|
render: () => (
|
|
193
|
-
<div className="
|
|
194
|
-
<
|
|
195
|
-
<thead className="bg-muted text-fg-secondary">
|
|
196
|
-
<tr>
|
|
197
|
-
<th className="text-left px-3 py-2 font-medium">任務</th>
|
|
198
|
-
<th className="text-left px-3 py-2 font-medium">負責人</th>
|
|
199
|
-
</tr>
|
|
200
|
-
</thead>
|
|
201
|
-
<tbody>
|
|
202
|
-
{rows.map((r) => {
|
|
203
|
-
const visible = r.assignees.slice(0, 2)
|
|
204
|
-
const hidden = r.assignees.slice(2)
|
|
205
|
-
return (
|
|
206
|
-
<tr key={r.title} className="border-t border-divider">
|
|
207
|
-
<td className="px-3 py-2">{r.title}</td>
|
|
208
|
-
<td className="px-3 py-2">
|
|
209
|
-
<div className="flex items-center">
|
|
210
|
-
{visible.map((p, i) => (
|
|
211
|
-
<span key={p.name} className={i > 0 ? '-ml-1.5' : ''}>
|
|
212
|
-
<Avatar alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
213
|
-
</span>
|
|
214
|
-
))}
|
|
215
|
-
{hidden.length > 0 && (
|
|
216
|
-
<span className="-ml-1.5">
|
|
217
|
-
<OverflowIndicator count={hidden.length} shape="circle" size="sm">
|
|
218
|
-
<div className="flex flex-col gap-1 min-w-[140px]">
|
|
219
|
-
{hidden.map((p) => (
|
|
220
|
-
<div key={p.name} className="flex items-center gap-2">
|
|
221
|
-
<Avatar alt={p.name} color={p.color} size={20} hoverCard={personHoverCard(p)} />
|
|
222
|
-
<span>{p.name}</span>
|
|
223
|
-
</div>
|
|
224
|
-
))}
|
|
225
|
-
</div>
|
|
226
|
-
</OverflowIndicator>
|
|
227
|
-
</span>
|
|
228
|
-
)}
|
|
229
|
-
</div>
|
|
230
|
-
</td>
|
|
231
|
-
</tr>
|
|
232
|
-
)
|
|
233
|
-
})}
|
|
234
|
-
</tbody>
|
|
235
|
-
</table>
|
|
242
|
+
<div className="max-w-2xl">
|
|
243
|
+
<DataTable columns={assigneeColumns} data={rows} getRowId={(r) => r.title} height="auto" />
|
|
236
244
|
</div>
|
|
237
245
|
),
|
|
238
246
|
}
|