@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.87
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 +19 -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 +8 -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 +10 -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/Empty/empty.spec.md +0 -1
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +46 -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 +5 -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 +4 -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 +10 -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 +4 -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/action-bar/action-bar.spec.md +1 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.spec.md +4 -0
- 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/motion/motion.spec.md +6 -7
- 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
|
@@ -48,6 +48,9 @@ type ShapeKey = 'circle' | 'tag'
|
|
|
48
48
|
const SIZES: SizeKey[] = ['sm', 'md', 'lg']
|
|
49
49
|
const SHAPES: ShapeKey[] = ['circle', 'tag']
|
|
50
50
|
|
|
51
|
+
// 真實隱藏項目池(reviewer / assignee 溢出情境;count 可調,超出池長度時循環)— 取代編號 placeholder
|
|
52
|
+
const HIDDEN_REVIEWERS = ['林思妤', '陳柏宇', 'Aisha Khan', '黃冠霖', 'Diego Santos', '王品澄', 'Nadia Petrova', '張哲瑋']
|
|
53
|
+
|
|
51
54
|
// font-size 依 shape 分流(re-verified 2026-07-04):circle shape 走元件內建 triggerText
|
|
52
55
|
// map(overflow-indicator.tsx:28-32),tag shape 走 tagVariants({ size })(tag.tsx:40-44)。
|
|
53
56
|
// circleText / tagText 兩欄分別對應,避免把 circle-only 字級當成兩 shape 通用。
|
|
@@ -209,9 +212,9 @@ function OverflowInspector() {
|
|
|
209
212
|
<OverflowIndicator count={count} shape={shape} size={size}>
|
|
210
213
|
<div className="flex flex-col gap-1 text-caption min-w-[140px]">
|
|
211
214
|
{Array.from({ length: Math.min(count, 8) }).map((_, i) => (
|
|
212
|
-
<span key={i}
|
|
215
|
+
<span key={i}>{HIDDEN_REVIEWERS[i % HIDDEN_REVIEWERS.length]}</span>
|
|
213
216
|
))}
|
|
214
|
-
{count > 8 && <span className="text-fg-muted">…及其他 {count - 8}
|
|
217
|
+
{count > 8 && <span className="text-fg-muted">…及其他 {count - 8} 位</span>}
|
|
215
218
|
</div>
|
|
216
219
|
</OverflowIndicator>
|
|
217
220
|
</div>
|
|
@@ -291,6 +294,7 @@ function OverflowInspector() {
|
|
|
291
294
|
value={count}
|
|
292
295
|
onChange={(e) => setCount(parseInt(e.target.value, 10))}
|
|
293
296
|
className="w-full"
|
|
297
|
+
aria-label="調整隱藏項目數量"
|
|
294
298
|
/>
|
|
295
299
|
<div className="text-caption font-mono text-fg-secondary">count = {count}</div>
|
|
296
300
|
</div>
|
|
@@ -381,7 +385,7 @@ export const ShapeMatrix: Story = {
|
|
|
381
385
|
</OverflowIndicator>
|
|
382
386
|
</Td>
|
|
383
387
|
<Td mono>tagVariants neutral · rounded-md · 同 Tag 視覺</Td>
|
|
384
|
-
<Td>Combobox multi-select tag 溢出
|
|
388
|
+
<Td>Combobox multi-select tag 溢出(Breadcrumb 收合走 BreadcrumbEllipsis canonical,非本元件)</Td>
|
|
385
389
|
</tr>
|
|
386
390
|
</tbody>
|
|
387
391
|
</table>
|
|
@@ -545,7 +549,7 @@ export const Accessibility = {
|
|
|
545
549
|
render: () => (
|
|
546
550
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
547
551
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
548
|
-
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0;不掛 role/aria-haspopup——無 activation 行為的宣告是對 AT 空承諾,2026-07-14 對齊 Avatar hoverCard canonical 拆除;2026-06-01 #13 由純 passive 改 focusable,修 WCAG 2.1.1 違反)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger 是 tab stop(focus-visible ring,鍵盤使用者可 focus 開啟 HoverCard 看溢出內容);HoverCard
|
|
552
|
+
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0;不掛 role/aria-haspopup——無 activation 行為的宣告是對 AT 空承諾,2026-07-14 對齊 Avatar hoverCard canonical 拆除;2026-06-01 #13 由純 passive 改 focusable,修 WCAG 2.1.1 違反)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger 是 tab stop(focus-visible ring,鍵盤使用者可 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的內容不接受鍵盤 focus——Radix 強制 content 內 tabbable node 為 tabindex=-1,鍵盤等效操作由主列可見項承擔,需鍵盤可操作的互動浮層改用 Popover(click 觸發)。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。"}</p>
|
|
549
553
|
</div>
|
|
550
554
|
),
|
|
551
555
|
}
|
|
@@ -29,9 +29,6 @@ export const UsageGuidance: Story = {
|
|
|
29
29
|
<li>
|
|
30
30
|
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="人員頭像 疊合 +N"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">PR reviewer 頭像疊合 +N(只顯前 3 位)</span></LinkTo>
|
|
31
31
|
</li>
|
|
32
|
-
<li>
|
|
33
|
-
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="Breadcrumb 中段收合"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Breadcrumb 中段收合</span></LinkTo>
|
|
34
|
-
</li>
|
|
35
32
|
<li>
|
|
36
33
|
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="DataTable 人員欄位"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">DataTable 人員欄位</span></LinkTo>
|
|
37
34
|
</li>
|
|
@@ -43,10 +40,10 @@ export const UsageGuidance: Story = {
|
|
|
43
40
|
<div className="prose prose-sm max-w-prose">
|
|
44
41
|
<p>處理超出空間的 2 種策略:</p>
|
|
45
42
|
<ul>
|
|
46
|
-
<li><strong>OverflowIndicator(本元件)</strong>—項目數量已知且不多時,顯示前幾個、其餘折成 <code>+N</code
|
|
43
|
+
<li><strong>OverflowIndicator(本元件)</strong>—項目數量已知且不多時,顯示前幾個、其餘折成 <code>+N</code>,hover 展開看完整清單</li>
|
|
47
44
|
<li><strong>ScrollArea</strong>—項目數量未知或極多時,讓使用者捲動瀏覽全部</li>
|
|
48
45
|
</ul>
|
|
49
|
-
<p className="text-fg-muted"
|
|
46
|
+
<p className="text-fg-muted">判斷:項目少量、已知、適合一次預覽 → OverflowIndicator;數量大、未知或需連續瀏覽 → ScrollArea。</p>
|
|
50
47
|
</div>
|
|
51
48
|
</div>
|
|
52
49
|
),
|
|
@@ -67,8 +64,10 @@ export const CompositionRules: Story = {
|
|
|
67
64
|
<h4>Pattern 2 — 人員頭像疊合 +N</h4>
|
|
68
65
|
<p>一群人只顯示前幾位、其餘折成 `+M`。目前由列表元件自行把頭像疊合再放上 OverflowIndicator(形狀用圓形對齊頭像);未來規劃中的 Avatar 群組元件會把這段組合收進去。對齊 Slack 工作區成員預覽 / Linear 團隊成員的做法。</p>
|
|
69
66
|
|
|
70
|
-
<h4>Pattern 3 —
|
|
71
|
-
<p
|
|
67
|
+
<h4>Pattern 3 — PeoplePicker 人員選擇欄位 +N</h4>
|
|
68
|
+
<p>人員選擇欄位選了多位、單行放不下 → PeoplePicker(<code>PersonDisplay</code>)內部使用 OverflowIndicator(圓形對齊頭像),hover `+N` 展開完整名單。對齊 Linear 多指派人 / Jira watchers 的做法。</p>
|
|
69
|
+
|
|
70
|
+
<p className="text-fg-muted">水平容器(Tabs / 單行 chip 列)寬度不夠時<strong className="font-medium">不用本元件</strong>——DS canonical 是 <code>horizontal-overflow</code> 的 <code>OverflowMenuTriggerButton</code> + DropdownMenu(click 開選單,見 horizontal-overflow.spec.md);Breadcrumb 中段收合走 BreadcrumbEllipsis + DropdownMenu(見 breadcrumb.spec.md)。兩者皆 click 開選單,與本元件 hover 展開語義不同。</p>
|
|
72
71
|
|
|
73
72
|
<p className="text-fg-muted">禁止:在頁面程式碼裡自己手刻 `+N` <code><span></code>(會失去 hover 展開浮層與一致的形狀樣式)— 一律使用 OverflowIndicator。</p>
|
|
74
73
|
</div>
|
|
@@ -124,6 +124,6 @@ OverflowIndicator 是 **composite**(HoverCard trigger + tag-styled `+N` span + H
|
|
|
124
124
|
|
|
125
125
|
**互動行為**:trigger 為 `+N` 計數 span,**keyboard-focusable**(`tabIndex=0`;**不掛 `role="button"` / `aria-haspopup`**——2026-07-14 對齊 Avatar hoverCard canonical 2026-07-06 拆除:trigger 無 activation 行為,宣告 button/haspopup 卻按 Enter 無反應 = 對 AT 空承諾),HoverCard 在 hover 或 trigger 取得 focus 時自動展開——無「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。(2026-06-01 #13:原設計純 passive 不可聚焦 → 鍵盤使用者無法開啟 HoverCard 看溢出內容,違 WCAG 2.1.1;改 focusable)。**鍵盤限制**:HoverCard 內容(tag dismiss / nested ProfileCard)僅滑鼠可互動——Radix 把 content 內 tabbable node 設 `tabindex="-1"`(hover-card.spec.md「A11y 預設」),鍵盤等效操作由主列可見項承擔。
|
|
126
126
|
|
|
127
|
-
**Focus**:trigger 是 tab stop(keyboard 可達 + focus-visible ring,讓鍵盤使用者也能 focus 開啟 HoverCard 看溢出內容);HoverCard
|
|
127
|
+
**Focus**:trigger 是 tab stop(keyboard 可達 + focus-visible ring,讓鍵盤使用者也能 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的內容**不接受鍵盤 focus**——Radix 強制 content 內 tabbable node 為 `tabindex="-1"`(見上方「互動行為」鍵盤限制 + `hover-card.spec.md`「A11y 預設」),鍵盤等效操作由主列可見項承擔;需鍵盤可操作的互動浮層改用 Popover(click 觸發)。
|
|
128
128
|
|
|
129
129
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
@@ -129,38 +129,14 @@ export const AvatarStackOverflow: Story = {
|
|
|
129
129
|
// (overflow-indicator.anatomy.stories.tsx)完整覆蓋,展示層只留真實業務場景;
|
|
130
130
|
// principles UsageGuidance 對應 LinkTo 已同步移除。
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
name: 'Breadcrumb 中段收合',
|
|
138
|
-
render: () => (
|
|
139
|
-
<div className="flex flex-col gap-3 max-w-lg">
|
|
140
|
-
<p className="text-caption text-fg-muted">
|
|
141
|
-
深層路徑過長時,中段收合為 +N,hover 看完整路徑。
|
|
142
|
-
</p>
|
|
143
|
-
<nav className="flex items-center gap-1 text-caption">
|
|
144
|
-
<span className="text-fg-muted hover:text-foreground cursor-pointer">Projects</span>
|
|
145
|
-
<span className="text-fg-muted">/</span>
|
|
146
|
-
<OverflowIndicator count={3} shape="tag" size="sm">
|
|
147
|
-
<div className="flex flex-col gap-1 text-caption">
|
|
148
|
-
<span>Platform</span>
|
|
149
|
-
<span>Infrastructure</span>
|
|
150
|
-
<span>Monitoring</span>
|
|
151
|
-
</div>
|
|
152
|
-
</OverflowIndicator>
|
|
153
|
-
<span className="text-fg-muted">/</span>
|
|
154
|
-
<span className="text-fg-muted hover:text-foreground cursor-pointer">Dashboards</span>
|
|
155
|
-
<span className="text-fg-muted">/</span>
|
|
156
|
-
<span className="text-foreground font-medium">API latency</span>
|
|
157
|
-
</nav>
|
|
158
|
-
</div>
|
|
159
|
-
),
|
|
160
|
-
}
|
|
132
|
+
// @story-trait-rationale: BreadcrumbCollapse(Breadcrumb 中段收合)retired 2026-07-16 per
|
|
133
|
+
// deep-audit A.1b — DS Breadcrumb 收合 canonical = BreadcrumbEllipsis + DropdownMenu(click 開選單,
|
|
134
|
+
// breadcrumb.spec.md「BreadcrumbEllipsis」段),Breadcrumb 全庫零 OverflowIndicator 消費;
|
|
135
|
+
// 本 story 示範與 canonical 相左的 hover +N 收合 = 誤導 consumer,故 retire;
|
|
136
|
+
// principles UsageGuidance 對應 LinkTo 已同步移除。
|
|
161
137
|
|
|
162
138
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
163
|
-
Story
|
|
139
|
+
Story 3:DataTable row 的指派人員溢出
|
|
164
140
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
165
141
|
|
|
166
142
|
const rows = [
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 4. **架構違反**:`MultiPersonDisplay` display path 用 canvas-based 算 / Combobox edit path 用 DOM offsetWidth
|
|
11
11
|
* → 同 cell width 兩 path 不同結果 → user verbatim「同寬 cell overflow 時間不一樣」SSOT 根本被違反
|
|
12
12
|
*
|
|
13
|
-
* **Fix**(per codex Q3 consensus):抽 pure formula + React hook,
|
|
13
|
+
* **Fix**(per codex Q3 consensus):抽 pure formula + React hook,view + edit 兩 path **共用**。
|
|
14
14
|
*
|
|
15
15
|
* **Deterministic formula**:
|
|
16
16
|
* ```
|
|
@@ -31,6 +31,7 @@ export const Overview: Story = {
|
|
|
31
31
|
people={SAMPLE_PEOPLE}
|
|
32
32
|
value={SAMPLE_PEOPLE[0]}
|
|
33
33
|
onChange={() => {}}
|
|
34
|
+
aria-label="負責人"
|
|
34
35
|
/>
|
|
35
36
|
</div>
|
|
36
37
|
</div>
|
|
@@ -45,6 +46,7 @@ export const Overview: Story = {
|
|
|
45
46
|
people={SAMPLE_PEOPLE}
|
|
46
47
|
value={SAMPLE_PEOPLE[0]}
|
|
47
48
|
onChange={() => {}}
|
|
49
|
+
aria-label="指派對象(單選 assignee 範例)"
|
|
48
50
|
/>
|
|
49
51
|
</div>
|
|
50
52
|
<div>
|
|
@@ -53,6 +55,7 @@ export const Overview: Story = {
|
|
|
53
55
|
people={SAMPLE_PEOPLE}
|
|
54
56
|
value={[SAMPLE_PEOPLE[0], SAMPLE_PEOPLE[1]]}
|
|
55
57
|
onChange={() => {}}
|
|
58
|
+
aria-label="專案協作者(多選 reviewers 範例)"
|
|
56
59
|
/>
|
|
57
60
|
</div>
|
|
58
61
|
</div>
|
|
@@ -65,7 +68,7 @@ export const Overview: Story = {
|
|
|
65
68
|
<thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
|
|
66
69
|
<tbody>
|
|
67
70
|
{[
|
|
68
|
-
['mode', "'edit' | '
|
|
71
|
+
['mode', "'edit' | 'view' | 'readonly' | 'disabled'", "'edit'", 'Field mode'],
|
|
69
72
|
['variant', "'default'", "'default'", 'Field chrome variant(對齊 Select / Combobox;naked = @internal cell-as-input,2026-07-14 型別收窄至 FieldVariantInternal)'],
|
|
70
73
|
['size', "'sm' | 'md' | 'lg'", "'md'", '對齊 field-height tier'],
|
|
71
74
|
['value', 'PersonValue | PersonValue[] | null', '—', '單選 / 多選(類型決定模式)'],
|
|
@@ -78,7 +81,7 @@ export const Overview: Story = {
|
|
|
78
81
|
['pillShowAvatar', 'boolean', 'true', "multiDisplay='pill' 時是否顯示 avatar prefix"],
|
|
79
82
|
['pillWrap', 'boolean', 'true', 'pill 模式是否允許換行'],
|
|
80
83
|
['searchIn', "'menu' | 'trigger'", "'menu'", '搜尋型態(menu 浮層內 / trigger inline;multi 才有意義)'],
|
|
81
|
-
['showDisplayEndIcon', 'boolean', 'false', '
|
|
84
|
+
['showDisplayEndIcon', 'boolean', 'false', 'view 模式渲 ChevronDown + naked wrapper(opt-in 逃生門;2026-07-08 A 案後 DataTable 預設不傳)'],
|
|
82
85
|
['defaultOpen', 'boolean', 'false', 'uncontrolled 初始開啟狀態'],
|
|
83
86
|
['onOpenChange', '(open: boolean) => void', '—', 'open 狀態變更 callback'],
|
|
84
87
|
['disabled', 'boolean', 'false', '停用'],
|
|
@@ -97,7 +100,7 @@ export const Overview: Story = {
|
|
|
97
100
|
export const Inspector: Story = {
|
|
98
101
|
name: '元件檢閱器',
|
|
99
102
|
parameters: {
|
|
100
|
-
docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit /
|
|
103
|
+
docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit / view / readonly / disabled 視覺差異,切 `size` 對照 field-height tier,切 `variant` 看 default / naked chrome 差異。' } },
|
|
101
104
|
},
|
|
102
105
|
args: {
|
|
103
106
|
mode: 'edit',
|
|
@@ -111,7 +114,7 @@ export const Inspector: Story = {
|
|
|
111
114
|
emptyText: '沒有符合的人員',
|
|
112
115
|
},
|
|
113
116
|
argTypes: {
|
|
114
|
-
mode: { control: 'radio', options: ['edit', '
|
|
117
|
+
mode: { control: 'radio', options: ['edit', 'view', 'readonly', 'disabled'] },
|
|
115
118
|
variant: { control: 'radio', options: ['default', 'naked'] },
|
|
116
119
|
size: { control: 'radio', options: ['sm', 'md', 'lg'] },
|
|
117
120
|
disabled: { control: 'boolean' },
|
|
@@ -121,7 +124,7 @@ export const Inspector: Story = {
|
|
|
121
124
|
},
|
|
122
125
|
render: (args) => (
|
|
123
126
|
<div className="max-w-md">
|
|
124
|
-
<PeoplePicker {...args} onChange={() => {}} />
|
|
127
|
+
<PeoplePicker {...args} onChange={() => {}} aria-label="負責人(Inspector 範例)" />
|
|
125
128
|
</div>
|
|
126
129
|
),
|
|
127
130
|
}
|
|
@@ -133,12 +136,12 @@ export const ModeMatrix: Story = {
|
|
|
133
136
|
<div>
|
|
134
137
|
<H3>edit(預設)</H3>
|
|
135
138
|
<Desc>Field 樣式 + 展開觸發 Popover + Command 搜尋。</Desc>
|
|
136
|
-
<PeoplePicker people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} onChange={() => {}} />
|
|
139
|
+
<PeoplePicker people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} onChange={() => {}} aria-label="負責人(edit 模式範例)" />
|
|
137
140
|
</div>
|
|
138
141
|
<div>
|
|
139
|
-
<H3>
|
|
142
|
+
<H3>view</H3>
|
|
140
143
|
<Desc>裸 PersonDisplay(Avatar + Name),無 field chrome——DataTable cell / detail panel 純顯示。</Desc>
|
|
141
|
-
<PeoplePicker mode="
|
|
144
|
+
<PeoplePicker mode="view" people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} />
|
|
142
145
|
</div>
|
|
143
146
|
<div>
|
|
144
147
|
<H3>readonly</H3>
|
|
@@ -341,8 +344,8 @@ export const StateBehavior: Story = {
|
|
|
341
344
|
people={SAMPLE_PEOPLE}
|
|
342
345
|
value={null}
|
|
343
346
|
onChange={() => {}}
|
|
344
|
-
searchPlaceholder="
|
|
345
|
-
emptyText="找不到符合的組員
|
|
347
|
+
searchPlaceholder="搜尋團隊成員…"
|
|
348
|
+
emptyText="找不到符合的組員"
|
|
346
349
|
/>
|
|
347
350
|
</div>
|
|
348
351
|
|
|
@@ -79,6 +79,7 @@ export const UsageGuidance: Story = {
|
|
|
79
79
|
value={assignee}
|
|
80
80
|
onChange={(v) => setAssignee(Array.isArray(v) ? v[0] : v)}
|
|
81
81
|
people={team}
|
|
82
|
+
aria-label="task 負責人"
|
|
82
83
|
/>
|
|
83
84
|
</div>
|
|
84
85
|
</Rule>
|
|
@@ -115,6 +116,7 @@ export const UsageGuidance: Story = {
|
|
|
115
116
|
]}
|
|
116
117
|
value={tags}
|
|
117
118
|
onChange={setTags}
|
|
119
|
+
aria-label="技術 stack(多選 Combobox)"
|
|
118
120
|
/>
|
|
119
121
|
<Label>↑ 技術 stack 是分類多選,不是人員,用 Combobox</Label>
|
|
120
122
|
</Rule>
|
|
@@ -140,6 +142,7 @@ export const SingleVsMultiRule: Story = {
|
|
|
140
142
|
value={assignee}
|
|
141
143
|
onChange={(v) => setAssignee(Array.isArray(v) ? v[0] : v)}
|
|
142
144
|
people={team}
|
|
145
|
+
aria-label="task 負責人(單選)"
|
|
143
146
|
/>
|
|
144
147
|
<Label>↑ 指派 task:assignee 通常一人</Label>
|
|
145
148
|
</Rule>
|
|
@@ -152,6 +155,7 @@ export const SingleVsMultiRule: Story = {
|
|
|
152
155
|
value={reviewers}
|
|
153
156
|
onChange={(v) => setReviewers(Array.isArray(v) ? v : [v])}
|
|
154
157
|
people={team}
|
|
158
|
+
aria-label="PR reviewers(多選)"
|
|
155
159
|
/>
|
|
156
160
|
<Label>↑ PR reviewers:可選多人,已選 {reviewers.length} 人</Label>
|
|
157
161
|
</Rule>
|
|
@@ -177,7 +181,7 @@ export const EmptyStateRule: Story = {
|
|
|
177
181
|
title="edit 模式 — 未選時顯示「請選擇人員」佔位提示"
|
|
178
182
|
note="跟 Select / Combobox 的 placeholder 行為一致。不用半形連字號,因為 edit mode 是可操作的"
|
|
179
183
|
>
|
|
180
|
-
<PeoplePicker value={null} onChange={() => {}} people={team} />
|
|
184
|
+
<PeoplePicker value={null} onChange={() => {}} people={team} aria-label="指派人員(空值 placeholder demo)" />
|
|
181
185
|
</Rule>
|
|
182
186
|
|
|
183
187
|
<Rule
|
|
@@ -60,7 +60,7 @@ const samplePeople = [
|
|
|
60
60
|
},
|
|
61
61
|
]
|
|
62
62
|
|
|
63
|
-
// @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add
|
|
63
|
+
// @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add view mode card to mode showcase only.
|
|
64
64
|
/* ── 單人(互動) ── */
|
|
65
65
|
const SinglePicker = () => {
|
|
66
66
|
const [val, setVal] = React.useState<PersonValue | null>(samplePeople[0])
|
|
@@ -72,8 +72,8 @@ const SinglePicker = () => {
|
|
|
72
72
|
</div>
|
|
73
73
|
{/* @story-trait-rationale: pre-existing trait gaps tracked separately */}
|
|
74
74
|
<div>
|
|
75
|
-
<h3 className="text-body font-bold text-foreground mb-2">
|
|
76
|
-
<PeoplePicker mode="
|
|
75
|
+
<h3 className="text-body font-bold text-foreground mb-2">view</h3>
|
|
76
|
+
<PeoplePicker mode="view" value={samplePeople[0]} />
|
|
77
77
|
</div>
|
|
78
78
|
<div>
|
|
79
79
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
@@ -100,7 +100,7 @@ const MultiPicker = () => {
|
|
|
100
100
|
<div className="flex flex-col gap-6 max-w-xs">
|
|
101
101
|
<div>
|
|
102
102
|
<h3 className="text-body font-bold text-foreground mb-2">edit(可互動,多選)</h3>
|
|
103
|
-
<PeoplePicker value={val} people={samplePeople} onChange={setVal} />
|
|
103
|
+
<PeoplePicker value={val} people={samplePeople} onChange={setVal} aria-label="專案協作者(edit multi demo)" />
|
|
104
104
|
</div>
|
|
105
105
|
<div>
|
|
106
106
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
@@ -120,7 +120,7 @@ const SizePicker = ({ size }: { size: 'sm' | 'md' | 'lg' }) => {
|
|
|
120
120
|
const [val, setVal] = React.useState<PersonValue | null>(samplePeople[0])
|
|
121
121
|
return (
|
|
122
122
|
<div className="flex items-center gap-3">
|
|
123
|
-
<PeoplePicker size={size} value={val} people={samplePeople} onChange={(v) => setVal(v[0] ?? null)} className="max-w-xs" />
|
|
123
|
+
<PeoplePicker size={size} value={val} people={samplePeople} onChange={(v) => setVal(v[0] ?? null)} className="max-w-xs" aria-label={`負責人(size=${size})`} />
|
|
124
124
|
<Button variant="primary" size={size}>送出</Button>
|
|
125
125
|
<span className="text-caption text-fg-muted">size="{size}"</span>
|
|
126
126
|
</div>
|
|
@@ -48,7 +48,7 @@ export { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass }
|
|
|
48
48
|
// 差別在 tagRenderer 視覺):
|
|
49
49
|
// - **'stack'**(default,baseline 既有視覺)— Avatar 疊合 + `+N` overflow indicator,
|
|
50
50
|
// 不可 wrap。tagRenderer 渲染 avatar stack(visible count 走 shared `avatar-stack-overflow`
|
|
51
|
-
// primitive deterministic formula,2026-05-15 Bug 3 fix;
|
|
51
|
+
// primitive deterministic formula,2026-05-15 Bug 3 fix;view 路徑 `<MultiPersonDisplay>` 同 primitive)。
|
|
52
52
|
// 對齊 Notion / Linear / Atlassian / Slack 多人 quick-glance idiom。
|
|
53
53
|
// - **'pill'**(opt-in)— 每人 Tag pill,可 wrap。Wrap `<Combobox tagRenderer>`,
|
|
54
54
|
// tagRenderer 用 Tag 元件 `avatar` prop SSOT(不塞 children)。
|
|
@@ -59,8 +59,12 @@ export { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass }
|
|
|
59
59
|
// 讓 consumer 可傳 `id` / `data-testid` / `onBlur` / `onFocus` / `aria-*` 等 HTML root props,
|
|
60
60
|
// component 內部 `...rest` forward 到 trigger 容器(對齊 DS 既有 Combobox / Select 慣例)。
|
|
61
61
|
// `onChange` 衝突走 Omit(本 component 用 PersonValue[] custom signature)。
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// 2026-07-17 Dim 26 修:`defaultValue` 一併 Omit — 本元件 controlled-only(spec「Controlled-only
|
|
63
|
+
// rationale」),React.HTMLAttributes 內建的 `defaultValue` 若不 Omit 會讓 consumer 傳入假
|
|
64
|
+
// uncontrolled API,runtime 經 `...rest` 靜默轉送 trigger div 後無效。Omit 本身即 type-level
|
|
65
|
+
// regression(consumer 傳 defaultValue 直接 TS 編譯錯)。DS 先例 steps.tsx:166 同款 Omit。
|
|
66
|
+
export interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'> {
|
|
67
|
+
/** Field mode(edit / view / readonly / disabled),默認 inherit Field context 或 'edit' */
|
|
64
68
|
mode?: FieldMode
|
|
65
69
|
/** Field chrome variant(對齊 Select / Combobox)*/
|
|
66
70
|
variant?: FieldVariant
|
|
@@ -113,9 +117,9 @@ export interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElem
|
|
|
113
117
|
*/
|
|
114
118
|
searchIn?: 'menu' | 'trigger'
|
|
115
119
|
/**
|
|
116
|
-
*
|
|
117
|
-
* — DataTable cell
|
|
118
|
-
* 設 true 時
|
|
120
|
+
* View 態是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)
|
|
121
|
+
* — DataTable cell view↔edit 像素級對齊用。預設 false(裸 PersonDisplay,backward compat)。
|
|
122
|
+
* 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,
|
|
119
123
|
* 與 edit (Select / Combobox wrapped) 同 DOM 結構,消除 Layer-B padding mismatch。
|
|
120
124
|
*/
|
|
121
125
|
showDisplayEndIcon?: boolean
|
|
@@ -156,8 +160,8 @@ const PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(functio
|
|
|
156
160
|
const isMulti = Array.isArray(value)
|
|
157
161
|
const isEmpty = !value || (isMulti && value.length === 0)
|
|
158
162
|
|
|
159
|
-
// 2026-07-05 D3 P0 修:以下派生 + 4 hooks 原宣告在
|
|
160
|
-
// 之後 — 同一 mounted instance 的 resolvedMode 於 edit↔
|
|
163
|
+
// 2026-07-05 D3 P0 修:以下派生 + 4 hooks 原宣告在 view/readonly/single/pill 四個 early return
|
|
164
|
+
// 之後 — 同一 mounted instance 的 resolvedMode 於 edit↔view/disabled 切換(<Field mode>/<Field
|
|
161
165
|
// disabled> cascade 正是 runtime 翻轉機制)時 hook 數 7→11 變動 → React #310 crash(與 Combobox
|
|
162
166
|
// beta.76 / LinkInput 2026-07-04 同家族)。全部 hoist 到任何 early return 之前(對齊 select.tsx
|
|
163
167
|
// 「所有 hooks 必在 early return 前 call」canonical);effect 加 mode/stack guard,邏輯不變。
|
|
@@ -206,23 +210,38 @@ const PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(functio
|
|
|
206
210
|
else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = el
|
|
207
211
|
}, [ref])
|
|
208
212
|
|
|
209
|
-
// ── mode='
|
|
213
|
+
// ── mode='view' ────────────────────────────────────────────────────────
|
|
210
214
|
// Default(showDisplayEndIcon=false):裸 PersonDisplay / MultiPersonDisplay — backward compat。
|
|
211
215
|
// Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,
|
|
212
|
-
// 與 edit (Select / Combobox wrapped) 同 DOM 結構消除 cell
|
|
213
|
-
if (resolvedMode === '
|
|
216
|
+
// 與 edit (Select / Combobox wrapped) 同 DOM 結構消除 cell view↔edit 像素偏移。
|
|
217
|
+
if (resolvedMode === 'view') {
|
|
214
218
|
if (!showDisplayEndIcon) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
// 2026-07-17 Dim 9 修:裸顯示分支原直接 return PersonDisplay/MultiPersonDisplay/span,
|
|
220
|
+
// 遺失 ref / className / DOM-safe rest props(違 spec「forwardRef + 單一 root」root props 契約,
|
|
221
|
+
// 與 readonly/disabled 分支不對稱)。補穩定 forwarding root:`w-full min-w-0` 保留
|
|
222
|
+
// PersonDisplay 既有 w-full truncate 寬度約束鏈(單人 fill + 多人 stack 左靠不變),
|
|
223
|
+
// 對齊 switch.tsx:209 view 分支轉發先例。
|
|
224
|
+
return (
|
|
225
|
+
<div ref={ref} className={cn('w-full min-w-0', className)} aria-label={ariaLabel} {...rest}>
|
|
226
|
+
{isEmpty
|
|
227
|
+
? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>
|
|
228
|
+
: isMulti
|
|
229
|
+
? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />
|
|
230
|
+
: <PersonDisplay value={value as PersonValue} size={size} />}
|
|
231
|
+
</div>
|
|
232
|
+
)
|
|
219
233
|
}
|
|
220
234
|
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
|
|
221
235
|
const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
222
236
|
return (
|
|
223
237
|
<div
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
// 2026-07-17 Dim 9 修:D-path view root 補 ref / aria-label / {...rest} 轉發(原只套 className,
|
|
239
|
+
// 遺失 root props;對齊 readonly/disabled 分支與 spec root props 契約)。
|
|
240
|
+
ref={ref}
|
|
241
|
+
className={cn(fieldWrapperStyles({ mode: 'view', variant: resolvedVariant, width, size }), className)}
|
|
242
|
+
data-field-mode="view"
|
|
243
|
+
aria-label={ariaLabel}
|
|
244
|
+
{...rest}
|
|
226
245
|
>
|
|
227
246
|
<span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign)}>
|
|
228
247
|
{isEmpty
|
|
@@ -371,7 +390,7 @@ const PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(functio
|
|
|
371
390
|
// **2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus)**:visible count 走 shared
|
|
372
391
|
// `avatar-stack-overflow` primitive deterministic formula(取代 Combobox DOM offsetWidth-based
|
|
373
392
|
// useOverflowCount + 60px fallback 不 deterministic),pass override 給 Combobox bypass internal
|
|
374
|
-
// measurement。`MultiPersonDisplay`(
|
|
393
|
+
// measurement。`MultiPersonDisplay`(view path)同 primitive,view + edit 結果一致。
|
|
375
394
|
// 對齊 user verbatim SSOT「同 cell width 同 overflow 判斷」+ codex Q3 consensus shared primitive。
|
|
376
395
|
const handleMultiChange = (next: string[]) => {
|
|
377
396
|
onChange?.(next.map(name => findPerson(people, name)))
|
|
@@ -430,10 +449,10 @@ const PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(functio
|
|
|
430
449
|
// 既有 OverflowIndicator default 'circle' SSOT。
|
|
431
450
|
overflowShape="circle"
|
|
432
451
|
// 2026-05-15 Bug 3 fix:formula-based visible count override(避免 Combobox DOM measurement +
|
|
433
|
-
// 60px fallback 不 deterministic)。SSOT in `./avatar-stack-overflow.ts`,
|
|
452
|
+
// 60px fallback 不 deterministic)。SSOT in `./avatar-stack-overflow.ts`,view + edit 共用。
|
|
434
453
|
visibleCountOverride={stackVisibleCount}
|
|
435
454
|
// 2026-05-14 I4 fix(per codex+Layer A 共識):hidden items 在 `+N` overflow popover 顯
|
|
436
|
-
// Tag with avatar(對齊
|
|
455
|
+
// Tag with avatar(對齊 view path MultiPersonDisplay popover SSOT,user 抓 display vs edit
|
|
437
456
|
// overflow 視覺不一致)。
|
|
438
457
|
renderHiddenTag={(item) => {
|
|
439
458
|
const p = resolvePerson(findPerson(people, item.value))
|
|
@@ -186,7 +186,7 @@ function MultiPersonDisplay({
|
|
|
186
186
|
max?: number
|
|
187
187
|
/**
|
|
188
188
|
* 2026-05-15 codex Round 5 C+ SSOT fix:`measured=true` 啟動 container-width 量測(取代 hardcode `max ?? 3`)
|
|
189
|
-
* →
|
|
189
|
+
* → view + edit stack 同 algorithm(同 cell width → 同 overflow 判斷),不再 view 用固定 3 vs edit
|
|
190
190
|
* 用 useOverflowCount。對齊 field-controls.spec.md:286 「4-mode 共享 renderer」contract + user round 3
|
|
191
191
|
* verbatim「同空間兩判斷點」SSOT directive。Default false 保 backward compat(non-cell context 仍 max ?? 3)。
|
|
192
192
|
*/
|
|
@@ -201,8 +201,8 @@ function MultiPersonDisplay({
|
|
|
201
201
|
// 切換時 hook 數 0↔3 變動必 crash(現靠 consumer 三元切換 element type 偶然避開)。hoist 到 return 前。
|
|
202
202
|
// 2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus):消費 shared `avatar-stack-overflow`
|
|
203
203
|
// primitive。原 inline canvas-based formula 是 dual-implementation 違反 user SSOT「同 cell width 同
|
|
204
|
-
// overflow 判斷」(edit path 用 Combobox useOverflowCount DOM offsetWidth /
|
|
205
|
-
// canvas)。**抽 primitive 統一**:
|
|
204
|
+
// overflow 判斷」(edit path 用 Combobox useOverflowCount DOM offsetWidth / view path 用 inline
|
|
205
|
+
// canvas)。**抽 primitive 統一**:view + edit 共用 `getAvatarStackVisibleCount` formula。
|
|
206
206
|
// SSOT in `./avatar-stack-overflow.ts`,M14 mechanical guard 防 future drift。
|
|
207
207
|
const containerRef = React.useRef<HTMLSpanElement>(null)
|
|
208
208
|
const [measuredCount, setMeasuredCount] = React.useState<number | null>(null)
|
|
@@ -161,14 +161,17 @@ export const PlacementMatrix: Story = {
|
|
|
161
161
|
{(['top', 'right', 'bottom', 'left'] as const).flatMap(side =>
|
|
162
162
|
(['start', 'center', 'end'] as const).map(align => (
|
|
163
163
|
<div key={`${side}-${align}`} className="flex items-center gap-3 border border-dashed border-divider rounded-md p-3">
|
|
164
|
+
{/* side/align 屬定位參數,標在格外 caption(非浮層可見內容);浮層本體用真實使用情境 */}
|
|
165
|
+
<span className="text-caption font-mono text-fg-muted shrink-0 whitespace-nowrap">{side} / {align}</span>
|
|
166
|
+
{/* @overlay-open-skip:12-cell 定位矩陣示範 side×align 落點,全部 defaultOpen 會讓 12 個浮層互相重疊;點擊逐格開啟即可觀察定位,開啟態視覺覆蓋於 Inspector(defaultOpen) */}
|
|
164
167
|
<Popover>
|
|
165
168
|
<PopoverTrigger asChild>
|
|
166
|
-
<Button variant="tertiary" size="sm"
|
|
169
|
+
<Button variant="tertiary" size="sm">使用說明</Button>
|
|
167
170
|
</PopoverTrigger>
|
|
168
|
-
|
|
169
|
-
|
|
171
|
+
{/* naked popover(無 PopoverTitle)→ 自傳 aria-label 讓 role="dialog" 有 accessible name */}
|
|
172
|
+
<PopoverContent side={side} align={align} aria-label="使用說明">
|
|
173
|
+
<PopoverBody><div className="text-caption text-fg-secondary">拖曳卡片可調整優先順序,變更會即時同步給協作者。</div></PopoverBody>
|
|
170
174
|
</PopoverContent>
|
|
171
|
-
{/* each placement variant already wrapped in PopoverBody for consistent padding */}
|
|
172
175
|
</Popover>
|
|
173
176
|
</div>
|
|
174
177
|
))
|
|
@@ -218,13 +221,13 @@ export const SizeMatrix: Story = {
|
|
|
218
221
|
<div className="flex items-center gap-3 border border-dashed border-divider rounded-md p-3">
|
|
219
222
|
<span className="text-caption font-mono w-20">w-72(預設)</span>
|
|
220
223
|
<Popover><PopoverTrigger asChild><Button variant="tertiary" size="sm">開啟</Button></PopoverTrigger>
|
|
221
|
-
<PopoverContent><PopoverBody><div className="text-caption">預設寬度 w-72</div></PopoverBody></PopoverContent>
|
|
224
|
+
<PopoverContent aria-label="預設寬度示範"><PopoverBody><div className="text-caption">預設寬度 w-72</div></PopoverBody></PopoverContent>
|
|
222
225
|
</Popover>
|
|
223
226
|
</div>
|
|
224
227
|
<div className="flex items-center gap-3 border border-dashed border-divider rounded-md p-3">
|
|
225
228
|
<span className="text-caption font-mono w-20">w-96</span>
|
|
226
229
|
<Popover><PopoverTrigger asChild><Button variant="tertiary" size="sm">開啟</Button></PopoverTrigger>
|
|
227
|
-
<PopoverContent className="w-96"><PopoverBody><div className="text-caption">自訂 w-96</div></PopoverBody></PopoverContent>
|
|
230
|
+
<PopoverContent className="w-96" aria-label="自訂寬度示範"><PopoverBody><div className="text-caption">自訂 w-96</div></PopoverBody></PopoverContent>
|
|
228
231
|
</Popover>
|
|
229
232
|
</div>
|
|
230
233
|
</div>
|
|
@@ -244,7 +247,7 @@ export const StateBehavior: Story = {
|
|
|
244
247
|
<div className="flex flex-col gap-8">
|
|
245
248
|
<div>
|
|
246
249
|
<H3>開啟 / 關閉</H3>
|
|
247
|
-
<Desc>Radix 提供 data-state 切換 + DS Tailwind animate 驅動(popover.tsx
|
|
250
|
+
<Desc>Radix 提供 data-state 切換 + DS Tailwind animate 驅動(popover.tsx L105-106):進場 `fade-in + zoom-in-95 + slide-from-side`,離場 `fade-out + zoom-out`(無 slide-out,對齊 shadcn 慣例)。進場方向 side-aware slide,浮層看起來從 trigger 「長出來」。</Desc>
|
|
248
251
|
<ul className="text-caption text-fg-muted list-disc pl-5 space-y-1">
|
|
249
252
|
<li>點擊 trigger → 開啟</li>
|
|
250
253
|
<li>點 Popover 外部 → 關閉(click outside)</li>
|