@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +210 -0
- package/CLAUDE.md +17 -191
- package/cli-init.mjs +30 -2
- package/dist/components/Accordion/accordion.d.ts +2 -2
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Avatar/avatar.js +1 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button-group.d.ts +2 -2
- package/dist/components/Button/button-group.d.ts.map +1 -1
- package/dist/components/Button/button-group.js +2 -2
- package/dist/components/Button/button-group.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -1
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +1 -1
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +14 -8
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +64 -37
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js +21 -14
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +2 -2
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +49 -10
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +15 -6
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +13 -7
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +11 -2
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts +5 -5
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +41 -38
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +1 -17
- package/dist/components/DataTable/column-types.d.ts.map +1 -1
- package/dist/components/DataTable/column-types.js.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +3 -4
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +2 -2
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +44 -32
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +3 -3
- package/dist/components/DatePicker/date-picker.js +4 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.d.ts +3 -3
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
- package/dist/components/DescriptionList/description-list.js +6 -6
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +2 -2
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +16 -10
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-types.d.ts +2 -2
- package/dist/components/Field/field-types.d.ts.map +1 -1
- package/dist/components/Field/field-types.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +20 -4
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +30 -31
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +25 -3
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/use-form-validation.d.ts +1 -1
- package/dist/components/Field/use-form-validation.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +2 -5
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +5 -1
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +2 -1
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +2 -2
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +4 -2
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +104 -62
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +6 -6
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +5 -5
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +3 -3
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +17 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +7 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +12 -1
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +7 -5
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +1 -1
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +3 -3
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +1 -1
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +4 -0
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts +16 -6
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +17 -5
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +17 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +17 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
- package/dist/components/SelectionControl/boolean-value.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +2 -2
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.js +2 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +6 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +6 -4
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +19 -5
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +4 -4
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -1
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +73 -23
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts +3 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +2 -2
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +4 -4
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +15 -15
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +4 -4
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -5
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +27 -23
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +16 -0
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/drag-visual.d.ts +2 -2
- package/dist/lib/drag-visual.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +21 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +3 -3
- package/dist/tokens/categorical-color.d.ts.map +1 -1
- package/dist/tokens/categorical-color.js +2 -2
- package/dist/tokens/categorical-color.js.map +1 -1
- package/ds-canonical/fork/AGENTS.md +213 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
- package/ds-canonical/fork/codex/hooks.json +16 -0
- package/ds-canonical/fork/governance.lock +22 -7
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/fork/manifest.json +10 -1
- package/ds-canonical/fork/preamble.md +3 -2
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
- package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
- package/ds-canonical/references/certified-surfaces.md +20 -0
- package/ds-canonical/references/preflight-gate-baseline.json +5 -0
- package/ds-canonical/references/principle-dim-map.json +20 -2
- package/ds-canonical/references/props-naming.md +2 -1
- package/ds-canonical/references/ssot-index.md +2 -2
- package/ds-canonical/references/story-baseline-registry.json +2 -2
- package/ds-canonical/rules/story-rules.md +1 -1
- package/ds-canonical/rules/ui-development.md +2 -1
- package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
- package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
- package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
- package/ds-story-manifest.json +21 -21
- package/llms-full.txt +3 -3
- package/llms.txt +1 -1
- package/package.json +2 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
- package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
- package/src/components/Accordion/accordion.spec.md +10 -1
- package/src/components/Accordion/accordion.stories.tsx +10 -5
- package/src/components/Accordion/accordion.tsx +7 -2
- package/src/components/Alert/alert.principles.stories.tsx +2 -8
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
- package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
- package/src/components/AppShell/app-shell.spec.md +4 -0
- package/src/components/AppShell/app-shell.stories.tsx +4 -5
- package/src/components/Avatar/avatar.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -2
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
- package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
- package/src/components/Button/button-group.tsx +4 -4
- package/src/components/Button/button.anatomy.stories.tsx +26 -7
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.stories.tsx +22 -28
- package/src/components/Button/button.tsx +2 -1
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +1 -1
- package/src/components/Carousel/carousel.spec.md +17 -1
- package/src/components/Carousel/carousel.tsx +93 -42
- package/src/components/Checkbox/checkbox-group.tsx +26 -15
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
- package/src/components/Checkbox/checkbox.spec.md +12 -3
- package/src/components/Checkbox/checkbox.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.tsx +79 -19
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
- package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
- package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
- package/src/components/Combobox/combobox.spec.md +6 -2
- package/src/components/Combobox/combobox.stories.tsx +9 -36
- package/src/components/Combobox/combobox.tsx +42 -27
- package/src/components/Command/command.spec.md +3 -3
- package/src/components/Command/command.tsx +9 -2
- package/src/components/DataTable/cell-registry.tsx +75 -76
- package/src/components/DataTable/column-types.ts +4 -17
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
- package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
- package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
- package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
- package/src/components/DataTable/data-table.css +2 -3
- package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
- package/src/components/DataTable/data-table.spec.md +7 -7
- package/src/components/DataTable/data-table.stories.tsx +39 -29
- package/src/components/DataTable/data-table.tsx +90 -67
- package/src/components/DataTable/filter-operators.spec.md +2 -0
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
- package/src/components/DatePicker/date-picker.spec.md +9 -9
- package/src/components/DatePicker/date-picker.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.tsx +13 -13
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +12 -12
- package/src/components/DescriptionList/description-list.stories.tsx +3 -3
- package/src/components/DescriptionList/description-list.tsx +10 -10
- package/src/components/Dialog/dialog.tsx +4 -1
- package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +44 -37
- package/src/components/Field/field-types.ts +14 -12
- package/src/components/Field/field-wrapper.tsx +59 -43
- package/src/components/Field/field.anatomy.stories.tsx +6 -6
- package/src/components/Field/field.principles.stories.tsx +5 -28
- package/src/components/Field/field.spec.md +4 -4
- package/src/components/Field/field.stories.tsx +103 -72
- package/src/components/Field/field.tsx +36 -4
- package/src/components/Field/form-validation.spec.md +2 -0
- package/src/components/Field/use-form-validation.ts +1 -1
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
- package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
- package/src/components/FileItem/file-item.tsx +10 -8
- package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
- package/src/components/FileUpload/file-upload.spec.md +3 -2
- package/src/components/FileUpload/file-upload.tsx +5 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.spec.md +1 -1
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.tsx +3 -2
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
- package/src/components/HoverCard/hover-card.spec.md +2 -2
- package/src/components/HoverCard/hover-card.tsx +4 -2
- package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
- package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
- package/src/components/InlineEdit/inline-edit.spec.md +71 -46
- package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
- package/src/components/InlineEdit/inline-edit.tsx +211 -125
- package/src/components/Input/input.anatomy.stories.tsx +15 -15
- package/src/components/Input/input.principles.stories.tsx +3 -3
- package/src/components/Input/input.spec.md +4 -4
- package/src/components/Input/input.stories.tsx +3 -3
- package/src/components/Input/input.tsx +13 -13
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.spec.md +6 -2
- package/src/components/LinkInput/link-input.stories.tsx +8 -8
- package/src/components/LinkInput/link-input.tsx +21 -19
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.tsx +8 -2
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
- package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.spec.md +6 -6
- package/src/components/NumberInput/number-input.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.tsx +17 -5
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
- package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
- package/src/components/PeoplePicker/people-picker.tsx +39 -20
- package/src/components/PeoplePicker/person-display.tsx +3 -3
- package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
- package/src/components/Popover/popover.principles.stories.tsx +49 -28
- package/src/components/Popover/popover.spec.md +4 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
- package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
- package/src/components/README.md +1 -0
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
- package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
- package/src/components/RadioGroup/radio-group.tsx +19 -14
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
- package/src/components/Rating/rating.principles.stories.tsx +3 -3
- package/src/components/Rating/rating.spec.md +2 -2
- package/src/components/Rating/rating.stories.tsx +4 -18
- package/src/components/Rating/rating.tsx +5 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +5 -2
- package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
- package/src/components/SegmentedControl/segmented-control.tsx +6 -3
- package/src/components/Select/select.anatomy.stories.tsx +13 -7
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +9 -1
- package/src/components/Select/select.stories.tsx +41 -27
- package/src/components/Select/select.tsx +44 -26
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
- package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
- package/src/components/SelectMenu/select-menu.tsx +38 -5
- package/src/components/SelectionControl/boolean-value.tsx +2 -2
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
- package/src/components/Separator/separator.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
- package/src/components/Sheet/sheet.tsx +4 -1
- package/src/components/Sidebar/sidebar.tsx +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
- package/src/components/Slider/slider.principles.stories.tsx +6 -6
- package/src/components/Slider/slider.spec.md +13 -1
- package/src/components/Slider/slider.stories.tsx +44 -32
- package/src/components/Slider/slider.tsx +13 -4
- package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +4 -2
- package/src/components/Steps/steps.stories.tsx +4 -56
- package/src/components/Steps/steps.tsx +31 -7
- package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +4 -4
- package/src/components/Switch/switch.stories.tsx +3 -3
- package/src/components/Switch/switch.tsx +16 -10
- package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
- package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
- package/src/components/Tabs/tabs.spec.md +5 -2
- package/src/components/Tabs/tabs.stories.tsx +36 -44
- package/src/components/Tabs/tabs.tsx +101 -36
- package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
- package/src/components/Tag/tag.principles.stories.tsx +4 -4
- package/src/components/Tag/tag.spec.md +3 -1
- package/src/components/Tag/tag.tsx +5 -3
- package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
- package/src/components/Textarea/textarea.spec.md +5 -5
- package/src/components/Textarea/textarea.tsx +24 -24
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
- package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
- package/src/components/TimePicker/time-picker.spec.md +6 -5
- package/src/components/TimePicker/time-picker.stories.tsx +3 -3
- package/src/components/TimePicker/time-picker.tsx +24 -14
- package/src/components/Toast/toast.principles.stories.tsx +1 -1
- package/src/components/Toast/toast.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
- package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.spec.md +9 -3
- package/src/components/Tooltip/tooltip.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.tsx +12 -2
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
- package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
- package/src/components/TreeView/tree-view.spec.md +8 -6
- package/src/components/TreeView/tree-view.stories.tsx +9 -43
- package/src/components/TreeView/tree-view.tsx +36 -0
- package/src/index.ts +13 -10
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +19 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
- package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
- package/src/tokens/categorical-color.ts +5 -5
- package/src/tokens/color/color.spec.md +4 -4
- package/src/tokens/color/primitives.css +9 -2
- package/src/tokens/opacity/opacity.spec.md +1 -1
- package/src/tokens/orphan-tokens.spec.md +1 -1
- package/src/tokens/typography/typography.spec.md +2 -0
- package/src/tokens/uiSize/uiSize.css +5 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -68,7 +68,7 @@ const ISSUE_COLUMNS = [
|
|
|
68
68
|
*
|
|
69
69
|
* Per codex Layer B D3(2026-05-20):row-driven Aside trigger 才符合 Linear/Notion/Jira/Airtable
|
|
70
70
|
* production 真實情境。row 右側 dedicated action button(`Button variant="text" size="xs" iconOnly`
|
|
71
|
-
* per data-table.spec
|
|
71
|
+
* per data-table.spec L153 rowActions canonical)→ click 開 Aside + 被選 issue active visual(pressed prop)。
|
|
72
72
|
* AppShell header toggle 降級為 secondary show/hide 不是主入口。
|
|
73
73
|
*/
|
|
74
74
|
function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: string; asideOpen: boolean; onSelectIssue: (issue: Issue) => void }) {
|
|
@@ -118,7 +118,6 @@ function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: str
|
|
|
118
118
|
</PopoverTrigger>
|
|
119
119
|
<PopoverContent align="end" className="w-auto p-0">
|
|
120
120
|
<DataTableFilterPanel
|
|
121
|
-
mode="flat"
|
|
122
121
|
columns={ISSUE_COLUMNS as any}
|
|
123
122
|
value={filterTree}
|
|
124
123
|
onChange={setFilterTree}
|
|
@@ -150,7 +149,7 @@ function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: str
|
|
|
150
149
|
</div>
|
|
151
150
|
</div>
|
|
152
151
|
{/* DataTable:naked structure,layoutSpace 規則 1B 父層 mx 對齊 chrome 內容左右邊界。
|
|
153
|
-
rowActions:per data-table.spec
|
|
152
|
+
rowActions:per data-table.spec L153 rowActions canonical(Button text xs iconOnly,固定 24px)+
|
|
154
153
|
pressed={row.id === selectedId} 顯示當前選中(per codex D3 active visual)。 */}
|
|
155
154
|
<div className="flex-1 min-h-0 mx-[var(--layout-space-loose)] mb-[var(--layout-space-loose)]">
|
|
156
155
|
<DataTable
|
|
@@ -226,7 +225,7 @@ function IssueDetail({ issue }: { issue: Issue | null }) {
|
|
|
226
225
|
<Tag size="sm" color={PRIORITY_COLOR[issue.priority]}>{issue.priority}</Tag>
|
|
227
226
|
</div>
|
|
228
227
|
</div>
|
|
229
|
-
<DescriptionList
|
|
228
|
+
<DescriptionList orientation="horizontal" divided>
|
|
230
229
|
<DescriptionItem label="Assignee">{issue.assignee}</DescriptionItem>
|
|
231
230
|
<DescriptionItem label="Due">{issue.due}</DescriptionItem>
|
|
232
231
|
</DescriptionList>
|
|
@@ -374,7 +373,7 @@ export const PrimarySidebarWithTabs: Story = {
|
|
|
374
373
|
/**
|
|
375
374
|
* primary-header mode(GitHub / Gmail / Slack 派)— global header 橫跨頂部 + local header 仍在 main col 頂。
|
|
376
375
|
*
|
|
377
|
-
* @usage-ref: app-shell.spec.md
|
|
376
|
+
* @usage-ref: app-shell.spec.md「primary-header = primary-sidebar + 一條 global header」段(2-layer model)
|
|
378
377
|
* @usage-consumes: ChromeHeader + Sidebar viewportInsetTop + GlobalHeader + PageHeader + IssuesView
|
|
379
378
|
*
|
|
380
379
|
* 2026-05-21 v2 per user clarification「primary-header = primary-sidebar + 一條 global header」:
|
|
@@ -375,7 +375,7 @@ export const avatarMeta = {
|
|
|
375
375
|
// — item-anatomy AVATAR_SIZE 查表 / ProfileCard 40 等),無 discrete tier → 兩欄留空為 intentional 非漏填
|
|
376
376
|
variants: {},
|
|
377
377
|
sizes: {},
|
|
378
|
-
states: ['default', 'focus-visible', 'disabled'], // 2026-06-11 R2:本身無自有 hover/active(spec
|
|
378
|
+
states: ['default', 'focus-visible', 'disabled'], // 2026-06-11 R2:本身無自有 hover/active(spec「StateBehavior 範疇」段;hoverCard 互動屬 HoverCard),
|
|
379
379
|
tokens: {
|
|
380
380
|
bg: ['bg-surface-raised'],
|
|
381
381
|
fg: ['--foreground', '--on-emphasis'],
|
|
@@ -379,14 +379,14 @@ Badge 是**計數 / 狀態視覺指示器**,本身**非互動元件**:
|
|
|
379
379
|
- Badge 通常依附在互動元件上(Button / Nav Item),那些元件有自己的 state——Badge 隨父層視覺連動,不擁有獨立 state。
|
|
380
380
|
- 計數變化(`count` 更新)屬資料更新不是 UI state 切換。
|
|
381
381
|
|
|
382
|
-
對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix`。
|
|
382
|
+
對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix` + `Accessibility`。
|
|
383
383
|
|
|
384
384
|
---
|
|
385
385
|
|
|
386
386
|
## 相關
|
|
387
387
|
|
|
388
388
|
- `../Tag/tag.spec.md` — 分類標籤、狀態標記(Badge vs Tag 的詳細對照在本 spec 定位段落)
|
|
389
|
-
- `../Avatar/avatar.spec.md` — `badgeCount` 內部消費 `<Badge variant="critical">`(遵循本 spec);`status` 是 Avatar 自有 presence
|
|
389
|
+
- `../Avatar/avatar.spec.md` — `badgeCount` 內部消費 `<Badge variant="critical">`(遵循本 spec);`status` 是 Avatar 自有 presence dot(內部 `span` + inline backgroundColor,非 Badge 系統),兩者可並存,詳該 spec
|
|
390
390
|
- `../Button/button.spec.md` — iconOnly Button + Badge overlay 通知 icon 的組合模式
|
|
391
391
|
- `../Chip/chip.spec.md` — 可互動 filter(不是 Badge 的用途)
|
|
392
392
|
- `../CircularProgress/circular-progress.spec.md` — Loading 狀態指示(取代 Spinner)
|
|
@@ -342,19 +342,23 @@ export const StateBehavior: Story = {
|
|
|
342
342
|
<Breadcrumb>
|
|
343
343
|
<BreadcrumbList>
|
|
344
344
|
<BreadcrumbItem>
|
|
345
|
-
<BreadcrumbLink href="#"
|
|
345
|
+
<BreadcrumbLink href="#">團隊空間</BreadcrumbLink>
|
|
346
346
|
</BreadcrumbItem>
|
|
347
347
|
<BreadcrumbSeparator />
|
|
348
348
|
<BreadcrumbItem>
|
|
349
|
-
<BreadcrumbLink href="#"
|
|
349
|
+
<BreadcrumbLink href="#">設計系統</BreadcrumbLink>
|
|
350
350
|
</BreadcrumbItem>
|
|
351
351
|
<BreadcrumbSeparator />
|
|
352
352
|
<BreadcrumbItem>
|
|
353
|
-
<BreadcrumbPage
|
|
353
|
+
<BreadcrumbPage>元件規格</BreadcrumbPage>
|
|
354
354
|
</BreadcrumbItem>
|
|
355
355
|
</BreadcrumbList>
|
|
356
356
|
</Breadcrumb>
|
|
357
357
|
</div>
|
|
358
|
+
<p className="text-footnote text-fg-muted mt-3">
|
|
359
|
+
「團隊空間」「設計系統」為可點連結(預設 fg-secondary,移上去 hover 轉 primary-hover);
|
|
360
|
+
末項「元件規格」為當前頁(foreground,不可點)。
|
|
361
|
+
</p>
|
|
358
362
|
</div>
|
|
359
363
|
</div>
|
|
360
364
|
),
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
DropdownMenuContent,
|
|
19
19
|
DropdownMenuItem,
|
|
20
20
|
} from '@/design-system/components/DropdownMenu/dropdown-menu'
|
|
21
|
-
import { Tabs, TabsList, TabsTrigger } from '@/design-system/components/Tabs/tabs'
|
|
21
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/design-system/components/Tabs/tabs'
|
|
22
22
|
import { Button } from '@/design-system/components/Button/button'
|
|
23
23
|
|
|
24
24
|
const meta: Meta = {
|
|
@@ -159,6 +159,9 @@ export const UsageGuidance: Story = {
|
|
|
159
159
|
<TabsTrigger value="customers">顧客</TabsTrigger>
|
|
160
160
|
<TabsTrigger value="products">產品</TabsTrigger>
|
|
161
161
|
</TabsList>
|
|
162
|
+
<TabsContent value="orders" className="text-body text-fg-muted mt-2">訂單列表、篩選與批次出貨</TabsContent>
|
|
163
|
+
<TabsContent value="customers" className="text-body text-fg-muted mt-2">顧客名單、分群與生命週期價值</TabsContent>
|
|
164
|
+
<TabsContent value="products" className="text-body text-fg-muted mt-2">商品目錄、庫存與上下架狀態</TabsContent>
|
|
162
165
|
</Tabs>
|
|
163
166
|
</div>
|
|
164
167
|
</Rule>
|
|
@@ -190,7 +190,7 @@ export const DeclarativeAutoCollapse: Story = {
|
|
|
190
190
|
<Breadcrumb>
|
|
191
191
|
<BreadcrumbList
|
|
192
192
|
items={[
|
|
193
|
-
{ label: '
|
|
193
|
+
{ label: 'Global Platform Infrastructure Group', href: '/org' },
|
|
194
194
|
{ label: 'Product Engineering Team', href: '/team' },
|
|
195
195
|
{ label: 'Design System Component Refactor Sprint 23' },
|
|
196
196
|
]}
|
|
@@ -46,7 +46,7 @@ export const Overview: Story = {
|
|
|
46
46
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
47
47
|
</>
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
onClearSelection={() => {}}
|
|
50
50
|
/>
|
|
51
51
|
</div>
|
|
52
52
|
</section>
|
|
@@ -87,7 +87,7 @@ export const Overview: Story = {
|
|
|
87
87
|
<BulkActionBar
|
|
88
88
|
selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
|
|
89
89
|
actions={<Button variant="tertiary" size="md" startIcon={Download}>下載</Button>}
|
|
90
|
-
|
|
90
|
+
onClearSelection={() => {}}
|
|
91
91
|
/>
|
|
92
92
|
</div>
|
|
93
93
|
</div>
|
|
@@ -115,7 +115,7 @@ function SelectionStateDemo() {
|
|
|
115
115
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
116
116
|
</>
|
|
117
117
|
}
|
|
118
|
-
|
|
118
|
+
onClearSelection={() => setCount(0)}
|
|
119
119
|
/>
|
|
120
120
|
{count === 0 && <span className="text-caption text-fg-muted italic px-3 py-2 inline-block">↑ count=0 → BulkActionBar 不渲染</span>}
|
|
121
121
|
</div>
|
|
@@ -162,7 +162,7 @@ function InspectorInner() {
|
|
|
162
162
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
163
163
|
</>
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
onClearSelection={() => setSelectionCount(0)}
|
|
166
166
|
/>
|
|
167
167
|
{selectionCount === 0 && <span className="text-caption text-fg-muted italic px-3 py-2 inline-block">selection=0 → 不渲染</span>}
|
|
168
168
|
</div>
|
|
@@ -196,7 +196,7 @@ export const Accessibility: Story = {
|
|
|
196
196
|
<section>
|
|
197
197
|
<H3>鍵盤(預期 consumer 在 page 層級監聽)</H3>
|
|
198
198
|
<ul className="list-disc list-inside text-caption text-fg-secondary space-y-1">
|
|
199
|
-
<li><kbd>Esc</kbd> → 觸發 <code>
|
|
199
|
+
<li><kbd>Esc</kbd> → 觸發 <code>onClearSelection()</code>(consumer 在 page-level keydown 監聽)</li>
|
|
200
200
|
<li>Tab 序:close → actions(count 是純文字 / aria 朗讀對象,非 tab stop)</li>
|
|
201
201
|
<li>Hint CTA 是 <code>{`<button>`}</code>,鍵盤可達</li>
|
|
202
202
|
</ul>
|
|
@@ -216,7 +216,7 @@ export const Accessibility: Story = {
|
|
|
216
216
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger disabled>刪除(無權限)</Button>
|
|
217
217
|
</>
|
|
218
218
|
}
|
|
219
|
-
|
|
219
|
+
onClearSelection={() => {}}
|
|
220
220
|
/>
|
|
221
221
|
</div>
|
|
222
222
|
</section>
|
|
@@ -83,7 +83,7 @@ export const UsageGuidance: Story = {
|
|
|
83
83
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
84
84
|
</>
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
onClearSelection={() => {}}
|
|
87
87
|
/>
|
|
88
88
|
<Label>↑ selection {`>`} 0 浮現,= 0 完全藏</Label>
|
|
89
89
|
</Rule>
|
|
@@ -160,7 +160,7 @@ export const ActionVariantRule: Story = {
|
|
|
160
160
|
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
161
161
|
</>
|
|
162
162
|
}
|
|
163
|
-
|
|
163
|
+
onClearSelection={() => {}}
|
|
164
164
|
/>
|
|
165
165
|
<Label>↑ tertiary 主 / tertiary danger 破壞性</Label>
|
|
166
166
|
</Rule>
|
|
@@ -177,7 +177,7 @@ export const ActionVariantRule: Story = {
|
|
|
177
177
|
<Button variant="primary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
178
178
|
</>
|
|
179
179
|
}
|
|
180
|
-
|
|
180
|
+
onClearSelection={() => {}}
|
|
181
181
|
/>
|
|
182
182
|
<Label warn>↑ 兩顆都 primary → 視覺重量過高,跟 page Submit 競爭</Label>
|
|
183
183
|
</Rule>
|
|
@@ -211,7 +211,7 @@ export const HintBannerRule: Story = {
|
|
|
211
211
|
<BulkActionBar
|
|
212
212
|
selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
|
|
213
213
|
actions={<Button variant="tertiary" size="md">下載</Button>}
|
|
214
|
-
|
|
214
|
+
onClearSelection={() => {}}
|
|
215
215
|
/>
|
|
216
216
|
</div>
|
|
217
217
|
</div>
|
|
@@ -222,7 +222,19 @@ export const HintBannerRule: Story = {
|
|
|
222
222
|
title="❌ 自刻 hint banner / 用 contrast 底色 div"
|
|
223
223
|
note="banner 是 Alert 的職責(自帶 a11y role / aria-live / 視覺一致性)。自刻會破壞跟其他 Alert 的視覺一致性,也漏 a11y"
|
|
224
224
|
>
|
|
225
|
-
<
|
|
225
|
+
<div className="border border-divider rounded-md overflow-hidden">
|
|
226
|
+
<div className="bg-info-subtle text-info-text px-[var(--layout-space-loose)] py-[var(--layout-space-tight)] text-footnote">
|
|
227
|
+
已選取本頁全部 50 個。點此選取全部 5370 個項目
|
|
228
|
+
</div>
|
|
229
|
+
<div className="border-t border-divider">
|
|
230
|
+
<BulkActionBar
|
|
231
|
+
selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
|
|
232
|
+
actions={<Button variant="tertiary" size="md">下載</Button>}
|
|
233
|
+
onClearSelection={() => {}}
|
|
234
|
+
/>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
<Label warn>↑ 手刻 div 當 banner:無 role="status" / aria-live,SR 不會朗讀狀態變化;底色跟其他 Alert 不一致;「點此選取」是純文字非可操作連結</Label>
|
|
226
238
|
</Rule>
|
|
227
239
|
|
|
228
240
|
<Rule
|
|
@@ -233,7 +245,7 @@ export const HintBannerRule: Story = {
|
|
|
233
245
|
selection={['a', 'b', 'c']}
|
|
234
246
|
hiddenByFilter={2}
|
|
235
247
|
actions={<Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>}
|
|
236
|
-
|
|
248
|
+
onClearSelection={() => {}}
|
|
237
249
|
/>
|
|
238
250
|
<Label>↑ count 文字 inline:「已選 3 項 · 2 個被 filter 隱藏」</Label>
|
|
239
251
|
</Rule>
|
|
@@ -81,9 +81,9 @@ benchmark:
|
|
|
81
81
|
|
|
82
82
|
### Slot
|
|
83
83
|
|
|
84
|
-
- **`actions`**:consumer 提供 **md** Buttons(size rationale 見「Size canonical」)
|
|
84
|
+
- **`actions`**:consumer 提供 **md** Buttons(size rationale 見「Size canonical」);**一律 `variant=tertiary`**(含 destructive — `Trash` 等 icon + label 已辨識危險)— **不用 primary、destructive 不上 danger 紅填色**(2026-07-17 user 拍板:批次刪除鈕點下去是**開確認 dialog**非直接刪,紅色強調留給 dialog 內確認最終不可逆 action;對齊 UX Movement / GitLab Pajamas「紅留給不可逆最終確認」+ button.spec.md「Inline destructive 不用高強調」)
|
|
85
85
|
- **count 區**:`已選 {N} 項`(內建)+ inline filter hidden status `· {M} 個被 filter 隱藏`(`hiddenByFilter` prop 傳入時)
|
|
86
|
-
- **clear**:`<Button iconOnly size=md variant=text dismiss />`(內建,觸發 `
|
|
86
|
+
- **clear**:`<Button iconOnly size=md variant=text dismiss />`(內建,觸發 `onClearSelection`)
|
|
87
87
|
|
|
88
88
|
#### Size canonical(2026-05-04 升 SSOT)
|
|
89
89
|
|
|
@@ -143,7 +143,7 @@ interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
143
143
|
/** 已選 ID;length === 0 且無 totalSelected 時自動隱藏(回 null,完整判準見「Extend dataset pattern」) */
|
|
144
144
|
selection: readonly string[]
|
|
145
145
|
/** Clear 觸發,user 點 X icon(consumer 在 page-level 監聽 Esc 觸發) */
|
|
146
|
-
|
|
146
|
+
onClearSelection?: () => void
|
|
147
147
|
/** 批次 actions(consumer 提供 md Button,variant=tertiary 或 tertiary+danger,不用 primary) */
|
|
148
148
|
actions?: React.ReactNode
|
|
149
149
|
/** Filter 模式:hidden 數量,顯示在 count 區 inline 「已選 {N} 項 · {M} 個被 filter 隱藏」 */
|
|
@@ -169,6 +169,16 @@ interface BulkActionBarLabels {
|
|
|
169
169
|
|
|
170
170
|
**Hint banner(擴 dataset 提示)不在本 API**:由 consumer 用 `<Alert variant="info" placement="fixed">` 配 ReactNode title 帶 inline link 自組,黏在 BulkActionBar 上方。Alert / Notice 的 `title` + `description` 已支援 ReactNode(2026-04-28)。
|
|
171
171
|
|
|
172
|
+
### 批次操作進行中(loading / 防重複提交 / 選取保留)
|
|
173
|
+
|
|
174
|
+
`actions` 由 consumer 注入 ReactNode,**批次操作的非同步生命週期由 consumer 擁有**(BulkActionBar 是 stateless 呈現層,不介入 action 執行):
|
|
175
|
+
|
|
176
|
+
- **Loading**:非同步 action(批次刪除 / 匯出)進行中,對應 action Button 傳 `loading`(既有 API,spinner + 自動 disabled)——不在 bar 內另加全域 spinner
|
|
177
|
+
- **防重複提交**:同一批次操作進行中,consumer 對該 action Button 設 `loading` / `disabled` 阻止連點觸發多次(語義同 `../Field/form-validation.spec.md` double-submit 防護,但 owner 在 consumer 而非 bar)
|
|
178
|
+
- **選取保留**:操作進行中 `selection` 維持不變、bar 持續可見;**成功**後才由 consumer 清空 `selection`(觸發 bar 自動隱藏),**失敗**則保留選取讓 user 重試
|
|
179
|
+
|
|
180
|
+
對齊 Polaris BulkActions(action `loading` 由 consumer 提供)/ Material DataGrid batch action 慣例。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
181
|
+
|
|
172
182
|
### Extend dataset pattern(totalSelected)
|
|
173
183
|
|
|
174
184
|
「本頁全選 → hint 點擊 → 擴選整個 dataset」2-step 後,consumer 把 `totalSelected` 設為 dataset 真總數,count 區改顯示該值(否則 fallback `selection.length`)——避免 Alert 顯「已選 5370」但 bar 仍顯「已選 50」的不同步(2026-05-13 ship)。對齊 Gmail / Linear / Notion 全選 dataset hint pattern。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
@@ -183,7 +193,7 @@ interface BulkActionBarLabels {
|
|
|
183
193
|
- count 文字用 `aria-live="polite"` + `aria-atomic="true"`(selection 變更時 SR 整句重讀「已選 3 項」)
|
|
184
194
|
- Clear button:`aria-label="清除選取"`
|
|
185
195
|
- Hint banner 用 `role="status"` + `aria-live="polite"`(state 切換時通知)
|
|
186
|
-
- 鍵盤:Esc → `
|
|
196
|
+
- 鍵盤:Esc → `onClearSelection()`(consumer 應監聽 page-level keydown 觸發);Tab 序按 DOM 順序 = clear(X)→ actions(count 是純文字 span,非互動元素 → 不參與 Tab)
|
|
187
197
|
- Disabled action(無權限等)用 Button `disabled` + tooltip 解釋,**不藏 action**(避免 user 困惑)
|
|
188
198
|
|
|
189
199
|
---
|
|
@@ -194,7 +204,7 @@ interface BulkActionBarLabels {
|
|
|
194
204
|
- **底色**:**無底色 contrast**,跟 page 同色(`bg-canvas` / `bg-surface` 視 placement 繼承)。對齊 Notion / Linear minimalist — 用文字內容切換呈現「mode」,**不**用底色 highlight。**不像 Polaris 那種顯著底色變化** <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
195
205
|
- **邊界**:**無外框邊界**(融入 page chrome)— 恆 **`border-top` border-divider 切割 layout**(bar 是 page 結構,不是 floating overlay,不用 box-shadow 製造「浮層」誤導)。top-toolbar 變體為未來項(見「Size canonical」)
|
|
196
206
|
- **與 table 的關係**:inline composition — bar 接在 DataTable 下方,toolbar 永遠保留(見「Placement」)
|
|
197
|
-
- **Action variant
|
|
207
|
+
- **Action variant**:**一律 `tertiary`**(含 destructive,icon+label 辨識危險)— **不用 primary、不用 danger 紅填色**(紅色強調留給 dialog 內確認最終 action,見「Slot」rationale)
|
|
198
208
|
|
|
199
209
|
---
|
|
200
210
|
|
|
@@ -21,13 +21,13 @@ export const Default: Story = {
|
|
|
21
21
|
return (
|
|
22
22
|
<BulkActionBar
|
|
23
23
|
selection={selection}
|
|
24
|
-
|
|
24
|
+
onClearSelection={() => setSelection([])}
|
|
25
25
|
actions={
|
|
26
26
|
<>
|
|
27
27
|
<Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>
|
|
28
28
|
<Button variant="tertiary" size="md" startIcon={TagIcon}>加標籤</Button>
|
|
29
29
|
<Button variant="tertiary" size="md" startIcon={MoveRight}>移動</Button>
|
|
30
|
-
<Button variant="tertiary" size="md" startIcon={Trash2}
|
|
30
|
+
<Button variant="tertiary" size="md" startIcon={Trash2}>刪除</Button>
|
|
31
31
|
</>
|
|
32
32
|
}
|
|
33
33
|
/>
|
|
@@ -35,26 +35,10 @@ export const Default: Story = {
|
|
|
35
35
|
},
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const [selection, setSelection] = useState<string[]>(['issue-1', 'issue-2', 'issue-3'])
|
|
43
|
-
return (
|
|
44
|
-
<BulkActionBar
|
|
45
|
-
selection={selection}
|
|
46
|
-
onClear={() => setSelection([])}
|
|
47
|
-
hiddenByFilter={2}
|
|
48
|
-
actions={
|
|
49
|
-
<>
|
|
50
|
-
<Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>
|
|
51
|
-
<Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
|
|
52
|
-
</>
|
|
53
|
-
}
|
|
54
|
-
/>
|
|
55
|
-
)
|
|
56
|
-
},
|
|
57
|
-
}
|
|
38
|
+
// @story-trait-rationale: WithFilterHidden(selection=3 + hiddenByFilter=2)retired 2026-07-17 per audit Dim 24 —
|
|
39
|
+
// principles.stories.tsx HintBannerRule 第三 Rule 已用同情境(selection 3 + hiddenByFilter=2)且多教「filter hidden
|
|
40
|
+
// inline 進 count 區、不開 hint banner」規則;展示版無新增約束(earn-existence 2-test 雙 NO)→ retire。
|
|
41
|
+
// hiddenByFilter inline 呈現 canonical home = principles HintBannerRule。
|
|
58
42
|
|
|
59
43
|
// Hint banner via Alert primitive(擴 dataset 提示)— 對齊 ref 圖
|
|
60
44
|
// hint banner 唯一 trigger condition:本頁全選 + 還有 dataset 沒選到
|
|
@@ -108,11 +92,11 @@ export const WithExtendDatasetHint: Story = {
|
|
|
108
92
|
<BulkActionBar
|
|
109
93
|
selection={selection}
|
|
110
94
|
totalSelected={allSelected ? TOTAL : undefined}
|
|
111
|
-
|
|
95
|
+
onClearSelection={() => { setSelection([]); setAllSelected(false) }}
|
|
112
96
|
actions={
|
|
113
97
|
<>
|
|
114
98
|
<Button variant="tertiary" size="md" startIcon={Download}>下載</Button>
|
|
115
|
-
<Button variant="tertiary" size="md" startIcon={Trash2}
|
|
99
|
+
<Button variant="tertiary" size="md" startIcon={Trash2}>刪除</Button>
|
|
116
100
|
</>
|
|
117
101
|
}
|
|
118
102
|
/>
|
|
@@ -41,7 +41,7 @@ export interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
41
41
|
/** 已選 ID,length === 0 時自動隱藏(回傳 null) */
|
|
42
42
|
selection: readonly string[]
|
|
43
43
|
/** Clear 觸發,user 點 X icon 或 Esc(consumer 在 page-level 監聽) */
|
|
44
|
-
|
|
44
|
+
onClearSelection?: () => void
|
|
45
45
|
/** 批次 actions(consumer 提供 md Button,variant=tertiary 或 tertiary+danger;不用 primary) */
|
|
46
46
|
actions?: React.ReactNode
|
|
47
47
|
/** Filter 模式:hidden 數量,顯示在 count 區 inline「已選 {N} 項 · {M} 個被 filter 隱藏」 */
|
|
@@ -77,7 +77,7 @@ export interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
77
77
|
|
|
78
78
|
const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
|
|
79
79
|
function BulkActionBar(
|
|
80
|
-
{ selection,
|
|
80
|
+
{ selection, onClearSelection, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props },
|
|
81
81
|
ref
|
|
82
82
|
) {
|
|
83
83
|
const labels: BulkActionBarLabels = React.useMemo(
|
|
@@ -109,7 +109,7 @@ const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
|
|
|
109
109
|
{/* X close — md dismiss(2026-05-04 spec update:default placement = footer variant,
|
|
110
110
|
visual weight 對齊 Dialog footer commitment buttons md;same-row consistency 維持)
|
|
111
111
|
未來若有 top-toolbar variant(覆蓋 sm-density toolbar)→ 該 variant override sm */}
|
|
112
|
-
{
|
|
112
|
+
{onClearSelection && (
|
|
113
113
|
<Button
|
|
114
114
|
variant="text"
|
|
115
115
|
size="md"
|
|
@@ -117,7 +117,7 @@ const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
|
|
|
117
117
|
dismiss
|
|
118
118
|
startIcon={X}
|
|
119
119
|
aria-label={labels.clear}
|
|
120
|
-
onClick={
|
|
120
|
+
onClick={onClearSelection}
|
|
121
121
|
/>
|
|
122
122
|
)}
|
|
123
123
|
|
|
@@ -23,14 +23,14 @@ import { ButtonGroupContext } from './button'
|
|
|
23
23
|
* </ButtonGroup>
|
|
24
24
|
*
|
|
25
25
|
* // 垂直排列(fullWidth 自動套用)
|
|
26
|
-
* <ButtonGroup
|
|
26
|
+
* <ButtonGroup orientation="vertical">
|
|
27
27
|
* <Button variant="primary">確認</Button>
|
|
28
28
|
* <Button variant="tertiary">取消</Button>
|
|
29
29
|
* </ButtonGroup>
|
|
30
30
|
*/
|
|
31
31
|
interface ButtonGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
32
32
|
/** 排列方向,預設 horizontal */
|
|
33
|
-
|
|
33
|
+
orientation?: 'horizontal' | 'vertical'
|
|
34
34
|
/** 水平對齊,預設 start */
|
|
35
35
|
align?: 'start' | 'center' | 'end'
|
|
36
36
|
}
|
|
@@ -40,8 +40,8 @@ const BUTTON_GROUP_CTX_VERTICAL = { fullWidth: true } as const
|
|
|
40
40
|
const BUTTON_GROUP_CTX_HORIZONTAL = { fullWidth: false } as const
|
|
41
41
|
|
|
42
42
|
const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
|
|
43
|
-
({
|
|
44
|
-
const isVertical =
|
|
43
|
+
({ orientation = 'horizontal', align = 'start', className, children, ...props }, ref) => {
|
|
44
|
+
const isVertical = orientation === 'vertical'
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
47
|
<ButtonGroupContext.Provider value={isVertical ? BUTTON_GROUP_CTX_VERTICAL : BUTTON_GROUP_CTX_HORIZONTAL}>
|
|
@@ -102,6 +102,23 @@ const VARIANT_DESC: Record<VariantKey, string> = {
|
|
|
102
102
|
link: '外觀像連結的按鈕,不用於操作列',
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
// variant 名稱只放在左側 mono 標籤欄;按鈕本體用真實動作文案(禁 variant 名當 label)
|
|
106
|
+
const VARIANT_LABEL: Record<VariantKey, string> = {
|
|
107
|
+
primary: '新增任務',
|
|
108
|
+
secondary: '儲存變更',
|
|
109
|
+
tertiary: '取消',
|
|
110
|
+
text: '略過此步',
|
|
111
|
+
link: '查看說明',
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const DANGER_LABEL: Record<VariantKey, string> = {
|
|
115
|
+
primary: '刪除專案',
|
|
116
|
+
secondary: '移除成員',
|
|
117
|
+
tertiary: '清除紀錄',
|
|
118
|
+
text: '撤銷授權',
|
|
119
|
+
link: '刪除',
|
|
120
|
+
}
|
|
121
|
+
|
|
105
122
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
106
123
|
Shared UI Components
|
|
107
124
|
|
|
@@ -224,7 +241,8 @@ export const Overview = {
|
|
|
224
241
|
<div className="flex flex-col gap-2">
|
|
225
242
|
{VARIANTS.map((v) => (
|
|
226
243
|
<div key={v} className="flex items-center gap-4">
|
|
227
|
-
<
|
|
244
|
+
<span className="w-16 shrink-0 text-[11px] font-mono text-fg-muted">{v}</span>
|
|
245
|
+
<div className="w-28 shrink-0"><Button variant={v} size="sm" startIcon={Plus}>{VARIANT_LABEL[v]}</Button></div>
|
|
228
246
|
<span className="text-caption text-fg-secondary">{VARIANT_DESC[v]}</span>
|
|
229
247
|
</div>
|
|
230
248
|
))}
|
|
@@ -232,7 +250,8 @@ export const Overview = {
|
|
|
232
250
|
<span className="text-[11px] text-fg-muted font-medium">+ danger prop</span>
|
|
233
251
|
{DANGER_VARIANTS.map((v) => (
|
|
234
252
|
<div key={v} className="flex items-center gap-4">
|
|
235
|
-
<
|
|
253
|
+
<span className="w-16 shrink-0 text-[11px] font-mono text-fg-muted">{v}</span>
|
|
254
|
+
<div className="w-28 shrink-0"><Button variant={v} danger size="sm" startIcon={Trash2}>{DANGER_LABEL[v]}</Button></div>
|
|
236
255
|
<span className="text-caption text-fg-secondary">
|
|
237
256
|
{v === 'primary' ? '立即不可逆——點下去就執行' : v === 'secondary' ? '有警示意圖,後面還有確認' : '低強調的危險操作'}
|
|
238
257
|
</span>
|
|
@@ -503,7 +522,7 @@ export const ColorMatrix = {
|
|
|
503
522
|
<td className="p-3 border-b border-divider font-mono text-caption font-medium align-top">{v}</td>
|
|
504
523
|
{STATES.map((st) => (
|
|
505
524
|
<td key={st} className="p-3 border-b border-divider align-top min-w-[160px]">
|
|
506
|
-
<Button variant={v} size="sm" startIcon={Plus} disabled={st === 'disabled'}>{v}</Button>
|
|
525
|
+
<Button variant={v} size="sm" startIcon={Plus} disabled={st === 'disabled'}>{VARIANT_LABEL[v]}</Button>
|
|
507
526
|
<TokenAnnotation colors={TOKEN_MAP[v][st]} />
|
|
508
527
|
</td>
|
|
509
528
|
))}
|
|
@@ -523,7 +542,7 @@ export const ColorMatrix = {
|
|
|
523
542
|
<td className="p-3 border-b border-divider font-mono text-caption font-medium align-top">{v} + danger</td>
|
|
524
543
|
{STATES.map((st) => (
|
|
525
544
|
<td key={st} className="p-3 border-b border-divider align-top min-w-[160px]">
|
|
526
|
-
<Button variant={v} danger size="sm" startIcon={Trash2} disabled={st === 'disabled'}>{v}</Button>
|
|
545
|
+
<Button variant={v} danger size="sm" startIcon={Trash2} disabled={st === 'disabled'}>{DANGER_LABEL[v]}</Button>
|
|
527
546
|
<TokenAnnotation colors={DANGER_MAP[v]![st]} />
|
|
528
547
|
</td>
|
|
529
548
|
))}
|
|
@@ -612,10 +631,10 @@ export const SizeMatrix = {
|
|
|
612
631
|
<tr key={v}>
|
|
613
632
|
<Td mono>{v}</Td>
|
|
614
633
|
{SIZES.map((sz) => (
|
|
615
|
-
<Td key={sz}><Button variant={v} size={sz} startIcon={Plus}>{v}</Button></Td>
|
|
634
|
+
<Td key={sz}><Button variant={v} size={sz} startIcon={Plus}>{VARIANT_LABEL[v]}</Button></Td>
|
|
616
635
|
))}
|
|
617
636
|
{SIZES.map((sz) => (
|
|
618
|
-
<Td key={`io-${sz}`}><Button variant={v} size={sz} iconOnly startIcon={Plus} aria-label={v} /></Td>
|
|
637
|
+
<Td key={`io-${sz}`}><Button variant={v} size={sz} iconOnly startIcon={Plus} aria-label={VARIANT_LABEL[v]} /></Td>
|
|
619
638
|
))}
|
|
620
639
|
</tr>
|
|
621
640
|
))}
|
|
@@ -661,7 +680,7 @@ export const StateBehavior = {
|
|
|
661
680
|
<div className="flex flex-wrap gap-3">
|
|
662
681
|
{VARIANTS.map((v) => (
|
|
663
682
|
<div key={v} className="flex flex-col items-center gap-1">
|
|
664
|
-
<Button variant={v} disabled startIcon={Plus}>{v}</Button>
|
|
683
|
+
<Button variant={v} disabled startIcon={Plus}>{VARIANT_LABEL[v]}</Button>
|
|
665
684
|
<span className="text-[10px] text-fg-muted">{v}</span>
|
|
666
685
|
</div>
|
|
667
686
|
))}
|
|
@@ -351,7 +351,7 @@ export const OrderRule: Story = {
|
|
|
351
351
|
note="使用者眼睛最先掃到最上方,最希望被點擊的動作放第一個。所有按鈕撐滿容器寬度"
|
|
352
352
|
>
|
|
353
353
|
<div className="w-[200px]">
|
|
354
|
-
<ButtonGroup
|
|
354
|
+
<ButtonGroup orientation="vertical">
|
|
355
355
|
<Button variant="primary">確認送出</Button>
|
|
356
356
|
<Button variant="tertiary">取消</Button>
|
|
357
357
|
</ButtonGroup>
|
|
@@ -273,7 +273,7 @@ const ICON_ONLY_BASE = 'aspect-square p-0 min-w-0 gap-0'
|
|
|
273
273
|
|
|
274
274
|
完整 rationale(包含 2026-04-25 從 padding-formula 派切換的 bug origin)+ 4 家世界級對照 → **SSOT 在 `tokens/uiSize/uiSize.spec.md`「Icon-only 元件的 padding canonical」節**。本 spec 不重複,只 pointer。
|
|
275
275
|
|
|
276
|
-
**icon-only 按鈕內建自動 tooltip:** 當 `iconOnly` 為 true 時,Button 自動以 `aria-label` 的值渲染 tooltip
|
|
276
|
+
**icon-only 按鈕內建自動 tooltip:** 當 `iconOnly` 為 true 且非 `asChild` 時,Button 自動以 `aria-label` 的值渲染 tooltip(`asChild` 因 Radix Slot 單 child 限制不包 Tooltip,consumer 需自包)。開發者不需要額外包 `<Tooltip>`——tooltip 是元件保證的行為,不是開發者「記得要加」的外部組合。
|
|
277
277
|
|
|
278
278
|
`aria-label` 是給螢幕閱讀器的,tooltip 是給所有人看的,兩者語意相同,由同一個值驅動。
|
|
279
279
|
|
|
@@ -434,7 +434,7 @@ N/A(action trigger,無資料層)。
|
|
|
434
434
|
|
|
435
435
|
## A11y 預設
|
|
436
436
|
|
|
437
|
-
**ARIA / Pattern**:預設渲染原生 `<button>`,自動繼承瀏覽器原生按鈕語意(button role / Enter / Space 觸發 / Tab 聚焦),無需額外 ARIA。`asChild` 時改用 Radix `Slot` 把 props 合併到 consumer child element(Slot 為純 prop-merger,a11y 仍由該 child 自負)。icon-only 模式傳入 `aria-label`
|
|
437
|
+
**ARIA / Pattern**:預設渲染原生 `<button>`,自動繼承瀏覽器原生按鈕語意(button role / Enter / Space 觸發 / Tab 聚焦),無需額外 ARIA。`asChild` 時改用 Radix `Slot` 把 props 合併到 consumer child element(Slot 為純 prop-merger,a11y 仍由該 child 自負)。icon-only 模式傳入 `aria-label` 描述用途;**僅在非 `asChild` 時**自動包 Tooltip(`asChild` 因 Radix Slot 單 child 限制不包,consumer 需自管 child 的 `aria-label` 與 Tooltip)。`pressed` 定義時自動寫 `aria-pressed` + `data-state`。
|
|
438
438
|
|
|
439
439
|
**Focus**:鍵盤聚焦時(`focus-visible`)顯示 focus ring(`focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1`,以 box-shadow 實作並 `outline-none`);滑鼠點擊不觸發。Button 為單一互動元件,**不含** focus trap / focus restoration(那是 Dialog / 浮層的概念)。
|
|
440
440
|
|
|
@@ -24,7 +24,7 @@ const meta: Meta<typeof Button> = {
|
|
|
24
24
|
},
|
|
25
25
|
danger: {
|
|
26
26
|
control: 'boolean',
|
|
27
|
-
description: '套用危險色(紅色)。僅 `primary` / `secondary` / `text` 支援(`tertiary`
|
|
27
|
+
description: '套用危險色(紅色)。僅 `primary` / `secondary` / `text` 支援(`tertiary` 無 danger compound——會靜默渲染成一般 tertiary、並非等同 secondary+danger;`link` 語義矛盾。見 spec 禁止事項)。',
|
|
28
28
|
},
|
|
29
29
|
size: {
|
|
30
30
|
control: 'select',
|
|
@@ -76,11 +76,11 @@ export const Default: Story = {
|
|
|
76
76
|
name: '預設',
|
|
77
77
|
render: () => (
|
|
78
78
|
<div className="flex flex-wrap items-center gap-3">
|
|
79
|
-
<Button variant="primary"
|
|
80
|
-
<Button variant="secondary"
|
|
81
|
-
<Button variant="tertiary"
|
|
82
|
-
<Button variant="text"
|
|
83
|
-
<Button variant="link"
|
|
79
|
+
<Button variant="primary">送出申請</Button>
|
|
80
|
+
<Button variant="secondary">儲存草稿</Button>
|
|
81
|
+
<Button variant="tertiary">取消</Button>
|
|
82
|
+
<Button variant="text">重設表單</Button>
|
|
83
|
+
<Button variant="link">查看填寫說明</Button>
|
|
84
84
|
</div>
|
|
85
85
|
),
|
|
86
86
|
}
|
|
@@ -240,26 +240,20 @@ export const Loading: Story = {
|
|
|
240
240
|
<div className="flex flex-col gap-6">
|
|
241
241
|
{/* 行為對照 */}
|
|
242
242
|
<div>
|
|
243
|
-
<p className="mb-2 text-caption text-fg-muted"
|
|
244
|
-
<div className="
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
</
|
|
257
|
-
<div className="flex items-center gap-3">
|
|
258
|
-
<Button size="sm" iconOnly startIcon={Download} aria-label="下載" />
|
|
259
|
-
<span className="text-caption text-fg-muted">→</span>
|
|
260
|
-
<Button size="sm" iconOnly startIcon={Download} loading aria-label="下載中" />
|
|
261
|
-
<span className="text-caption text-fg-muted">icon-only:spinner 替換 icon</span>
|
|
262
|
-
</div>
|
|
243
|
+
<p className="mb-2 text-caption text-fg-muted">行為對照:操作前與載入中</p>
|
|
244
|
+
<div className="grid grid-cols-[auto_auto_1fr] items-center gap-x-6 gap-y-3">
|
|
245
|
+
<span className="text-caption text-fg-muted">操作前</span>
|
|
246
|
+
<span className="text-caption text-fg-muted">載入中</span>
|
|
247
|
+
<span />
|
|
248
|
+
<Button variant="primary" startIcon={Download}>匯出</Button>
|
|
249
|
+
<Button variant="primary" startIcon={Download} loading>匯出中</Button>
|
|
250
|
+
<span className="text-caption text-fg-muted">startIcon 被 spinner 替換,位置不變</span>
|
|
251
|
+
<Button variant="primary">儲存</Button>
|
|
252
|
+
<Button variant="primary" loading>儲存中</Button>
|
|
253
|
+
<span className="text-caption text-fg-muted">spinner 出現在文字左側,按鈕略寬</span>
|
|
254
|
+
<Button size="sm" iconOnly startIcon={Download} aria-label="下載" />
|
|
255
|
+
<Button size="sm" iconOnly startIcon={Download} loading aria-label="下載中" />
|
|
256
|
+
<span className="text-caption text-fg-muted">icon-only:spinner 替換 icon</span>
|
|
263
257
|
</div>
|
|
264
258
|
</div>
|
|
265
259
|
|
|
@@ -325,8 +319,8 @@ export const HoverFocusState: Story = {
|
|
|
325
319
|
tags: ['!autodocs'],
|
|
326
320
|
render: () => (
|
|
327
321
|
<div className="flex gap-4">
|
|
328
|
-
<Button variant="primary" data-testid="hover-target"
|
|
329
|
-
<Button variant="primary" data-testid="focus-target"
|
|
322
|
+
<Button variant="primary" data-testid="hover-target">查看帳單</Button>
|
|
323
|
+
<Button variant="primary" data-testid="focus-target">下載明細</Button>
|
|
330
324
|
</div>
|
|
331
325
|
),
|
|
332
326
|
play: async ({ canvasElement }) => {
|