@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
+
// @overlay-open-skip: 本檔為 usage-guidance(設計原則)story——每個 Rule 卡片以「關閉的 trigger 按鈕」並排比較 Popover / Dialog / DropdownMenu / Tooltip 何時用;全部 defaultOpen 會讓多個 portal 疊在一起、視覺全毀。overlay 開啟狀態的視覺覆蓋由 popover.stories.tsx(展示)+ popover.anatomy.stories.tsx(Inspector defaultOpen)負責。
|
|
2
3
|
import React from 'react'
|
|
3
4
|
import LinkTo from '@storybook/addon-links/react'
|
|
4
5
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
@@ -217,7 +218,8 @@ export const UsageGuidance: Story = {
|
|
|
217
218
|
<PopoverTrigger asChild>
|
|
218
219
|
<Button variant="tertiary" size="sm" startIcon={Filter}>篩選</Button>
|
|
219
220
|
</PopoverTrigger>
|
|
220
|
-
|
|
221
|
+
{/* naked popover(無 PopoverTitle)→ 自傳 aria-label 讓 role="dialog" 有 accessible name(popover.spec.md A11y) */}
|
|
222
|
+
<PopoverContent align="start" aria-label="篩選任務">
|
|
221
223
|
<PopoverBody>
|
|
222
224
|
<CheckboxGroup>
|
|
223
225
|
<Checkbox defaultChecked label="我的任務" />
|
|
@@ -255,33 +257,52 @@ export const VisualAlignmentRule: Story = {
|
|
|
255
257
|
title="Popover 與 Dialog 共用 overlay-surface 視覺語言"
|
|
256
258
|
note="bg-surface-raised / border-border / rounded-lg / elevation-200 完全一致。Header / Body / Footer 內 padding 來自 overlay-surface pattern 主檔(px-loose py-tight)。差異:(1) Popover 是 non-modal 無 overlay 遮罩,(2) Popover 鎖 layout-space=md(header 精簡);Dialog 不鎖 layout-space,全繼承 page(md page → 16 / lg page → 24)。兩者 ui-size 都繼承 page"
|
|
257
259
|
>
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
<
|
|
265
|
-
|
|
266
|
-
<
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
260
|
+
{/* @overlay-open-skip:視覺語言比較卡片——同一「顯示欄位」內容分別以 Popover / Dialog 呈現,證明 chrome 視覺完全一致;trigger 刻意關閉並排(見檔頭 escape),開啟態覆蓋於展示 / anatomy */}
|
|
261
|
+
<div className="flex flex-col items-start gap-2">
|
|
262
|
+
<Popover>
|
|
263
|
+
<PopoverTrigger asChild>
|
|
264
|
+
<Button variant="tertiary">顯示欄位</Button>
|
|
265
|
+
</PopoverTrigger>
|
|
266
|
+
<PopoverContent align="start">
|
|
267
|
+
<PopoverHeader><PopoverTitle>顯示欄位</PopoverTitle></PopoverHeader>
|
|
268
|
+
<PopoverBody>
|
|
269
|
+
<CheckboxGroup>
|
|
270
|
+
<Checkbox defaultChecked label="狀態" />
|
|
271
|
+
<Checkbox defaultChecked label="負責人" />
|
|
272
|
+
<Checkbox label="到期日" />
|
|
273
|
+
</CheckboxGroup>
|
|
274
|
+
</PopoverBody>
|
|
275
|
+
<PopoverFooter>
|
|
276
|
+
<Button variant="tertiary" size="sm">重設</Button>
|
|
277
|
+
<Button variant="primary" size="sm">套用</Button>
|
|
278
|
+
</PopoverFooter>
|
|
279
|
+
</PopoverContent>
|
|
280
|
+
</Popover>
|
|
281
|
+
<Label>↑ 同一內容以 Popover 呈現(non-modal 輕量浮層)</Label>
|
|
282
|
+
</div>
|
|
283
|
+
<div className="flex flex-col items-start gap-2">
|
|
284
|
+
<Dialog>
|
|
285
|
+
<DialogTrigger asChild>
|
|
286
|
+
<Button variant="tertiary">顯示欄位</Button>
|
|
287
|
+
</DialogTrigger>
|
|
288
|
+
<DialogContent autoHeight maxWidth="360px">
|
|
289
|
+
<DialogHeader><DialogTitle>顯示欄位</DialogTitle></DialogHeader>
|
|
290
|
+
<DialogBody>
|
|
291
|
+
<CheckboxGroup>
|
|
292
|
+
<Checkbox defaultChecked label="狀態" />
|
|
293
|
+
<Checkbox defaultChecked label="負責人" />
|
|
294
|
+
<Checkbox label="到期日" />
|
|
295
|
+
</CheckboxGroup>
|
|
296
|
+
</DialogBody>
|
|
297
|
+
<DialogFooter>
|
|
298
|
+
<Button variant="tertiary">重設</Button>
|
|
299
|
+
<Button variant="primary">套用</Button>
|
|
300
|
+
</DialogFooter>
|
|
301
|
+
</DialogContent>
|
|
302
|
+
</Dialog>
|
|
303
|
+
<Label>↑ 同一內容以 Dialog 呈現(modal 阻斷背景)</Label>
|
|
304
|
+
</div>
|
|
305
|
+
<Label>↑ 容器不同、chrome 視覺語言完全一致,consumer 切換不會產生視覺斷層</Label>
|
|
285
306
|
</Rule>
|
|
286
307
|
|
|
287
308
|
<Rule
|
|
@@ -152,11 +152,13 @@ canonical 判斷:「使用者 click 單項是否立即改變系統狀態?」是
|
|
|
152
152
|
|
|
153
153
|
## 邊界案例
|
|
154
154
|
|
|
155
|
-
- **極長內容**:PopoverContent 設 `max-h-[var(--radix-popover-content-available-height)]`(popover.tsx:
|
|
155
|
+
- **極長內容**:PopoverContent 設 `max-h-[var(--radix-popover-content-available-height)]`(popover.tsx:103),body 包 `<PopoverBody>`(SurfaceBody `flex-1 min-h-0 overflow-y-auto`)→ viewport 太小時 header / footer 留在視窗內、body 內捲。中間 wrapper 必 forward flex chain,詳 `../../patterns/overlay-surface/overlay-surface.spec.md`「Viewport-aware scroll chain invariant」。
|
|
156
156
|
- **Viewport 邊緣**:`collisionPadding = 8` 自動推開(見「Viewport 邊距 canonical」)。
|
|
157
157
|
- **嵌套 Popover**:禁止(見「禁止事項」)。
|
|
158
158
|
- **Dark mode**:殼走 semantic token 自動 adapt(見 `color.spec.md`)。
|
|
159
159
|
- **Density**:layout-space 鎖 `md`(header / footer padding 精簡);ui-size 繼承 page(見「定位」段)。
|
|
160
|
+
- **空內容 / loading / error / validation ownership**:Popover shell **不擁有**這些狀態——由 `PopoverBody` 內的 consumer 內容層負責:空狀態放 `<Empty>`、載入放 `<Skeleton>`、錯誤放 `<Alert>`、表單驗證放 `<Field>` 的 `FieldError`。structural pattern 的職責邊界 SSOT 見 `../../patterns/overlay-surface/overlay-surface.spec.md` SurfaceBody「邊界」段(loading / error / empty 屬 consumer 內容層)。
|
|
161
|
+
- **disabled ownership**:Popover 容器無 disabled 態;trigger 的 disabled 由 trigger 元件自管(`<Button disabled>`),content 內控件各自的 disabled 由該控件負責(對應 `StateBehavior` story「職責邊界」段)。
|
|
160
162
|
|
|
161
163
|
---
|
|
162
164
|
|
|
@@ -164,7 +166,7 @@ canonical 判斷:「使用者 click 單項是否立即改變系統狀態?」是
|
|
|
164
166
|
|
|
165
167
|
焦點 / 鍵盤 / ARIA 行為分兩層——**DS 覆寫**(改 Radix 預設)與 **Radix 內建**(沿用):
|
|
166
168
|
|
|
167
|
-
- **開啟焦點(DS 覆寫)**:DS 以 `onOpenAutoFocus` 覆寫 Radix 預設 autofocus(見 `popover.tsx` `handlePopoverOpenAutoFocus`),開啟時把焦點落在 body
|
|
169
|
+
- **開啟焦點(DS 覆寫)**:DS 以 `onOpenAutoFocus` 覆寫 Radix 預設 autofocus(見 `popover.tsx` `handlePopoverOpenAutoFocus`),開啟時把焦點落在 body 第一個**表單控件**(`input` / `textarea` / `select` / `button`,排除右上 close X);查無表單控件時退回 footer 按鈕,再無則落在 content 容器(`role="dialog"`)本身。Radix 預設會先 focus 右上 close X,DS 覆寫以避免觸發 tooltip leak(對齊 Material / Polaris「open 時 focus 落首個有意義控制」;selector 與 `dialog.tsx handleOpenAutoFocus` 同一套 DS canonical)。**注意**:(1) 若移除此 default handler,行為會回退成 Radix 預設 focus close X;(2) selector 只認表單控件——body 若只含 `a[href]` / `[tabindex]` / `contenteditable` 類可聚焦內容,焦點會落在 content 容器而非該內容,consumer 需自傳 `onOpenAutoFocus` 指定要聚焦的元素 <!-- @benchmark-unverified: Material / Polaris focus-on-open pattern per frontmatter benchmark list; DS canonical selector = dialog.tsx handleOpenAutoFocus -->
|
|
168
170
|
- **關閉返回(Radix 內建)**:關閉時 focus return to trigger
|
|
169
171
|
- **Esc 關閉(Radix 內建)**:按 Esc 自動關閉並返回焦點
|
|
170
172
|
- **Focus trap(Radix 內建,僅 modal)**:`modal={true}` 時焦點鎖在 content 內
|
|
@@ -205,7 +205,7 @@ export const SectionMatrix: Story = {
|
|
|
205
205
|
<div className="flex flex-col gap-10">
|
|
206
206
|
<div>
|
|
207
207
|
<H3>Minimal — profile header + View more</H3>
|
|
208
|
-
<Desc>最小形式:avatar + name + subtitle + **View more**(hover context
|
|
208
|
+
<Desc>最小形式:avatar + name + subtitle + **View more**(hover context 必含 — canonical owner 見 avatar.spec.md「onViewMore 為 hover context 必含」段;顯示條件見本元件 spec「View More」節)。@mention hover 場景 user 點 View more 跳完整 profile。</Desc>
|
|
209
209
|
<div className="border border-dashed border-divider rounded-md p-4 inline-block">
|
|
210
210
|
<ProfileCard name="Alice Wang" subtitle="Frontend Engineer" onViewMore={() => {}} />
|
|
211
211
|
</div>
|
|
@@ -24,7 +24,7 @@ import { ItemContent } from '@/design-system/patterns/element-anatomy/item-anato
|
|
|
24
24
|
* 跨 consumer(avatar.principles / profile-card.stories / future product code)應該用
|
|
25
25
|
* 同一組預設,避免每個範例各自發明 action 組合,讓 reader 誤以為 action 會隨情境自動變。
|
|
26
26
|
*
|
|
27
|
-
* ── 使用方式(hover context 必含 onViewMore
|
|
27
|
+
* ── 使用方式(hover context 必含 onViewMore — canonical owner 見 avatar.spec.md「onViewMore 為 hover context 必含」段;顯示條件見 profile-card.spec.md「View More」節)──
|
|
28
28
|
* <ProfileCard name="..." actions={<ProfileCardDefaultActions />} onViewMore={...} />
|
|
29
29
|
*
|
|
30
30
|
* ── 何時要換成自訂 action ──
|
|
@@ -91,7 +91,7 @@ export const Overview = {
|
|
|
91
91
|
{STATUSES.map((s) => (
|
|
92
92
|
<div key={s} className="flex items-center gap-4">
|
|
93
93
|
<div className="w-28 shrink-0">
|
|
94
|
-
<ProgressBar value={s === 'success' ? 100 : s === 'error' ? 60 : 45} status={s} />
|
|
94
|
+
<ProgressBar value={s === 'success' ? 100 : s === 'error' ? 60 : 45} status={s} aria-label={`${s} 狀態範例`} />
|
|
95
95
|
</div>
|
|
96
96
|
<span className="font-mono text-caption w-20 text-fg-secondary">{s}</span>
|
|
97
97
|
<span className="text-caption text-fg-secondary">{STATUS_TOKEN[s].desc}</span>
|
|
@@ -193,6 +193,7 @@ const InspectorInner = () => {
|
|
|
193
193
|
type="range" min={0} max={100} value={value}
|
|
194
194
|
onChange={(e) => setValue(Number(e.target.value))}
|
|
195
195
|
className="w-[240px]"
|
|
196
|
+
aria-label="調整進度值"
|
|
196
197
|
/>
|
|
197
198
|
<span className="text-[11px] font-mono text-fg-secondary tabular-nums w-10">{value}%</span>
|
|
198
199
|
</div>
|
|
@@ -203,7 +204,7 @@ const InspectorInner = () => {
|
|
|
203
204
|
{/* Left: preview */}
|
|
204
205
|
<div className="flex flex-col gap-5 min-w-[360px]">
|
|
205
206
|
<div className="px-6 py-10 rounded-lg bg-canvas border border-divider">
|
|
206
|
-
<ProgressBar value={value} status={status} affix={affixNode} />
|
|
207
|
+
<ProgressBar value={value} status={status} affix={affixNode} aria-label="即時預覽進度" />
|
|
207
208
|
</div>
|
|
208
209
|
|
|
209
210
|
{/* Blueprint:顯示 track 高度 + fill 寬度 */}
|
|
@@ -317,7 +318,7 @@ export const ColorMatrix = {
|
|
|
317
318
|
<Td mono>{s}</Td>
|
|
318
319
|
<Td>
|
|
319
320
|
<div className="w-[180px]">
|
|
320
|
-
<ProgressBar value={s === 'success' ? 100 : 60} status={s} />
|
|
321
|
+
<ProgressBar value={s === 'success' ? 100 : 60} status={s} aria-label={`${s} 狀態色彩範例`} />
|
|
321
322
|
</div>
|
|
322
323
|
</Td>
|
|
323
324
|
<Td><TokenCell token="--secondary" /></Td>
|
|
@@ -336,9 +337,9 @@ export const ColorMatrix = {
|
|
|
336
337
|
<div className="flex flex-col gap-3">
|
|
337
338
|
<span className="text-caption font-medium text-fg-secondary">含 affix 預覽</span>
|
|
338
339
|
<div className="flex flex-col gap-3 max-w-[420px]">
|
|
339
|
-
<ProgressBar value={42} status="inProgress" affix="value" />
|
|
340
|
-
<ProgressBar value={100} status="success" affix="status-icon" />
|
|
341
|
-
<ProgressBar value={68} status="error" affix="status-icon" />
|
|
340
|
+
<ProgressBar value={42} status="inProgress" affix="value" aria-label="進行中含百分比範例" />
|
|
341
|
+
<ProgressBar value={100} status="success" affix="status-icon" aria-label="完成含狀態圖示範例" />
|
|
342
|
+
<ProgressBar value={68} status="error" affix="status-icon" aria-label="失敗含狀態圖示範例" />
|
|
342
343
|
</div>
|
|
343
344
|
</div>
|
|
344
345
|
</div>
|
|
@@ -368,7 +369,7 @@ export const AffixBehavior = {
|
|
|
368
369
|
配額使用率、下載進度等需要精確數字時使用。
|
|
369
370
|
</p>
|
|
370
371
|
<div className="w-[360px]">
|
|
371
|
-
<ProgressBar value={45} status="inProgress" affix="value" />
|
|
372
|
+
<ProgressBar value={45} status="inProgress" affix="value" aria-label="含百分比的進度範例" />
|
|
372
373
|
</div>
|
|
373
374
|
</div>
|
|
374
375
|
|
|
@@ -381,9 +382,9 @@ export const AffixBehavior = {
|
|
|
381
382
|
inProgress → 無 icon(inProgress 非終態)。
|
|
382
383
|
</p>
|
|
383
384
|
<div className="flex flex-col gap-2 w-[360px]">
|
|
384
|
-
<ProgressBar value={100} status="success" affix="status-icon" />
|
|
385
|
-
<ProgressBar value={72} status="error" affix="status-icon" />
|
|
386
|
-
<ProgressBar value={50} status="inProgress" affix="status-icon" />
|
|
385
|
+
<ProgressBar value={100} status="success" affix="status-icon" aria-label="完成狀態範例" />
|
|
386
|
+
<ProgressBar value={72} status="error" affix="status-icon" aria-label="失敗狀態範例" />
|
|
387
|
+
<ProgressBar value={50} status="inProgress" affix="status-icon" aria-label="進行中狀態範例" />
|
|
387
388
|
<span className="text-footnote text-fg-muted">↑ inProgress 傳 status-icon 時不渲染 icon,且因無 affix 內容而 collapse 成純 bar(無 wrapper、無 gap,與不傳 affix 等價)</span>
|
|
388
389
|
</div>
|
|
389
390
|
</div>
|
|
@@ -398,7 +399,7 @@ export const AffixBehavior = {
|
|
|
398
399
|
<ProgressBar
|
|
399
400
|
value={42}
|
|
400
401
|
status="inProgress"
|
|
401
|
-
|
|
402
|
+
aria-label="可取消的進度範例"
|
|
402
403
|
affix={
|
|
403
404
|
<Button variant="text" size="xs" iconOnly startIcon={X} aria-label="取消上傳" />
|
|
404
405
|
}
|
|
@@ -406,7 +407,7 @@ export const AffixBehavior = {
|
|
|
406
407
|
<ProgressBar
|
|
407
408
|
value={66}
|
|
408
409
|
status="inProgress"
|
|
409
|
-
|
|
410
|
+
aria-label="含資料量的進度範例"
|
|
410
411
|
affix={<span className="text-caption text-fg-muted tabular-nums shrink-0">1.3 / 2.0 MB</span>}
|
|
411
412
|
/>
|
|
412
413
|
</div>
|
|
@@ -419,7 +420,7 @@ export const AffixBehavior = {
|
|
|
419
420
|
不包 wrapper,ProgressBar 本身就是整個元件。適合 FileItem 的 compact mode(上方已有檔名文字)。
|
|
420
421
|
</p>
|
|
421
422
|
<div className="w-[360px]">
|
|
422
|
-
<ProgressBar value={55} status="inProgress" />
|
|
423
|
+
<ProgressBar value={55} status="inProgress" aria-label="純 bar 進度範例" />
|
|
423
424
|
</div>
|
|
424
425
|
</div>
|
|
425
426
|
</div>
|
|
@@ -7,6 +7,7 @@ import LinkTo from '@storybook/addon-links/react'
|
|
|
7
7
|
import { Paperclip, X, FileText, Table as TableIcon } from 'lucide-react'
|
|
8
8
|
import { ProgressBar } from './progress-bar'
|
|
9
9
|
import { CircularProgress } from '@/design-system/components/CircularProgress/circular-progress'
|
|
10
|
+
import { FileItem } from '@/design-system/components/FileItem/file-item'
|
|
10
11
|
import { Button } from '@/design-system/components/Button/button'
|
|
11
12
|
|
|
12
13
|
const meta: Meta = {
|
|
@@ -105,31 +106,15 @@ export const UsageGuidance: Story = {
|
|
|
105
106
|
note="每個檔案一條 ProgressBar 已足夠表達整體狀態(使用者自然從完成數量推算),再加一條總 bar 會造成視覺重複與同步邏輯漂移。Dropbox / Google Drive 都只顯示每檔 bar。"
|
|
106
107
|
>
|
|
107
108
|
<Frame width={480}>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<ProgressBar value={100} status="success" affix="status-icon" />
|
|
115
|
-
</div>
|
|
116
|
-
<div>
|
|
117
|
-
<div className="flex items-center gap-2 mb-1">
|
|
118
|
-
<Paperclip size={16} className="text-fg-muted" />
|
|
119
|
-
<span className="text-body flex-1 truncate">簡報素材.zip</span>
|
|
120
|
-
</div>
|
|
121
|
-
<ProgressBar value={62} status="inProgress" affix="value" />
|
|
122
|
-
</div>
|
|
123
|
-
<div>
|
|
124
|
-
<div className="flex items-center gap-2 mb-1">
|
|
125
|
-
<Paperclip size={16} className="text-fg-muted" />
|
|
126
|
-
<span className="text-body flex-1 truncate">截圖.png</span>
|
|
127
|
-
</div>
|
|
128
|
-
<ProgressBar value={0} status="inProgress" />
|
|
129
|
-
</div>
|
|
109
|
+
{/* 上傳列表載體 = FileItem(compact list gap-1 canonical;內部消費 ProgressBar)—
|
|
110
|
+
不手組 Paperclip + 檔名 + ProgressBar(見下方「檔案上傳 UI → 用 FileItem」rule) */}
|
|
111
|
+
<div className="flex flex-col gap-1">
|
|
112
|
+
<FileItem mode="compact" name="會議記錄_0418.docx" status="completed" />
|
|
113
|
+
<FileItem mode="compact" name="簡報素材.zip" status="uploading" progress={62} />
|
|
114
|
+
<FileItem mode="compact" name="截圖.png" status="uploading" progress={0} />
|
|
130
115
|
</div>
|
|
131
116
|
</Frame>
|
|
132
|
-
<Label>✅
|
|
117
|
+
<Label>✅ 每檔一條(FileItem 內建),整體進度由使用者自然感知(1 檔完成、2 檔進行中)</Label>
|
|
133
118
|
</Rule>
|
|
134
119
|
|
|
135
120
|
<Rule
|
|
@@ -37,6 +37,7 @@ const SectionDesc = ({ children }: { children: React.ReactNode }) => (
|
|
|
37
37
|
// ── Default(基本範例) ──────────────────────────────────────────────────
|
|
38
38
|
|
|
39
39
|
export const Default: Story = {
|
|
40
|
+
name: '預設',
|
|
40
41
|
args: { value: 45, status: 'inProgress', affix: 'value' },
|
|
41
42
|
render: (args) => (
|
|
42
43
|
<div className="w-[360px]">
|
|
@@ -64,7 +65,7 @@ export const BatchTask: Story = {
|
|
|
64
65
|
<span className="text-body-lg font-medium flex-1">匯入客戶名單</span>
|
|
65
66
|
<span className="text-caption text-fg-muted tabular-nums">812 / 1,250 筆</span>
|
|
66
67
|
</div>
|
|
67
|
-
<ProgressBar value={65} status="inProgress" affix="value" />
|
|
68
|
+
<ProgressBar value={65} status="inProgress" affix="value" aria-label="匯入客戶名單進度" />
|
|
68
69
|
<p className="text-footnote text-fg-muted">
|
|
69
70
|
處理中,請勿關閉此視窗。預計剩餘 28 秒。
|
|
70
71
|
</p>
|
|
@@ -107,7 +108,12 @@ const quotaColumns: ColumnDef<QuotaRow>[] = [
|
|
|
107
108
|
header: '配額使用率',
|
|
108
109
|
meta: { width: 240 },
|
|
109
110
|
cell: ({ row }) => (
|
|
110
|
-
<ProgressBar
|
|
111
|
+
<ProgressBar
|
|
112
|
+
value={row.original.quota}
|
|
113
|
+
status={row.original.status}
|
|
114
|
+
affix="value"
|
|
115
|
+
aria-label={`${row.original.name} 配額使用率`}
|
|
116
|
+
/>
|
|
111
117
|
),
|
|
112
118
|
},
|
|
113
119
|
]
|
package/src/components/README.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
- `Checkbox/` — `checkbox.tsx` + `checkbox-group.tsx`(2026-04-21 CheckboxGroup merge 自 separate folder,對齊 standalone + group 世界級慣例)+ `boolean-display.tsx`(table cell 顯示)
|
|
23
23
|
- `Menu/` — `menu-item.tsx`(家族預留位)
|
|
24
24
|
- `SelectionControl/` — `selection-item.tsx`(Checkbox/Radio 共享的 row layout primitive home)
|
|
25
|
+
- `PeoplePicker/` — `people-picker.tsx` + `person-display.tsx`(`PersonDisplay` / `MultiPersonDisplay` / `PersonAvatarTag`)+ `avatar-stack-overflow.ts` + `people-picker-helpers.ts`。**compound rationale**:全部共享 `PersonValue` 資料模型 + avatar 視覺規則,且 picker↔display 雙向消費(edit 選人 / view 渲染已選)。`PersonDisplay` 為**唯一現存 cross-component view primitive**(可脫離 picker 用於 DataTable cell / detail panel,見 `Field/field-controls.spec.md`「唯一現存 cross-component view primitive」),經 `PeoplePicker` root barrel + subpath 一併公開——與 `Checkbox/boolean-display.tsx`(table-cell 顯示 co-located)同型共居先例
|
|
25
26
|
|
|
26
27
|
**判斷 compound vs 單獨 folder**:
|
|
27
28
|
- 元件能**獨立 lifecycle / 獨立使用** → 各自獨立 folder(Button / Input / Select)
|
|
@@ -169,9 +169,14 @@ export const Overview = {
|
|
|
169
169
|
<div className="flex flex-col gap-2 items-start">
|
|
170
170
|
<span className="text-[11px] text-fg-muted font-medium">搭配 SelectionItem</span>
|
|
171
171
|
<div className="inline-flex items-center border-2 border-dashed border-primary/30 rounded-md px-3 py-2.5 gap-2">
|
|
172
|
-
{
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
{/* magenta 為 primitive(無 --magenta semantic token)→ 顯式 --color-magenta-{6,1,7}(ProgressBar 同款修法) */}
|
|
173
|
+
{[
|
|
174
|
+
{ name: 'control', border: 'var(--info)', bg: 'var(--info-subtle)', text: 'var(--info)' },
|
|
175
|
+
{ name: 'control', border: 'var(--success)', bg: 'var(--success-subtle)', text: 'var(--success)' },
|
|
176
|
+
{ name: 'control', border: 'var(--color-magenta-6)', bg: 'var(--color-magenta-1)', text: 'var(--color-magenta-7)' },
|
|
177
|
+
].map((s, i) => (
|
|
178
|
+
<span key={i} className="rounded px-2 py-1 text-[11px] font-mono border border-dashed"
|
|
179
|
+
style={{ borderColor: s.border, backgroundColor: s.bg, color: s.text }}>{s.name}</span>
|
|
175
180
|
))}
|
|
176
181
|
</div>
|
|
177
182
|
<span className="text-[10px] text-fg-muted font-mono">flex items-start gap-2 · control 在一行文字高度的容器內置中</span>
|
|
@@ -15,7 +15,7 @@ type Story = StoryObj<typeof RadioGroupItem>
|
|
|
15
15
|
// 「何時用」明文禁止裸用)→ 收斂為公開 <RadioGroupItem value label description>(自動 wire SelectionItem
|
|
16
16
|
// + id/htmlFor),與同元件 principles / anatomy 層一致 — 三層 story 一律示範公開 API。
|
|
17
17
|
|
|
18
|
-
// @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with
|
|
18
|
+
// @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with view card.
|
|
19
19
|
/* ── 四模式 ── */
|
|
20
20
|
export const Modes: Story = {
|
|
21
21
|
name: '四模式',
|
|
@@ -30,8 +30,8 @@ export const Modes: Story = {
|
|
|
30
30
|
</RadioGroup>
|
|
31
31
|
</div>
|
|
32
32
|
<div>
|
|
33
|
-
<h3 className="text-body font-bold text-foreground mb-2">
|
|
34
|
-
<RadioGroup mode="
|
|
33
|
+
<h3 className="text-body font-bold text-foreground mb-2">view</h3>
|
|
34
|
+
<RadioGroup mode="view" value="yearly" aria-label="付款方案(view 模式示範)">
|
|
35
35
|
<RadioGroupItem value="monthly" label="月付方案" />
|
|
36
36
|
<RadioGroupItem value="yearly" label="年付方案" description="每年 $2,990,省下兩個月" />
|
|
37
37
|
<RadioGroupItem value="lifetime" label="終身方案" />
|
|
@@ -13,21 +13,24 @@ import type { AvatarData } from "@/design-system/components/Avatar/avatar"
|
|
|
13
13
|
import { fieldWrapperStyles } from "@/design-system/components/Field/field-wrapper"
|
|
14
14
|
import { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'
|
|
15
15
|
|
|
16
|
-
// ── RadioGroup
|
|
17
|
-
// RadioGroup mode='
|
|
16
|
+
// ── RadioGroup view mode ────────────────────────────────────────────────────
|
|
17
|
+
// RadioGroup mode='view' 時:Group 不渲染 Radix primitive(無 radio 視覺),
|
|
18
18
|
// 改由 RadioGroup 本體 walk props.children,找 control.value === selectedValue 的
|
|
19
19
|
// SelectionItem,把它的 label 渲染為單一純文字 span(其他選項不顯示)。
|
|
20
20
|
// 對齊 Carbon read-only single-select(只顯示 selected 內容)+ Airtable / Notion read-only。
|
|
21
|
-
// 實作在 RadioGroup forwardRef 內(見下方 mode === '
|
|
21
|
+
// 實作在 RadioGroup forwardRef 內(見下方 mode === 'view' 分支)。
|
|
22
22
|
|
|
23
23
|
// ── RadioGroup ──────────────────────────────────────────────────────────────
|
|
24
24
|
|
|
25
25
|
export interface RadioGroupProps
|
|
26
|
-
|
|
26
|
+
// asChild Omit(2026-07-18 決策2):RadioGroup 恆持有多個 radio item → <Root asChild> 的
|
|
27
|
+
// Radix Slot React.Children.only crash;view/readonly 模式更直接渲染固定 <div> 忽略之。
|
|
28
|
+
// children 保留(edit 容器內容 + view/readonly 走訪選中 label,見 body cast @line ~105)。
|
|
29
|
+
extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>, 'asChild'> {
|
|
27
30
|
/**
|
|
28
31
|
* Field mode(2026-05-05 Phase B3 align):
|
|
29
32
|
* edit — 一般可互動 RadioGroup(預設)
|
|
30
|
-
*
|
|
33
|
+
* view — **純展示**:不渲染 Radix Root / 任何 radio 視覺;RadioGroup 本體 walk
|
|
31
34
|
* children,僅 control.value === group.value 那筆把 label 渲染為純文字 span。
|
|
32
35
|
* 對齊 Carbon read-only / DataTable single-select cell read mode。
|
|
33
36
|
* readonly — standalone:ReadonlyContext 傳 items 鎖互動保留視覺;Field 內:灰框 + 選中項 label(不渲染 radio 群組)
|
|
@@ -50,7 +53,7 @@ const RadioGroupReadonlyContext = React.createContext(false)
|
|
|
50
53
|
// 對齊本檔 RadioGroupReadonlyContext 既有模式 + spec「Disabled」邊界案例(Group-level disabled 視覺繼承 SelectionItem SSOT text-fg-disabled)。
|
|
51
54
|
const RadioGroupDisabledContext = React.createContext(false)
|
|
52
55
|
|
|
53
|
-
// walk children 找 control.value === selectedValue 的 SelectionItem label(
|
|
56
|
+
// walk children 找 control.value === selectedValue 的 SelectionItem label(view / readonly-in-Field 共用)
|
|
54
57
|
function findSelectedRadioLabel(children: React.ReactNode, selectedValue: string | undefined): React.ReactNode {
|
|
55
58
|
let selectedLabel: React.ReactNode = null
|
|
56
59
|
React.Children.forEach(children, (child) => {
|
|
@@ -83,12 +86,12 @@ const RadioGroup = React.forwardRef<
|
|
|
83
86
|
const fieldCtx = useFieldContext()
|
|
84
87
|
// readonly 灰框 size:走 SSOT resolver(RadioGroup 無 size prop → ctx > 'md')
|
|
85
88
|
const resolvedBoxSize = useResolvedFieldSize(undefined, 'md') as 'sm' | 'md' | 'lg'
|
|
86
|
-
// mode='
|
|
89
|
+
// mode='view' — 純展示 selected option 的 label,不渲染任何 radio control 視覺。
|
|
87
90
|
// 對齊 Carbon read-only single-select(只顯示 selected 內容)+ Airtable / Notion read-only。
|
|
88
91
|
// 實作:walk children 找 control.value === selectedValue 的 SelectionItem,render label plain text。
|
|
89
92
|
// (不用 context dispatch 給 RadioGroupItem — SelectionItem layout wrapper 仍會渲染所有 item label)
|
|
90
|
-
// 2026-07-04 修:
|
|
91
|
-
// 且不轉發 forwardRef ref → 自家 radio-group.stories.tsx
|
|
93
|
+
// 2026-07-04 修:view / readonly-in-Field 分支的 <div> 原丟棄剩餘 props(id/data-*/aria-*)
|
|
94
|
+
// 且不轉發 forwardRef ref → 自家 radio-group.stories.tsx view demo 傳的 aria-label 都靜默失效。
|
|
92
95
|
// 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Checkbox/Switch 同修);
|
|
93
96
|
// edit 主路徑不受影響(Root 仍 spread 完整 props)。
|
|
94
97
|
const {
|
|
@@ -104,7 +107,7 @@ const RadioGroup = React.forwardRef<
|
|
|
104
107
|
...restDomProps
|
|
105
108
|
} = props as RadioGroupProps & { asChild?: boolean }
|
|
106
109
|
|
|
107
|
-
if (resolvedMode === '
|
|
110
|
+
if (resolvedMode === 'view') {
|
|
108
111
|
const selectedValue = (value ?? defaultValue) as string | undefined
|
|
109
112
|
if (!selectedValue) {
|
|
110
113
|
return <div {...restDomProps} ref={ref as React.Ref<HTMLDivElement>} role="group" className={cn('grid', className)}><span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span></div>
|
|
@@ -223,7 +226,9 @@ const dotSize: Record<string, number> = { sm: 8, md: 8, lg: 10 }
|
|
|
223
226
|
type RadioItemPrimitiveProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
|
224
227
|
|
|
225
228
|
export interface RadioGroupItemProps
|
|
226
|
-
|
|
229
|
+
// asChild / children Omit(2026-07-18 決策2):item 固定渲染 Indicator dot(<Circle/>)—
|
|
230
|
+
// children 被固定 Indicator 靜默覆蓋,asChild 破壞 radio 結構。對齊 Checkbox 收窄。label 走 `label` prop。
|
|
231
|
+
extends Omit<RadioItemPrimitiveProps, 'asChild' | 'children'>,
|
|
227
232
|
VariantProps<typeof radioItemVariants> {
|
|
228
233
|
/**
|
|
229
234
|
* Inline label。提供時 RadioGroupItem 自動透過 SelectionItem 包裝,
|
|
@@ -273,9 +278,9 @@ const RadioGroupItem = React.forwardRef<
|
|
|
273
278
|
const sizeKey = size ?? 'md'
|
|
274
279
|
const dotPx = dotSize[sizeKey]
|
|
275
280
|
|
|
276
|
-
// 注意:RadioGroup mode='
|
|
277
|
-
// (見上方 RadioGroup forwardRef 的 mode === '
|
|
278
|
-
// mode 下不會被獨立 render,故此處無
|
|
281
|
+
// 注意:RadioGroup mode='view' 的純文字渲染由 RadioGroup 本體 walk-children 處理
|
|
282
|
+
// (見上方 RadioGroup forwardRef 的 mode === 'view' 分支),RadioGroupItem 在 view
|
|
283
|
+
// mode 下不會被獨立 render,故此處無 view 分支。
|
|
279
284
|
|
|
280
285
|
// 注意:Radio 的 label 語意與 Checkbox/Switch 不同——
|
|
281
286
|
// Checkbox/Switch 的 label 就是該 control 的唯一 label(被 Field context 接管),
|
|
@@ -188,7 +188,7 @@ const InspectorInner = () => {
|
|
|
188
188
|
precision={precision}
|
|
189
189
|
readOnly={readOnly}
|
|
190
190
|
disabled={disabled}
|
|
191
|
-
aria-label={readOnly ? `平均評分 ${value} 星,共 5 星` :
|
|
191
|
+
aria-label={readOnly ? `平均評分 ${value} 星,共 5 星` : `為這次體驗評分,目前 ${value} 星,共 5 星`}
|
|
192
192
|
/>
|
|
193
193
|
</div>
|
|
194
194
|
<div className="text-caption text-fg-muted font-mono">
|
|
@@ -76,8 +76,8 @@ export const UsageGuidance: Story = {
|
|
|
76
76
|
{/* 何時不用 / 替代元件 — 原 WhenNotToUse */}
|
|
77
77
|
<div>
|
|
78
78
|
<Rule
|
|
79
|
-
title="❌ readOnly
|
|
80
|
-
note="純視覺的星星螢幕閱讀器讀不出「4.7 分」。readOnly Rating
|
|
79
|
+
title="❌ standalone readOnly 不給可存取名稱"
|
|
80
|
+
note="純視覺的星星螢幕閱讀器讀不出「4.7 分」。standalone readOnly Rating 必須有可存取名稱——傳 aria-label 描述目前分數與滿分(如「平均評分 4.5 星,共 5 星」);包在 Field 內時由 aria-labelledby 自動指向 FieldLabel,免傳 aria-label。評論數只在畫面確實顯示時才加進描述。"
|
|
81
81
|
>
|
|
82
82
|
<div className="flex flex-col gap-2 w-[320px] p-4 border border-border rounded-md">
|
|
83
83
|
<Rating value={4.5} readOnly precision="half" size="md" aria-label="平均評分 4.5 星,共 5 星" />
|
|
@@ -260,7 +260,7 @@ export const YellowStarConvention: Story = {
|
|
|
260
260
|
<div>
|
|
261
261
|
<Rule
|
|
262
262
|
title="黃星 = 世界級 convention,破壞 = 破壞使用者直覺"
|
|
263
|
-
note="
|
|
263
|
+
note="黃 / 金色星是星級評分最通用的視覺慣例——Amazon 商品評分、Google 地點評分都用金黃星,使用者的視覺記憶早已把「黃星 = 評分」綁定。換成品牌 primary 色(藍 / 綠 / 紫)會讓使用者多花一瞬間「這是什麼?」,這一瞬間就是設計 bug。(少數平台改用自家色:Yelp 紅星、Tripadvisor 綠色圓點 bubble——但黃 / 金星仍是跨平台最通用的星級評分色。)"
|
|
264
264
|
>
|
|
265
265
|
<div className="flex flex-col gap-2">
|
|
266
266
|
<Rating value={4.5} readOnly precision="half" size="lg" aria-label="標準黃星" />
|
|
@@ -36,7 +36,7 @@ Rating 是**離散 1–5 分評分元件**——使用者對商品、服務、
|
|
|
36
36
|
|
|
37
37
|
| 情境 | 改用 | 原因 |
|
|
38
38
|
|------|------|------|
|
|
39
|
-
| 純資訊標記(「熱門」「Beta」「新品」)| `
|
|
39
|
+
| 純資訊標記(「熱門」「Beta」「新品」)| `Tag` | Rating 是量化 1–5 分,不是分類標籤;文字分類標記走 Tag(Badge 僅 count/dot 兩模式,無文字承載) |
|
|
40
40
|
| 非 1–5 的連續數值(音量、亮度、價格範圍)| `Slider` | Rating 是離散 tier,Slider 是連續值 |
|
|
41
41
|
| 二元喜歡 / 不喜歡(thumbs up/down、like)| `Switch` 或自組 icon button | Like 是 binary,Rating 是 graded 1–5 |
|
|
42
42
|
| 多維度評比(服務 / 品質 / 速度 各 5 分)| 自組多個 Rating 縱向排列 | 單一 Rating 只表達單一維度 |
|
|
@@ -210,7 +210,7 @@ Star icon 渲染時明確設 `stroke="none"`(Lucide Star 預設 `stroke="current
|
|
|
210
210
|
## 相關
|
|
211
211
|
|
|
212
212
|
- **`Slider`** — 連續數值選擇(0–100、音量、亮度、價格區間)。Rating vs Slider 分界:離散 tier = Rating,連續值 = Slider
|
|
213
|
-
- **`
|
|
213
|
+
- **`Tag`** — 靜態文字分類標記(「熱門」「Beta」「NEW」)。Rating 是量化,Tag 是文字分類(Badge 僅 count/dot,不承載文字)
|
|
214
214
|
- **`Switch`** — 二元 on/off。Rating 是 graded,Switch 是 binary
|
|
215
215
|
- **`Button iconOnly + pressed={liked}`** — 愛心 / like 的正確實作
|
|
216
216
|
- **Color token 例外** — `color.spec.md`「共用 `--warning` 色相但語境不同」段落
|
|
@@ -113,21 +113,7 @@ export const InField: Story = {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/* @story-trait-rationale: AllSizes retired per F migration 2026-05-15 — anatomy.stories.tsx SizeMatrix auto-compile owns size showcase。 */
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<div className="flex flex-col gap-4 w-[420px]">
|
|
121
|
-
<p className="text-caption text-fg-muted">
|
|
122
|
-
評分期限已過的舊訂單,Rating 顯示使用者當初給的分數但無法再修改。
|
|
123
|
-
</p>
|
|
124
|
-
<div className="flex items-center gap-3 p-3 border border-border rounded-md bg-surface">
|
|
125
|
-
<div className="flex-1">
|
|
126
|
-
<div className="text-body font-medium">訂單 #A-2025-11-03</div>
|
|
127
|
-
<div className="text-caption text-fg-muted mt-[var(--item-gap-label-desc-scanning)]">評分期限已過</div>
|
|
128
|
-
</div>
|
|
129
|
-
<Rating value={4} disabled aria-label="此訂單已完成評分 4 星,無法修改" />
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
),
|
|
133
|
-
}
|
|
116
|
+
// @story-trait-rationale: Disabled retired per audit Dim 24 —
|
|
117
|
+
// disabled 覆蓋已由 anatomy.stories.tsx StateBehavior 的 disabled live case
|
|
118
|
+
// (value=4 disabled)owns;對齊 Checkbox / Switch / RadioGroup 同 Family
|
|
119
|
+
// 已 retire 的獨立 Disabled story,不重複展示同一 state。
|
|
@@ -12,7 +12,7 @@ import { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useRes
|
|
|
12
12
|
*
|
|
13
13
|
* ── 使用情境 ──
|
|
14
14
|
* - review / feedback:商品評分 / 服務評分(可編輯 + 唯讀兩種)
|
|
15
|
-
* -
|
|
15
|
+
* - view:已提交評分的唯讀呈現(商品清單星等)
|
|
16
16
|
*
|
|
17
17
|
* ── 視覺 ──
|
|
18
18
|
* 填色用 `var(--warning)`(yellow-6,世界級黃星 convention;與 warning 語意共用色相
|
|
@@ -112,6 +112,10 @@ const Rating = React.forwardRef<HTMLDivElement, RatingProps>(
|
|
|
112
112
|
// - Standalone(無 Field context) → default `xs`(24px,對齊 Avatar / Tag sm / iOS HIG standalone)
|
|
113
113
|
// consumer 可傳 size 顯式 override。世界級對照:Material Rating standalone 24dp、
|
|
114
114
|
// Ant Rate in Form 跟 Form.itemSize,standalone 24px。
|
|
115
|
+
// 2026-07-18 決策4:max dev-warn(spec canonical ≤7;維持 number 型別不收窄,對齊 MUI Rating.max)。
|
|
116
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production' && (max > 7 || max < 1 || Math.round(max) !== max)) {
|
|
117
|
+
console.warn(`[DS] Rating max ${max} 超出 canonical 範圍 1-7(或非整數)。建議 ≤7 顆星(對齊世界級 review-stars)。`)
|
|
118
|
+
}
|
|
115
119
|
const fieldCtx = useFieldContext() // 保留:aria-labelledby 用 fieldCtx.labelId
|
|
116
120
|
// 2026-06-08 SSOT:<Field disabled> cascade(原 isInteractive 只看 local disabled prop)
|
|
117
121
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
@@ -255,7 +255,7 @@ export const SolvesDataTableBug: Story = {
|
|
|
255
255
|
|
|
256
256
|
<Rule
|
|
257
257
|
title="解法 — ScrollArea overlay 捲軸,跨 OS 一致不吃寬度"
|
|
258
|
-
note="同一份表格,改用 ScrollArea 包起來、額外渲染 horizontal ScrollBar。macOS 與 Windows 呈現完全一致,右側 Status
|
|
258
|
+
note="同一份表格,改用 ScrollArea 包起來、額外渲染 horizontal ScrollBar。macOS 與 Windows 呈現完全一致,右側 Status 欄不被裁切。此組合限外層包 height='auto' 表格的 demo 場景;DataTable 中央捲動區本體走 native overflow-x-auto(pinned column 結構需求,見 scroll-area.spec.md「何時用」例外 + data-table.spec.md「捲軸 canonical」)。"
|
|
259
259
|
>
|
|
260
260
|
<div className="w-[560px]">
|
|
261
261
|
<ScrollArea className="border border-success/40 rounded-md bg-surface">
|
|
@@ -132,7 +132,7 @@ Radix Viewport 內建 wrapper `min-width:100%; display:table`——這是**水
|
|
|
132
132
|
|
|
133
133
|
## 相關
|
|
134
134
|
|
|
135
|
-
- `../DataTable/data-table.spec.md` —
|
|
135
|
+
- `../DataTable/data-table.spec.md` — 歷史動機來源(橫向捲動跑版問題),**非 consumer**:DataTable 中央捲動區走 native `overflow-x-auto`(0 import,見上方「何時用」例外 +「捲軸 canonical」節)
|
|
136
136
|
- `../Sheet/sheet.spec.md` — body 捲動
|
|
137
137
|
- `../Dialog/dialog.spec.md` — body 捲動
|
|
138
138
|
- `../Sidebar/sidebar.spec.md` — nav 長列表捲動
|
|
@@ -20,7 +20,8 @@ import { cn } from '@/lib/utils'
|
|
|
20
20
|
* 捲動時浮現(hover / scroll 自動顯示)。
|
|
21
21
|
*
|
|
22
22
|
* ── 何時用 ──
|
|
23
|
-
* - DataTable
|
|
23
|
+
* - 寬內容橫向捲動(寬表格類 demo / 程式碼區塊;例外:DataTable 中央捲動區走 native
|
|
24
|
+
* overflow-x-auto + scrollLeft 同步,不用 ScrollArea — 見 scroll-area.spec.md「何時用」)
|
|
24
25
|
* - Sheet / Dialog 垂直內容捲動(body 太長)
|
|
25
26
|
* - Sidebar nav 長列表
|
|
26
27
|
* - 任何「內容可能溢出容器」且「跨 OS 視覺必須一致」的場景
|
|
@@ -33,7 +34,9 @@ import { cn } from '@/lib/utils'
|
|
|
33
34
|
|
|
34
35
|
const ScrollArea = React.forwardRef<
|
|
35
36
|
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
|
36
|
-
|
|
37
|
+
// asChild Omit(2026-07-18 決策2):Root 恆渲染固定三子節點(Viewport + ScrollBar + Corner)
|
|
38
|
+
// → <Root asChild> Radix Slot React.Children.only crash。children 保留(路由進固定 Viewport)。
|
|
39
|
+
Omit<React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>, 'asChild'> & {
|
|
37
40
|
/** 2026-07-08(WM 戰役 R2):Radix Viewport 內建 wrapper `display:table; min-width:100%`
|
|
38
41
|
* 讓垂直捲動容器內的 flex 多欄佈局以 max-content 佈局、突破 100% 寬(WM 兩欄 dialog
|
|
39
42
|
* 右欄被裁 33px 實證)。垂直捲動場景 opt-in 此 prop 中和為 block/w-full(水平捲動
|