@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +210 -0
- package/CLAUDE.md +17 -191
- package/cli-init.mjs +30 -2
- package/dist/components/Accordion/accordion.d.ts +2 -2
- package/dist/components/Accordion/accordion.d.ts.map +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Avatar/avatar.js +1 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button-group.d.ts +2 -2
- package/dist/components/Button/button-group.d.ts.map +1 -1
- package/dist/components/Button/button-group.js +2 -2
- package/dist/components/Button/button-group.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -1
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +1 -1
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +14 -8
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +64 -37
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js +21 -14
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +2 -2
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +49 -10
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +15 -6
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +13 -7
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +11 -2
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts +5 -5
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +41 -38
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +1 -17
- package/dist/components/DataTable/column-types.d.ts.map +1 -1
- package/dist/components/DataTable/column-types.js.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +3 -4
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +2 -2
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +44 -32
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +3 -3
- package/dist/components/DatePicker/date-picker.js +4 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.d.ts +3 -3
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
- package/dist/components/DescriptionList/description-list.js +6 -6
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +2 -2
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +16 -10
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-types.d.ts +2 -2
- package/dist/components/Field/field-types.d.ts.map +1 -1
- package/dist/components/Field/field-types.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +20 -4
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +30 -31
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +25 -3
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/use-form-validation.d.ts +1 -1
- package/dist/components/Field/use-form-validation.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +2 -5
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +5 -1
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +2 -1
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +2 -2
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +4 -2
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
- package/dist/components/InlineEdit/inline-edit.js +104 -62
- package/dist/components/InlineEdit/inline-edit.js.map +1 -1
- package/dist/components/Input/input.d.ts +1 -1
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +6 -6
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +5 -5
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +3 -3
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +17 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +7 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +12 -1
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +7 -5
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +1 -1
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +3 -3
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +1 -1
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.d.ts.map +1 -1
- package/dist/components/Rating/rating.js +4 -0
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts +16 -6
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +17 -5
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +17 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +17 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
- package/dist/components/SelectionControl/boolean-value.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +2 -2
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.js +2 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +6 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +6 -4
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +19 -5
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +4 -4
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -1
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +73 -23
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts +3 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +2 -2
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +4 -4
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +15 -15
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +4 -4
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -5
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +27 -23
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +16 -0
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/drag-visual.d.ts +2 -2
- package/dist/lib/drag-visual.js.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +21 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +3 -3
- package/dist/tokens/categorical-color.d.ts.map +1 -1
- package/dist/tokens/categorical-color.js +2 -2
- package/dist/tokens/categorical-color.js.map +1 -1
- package/ds-canonical/fork/AGENTS.md +213 -0
- package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
- package/ds-canonical/fork/codex/hooks.json +16 -0
- package/ds-canonical/fork/governance.lock +22 -7
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/fork/manifest.json +10 -1
- package/ds-canonical/fork/preamble.md +3 -2
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
- package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
- package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
- package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
- package/ds-canonical/references/certified-surfaces.md +20 -0
- package/ds-canonical/references/preflight-gate-baseline.json +5 -0
- package/ds-canonical/references/principle-dim-map.json +20 -2
- package/ds-canonical/references/props-naming.md +2 -1
- package/ds-canonical/references/ssot-index.md +2 -2
- package/ds-canonical/references/story-baseline-registry.json +2 -2
- package/ds-canonical/rules/story-rules.md +1 -1
- package/ds-canonical/rules/ui-development.md +2 -1
- package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
- package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
- package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
- package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
- package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
- package/ds-story-manifest.json +21 -21
- package/llms-full.txt +3 -3
- package/llms.txt +1 -1
- package/package.json +2 -1
- package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
- package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
- package/src/components/Accordion/accordion.spec.md +10 -1
- package/src/components/Accordion/accordion.stories.tsx +10 -5
- package/src/components/Accordion/accordion.tsx +7 -2
- package/src/components/Alert/alert.principles.stories.tsx +2 -8
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
- package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
- package/src/components/AppShell/app-shell.spec.md +4 -0
- package/src/components/AppShell/app-shell.stories.tsx +4 -5
- package/src/components/Avatar/avatar.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -2
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
- package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
- package/src/components/Button/button-group.tsx +4 -4
- package/src/components/Button/button.anatomy.stories.tsx +26 -7
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.stories.tsx +22 -28
- package/src/components/Button/button.tsx +2 -1
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +1 -1
- package/src/components/Carousel/carousel.spec.md +17 -1
- package/src/components/Carousel/carousel.tsx +93 -42
- package/src/components/Checkbox/checkbox-group.tsx +26 -15
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
- package/src/components/Checkbox/checkbox.spec.md +12 -3
- package/src/components/Checkbox/checkbox.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.tsx +79 -19
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
- package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
- package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
- package/src/components/Combobox/combobox.spec.md +6 -2
- package/src/components/Combobox/combobox.stories.tsx +9 -36
- package/src/components/Combobox/combobox.tsx +42 -27
- package/src/components/Command/command.spec.md +3 -3
- package/src/components/Command/command.tsx +9 -2
- package/src/components/DataTable/cell-registry.tsx +75 -76
- package/src/components/DataTable/column-types.ts +4 -17
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
- package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
- package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
- package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
- package/src/components/DataTable/data-table.css +2 -3
- package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
- package/src/components/DataTable/data-table.spec.md +7 -7
- package/src/components/DataTable/data-table.stories.tsx +39 -29
- package/src/components/DataTable/data-table.tsx +90 -67
- package/src/components/DataTable/filter-operators.spec.md +2 -0
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
- package/src/components/DatePicker/date-picker.spec.md +9 -9
- package/src/components/DatePicker/date-picker.stories.tsx +9 -9
- package/src/components/DatePicker/date-picker.tsx +13 -13
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +12 -12
- package/src/components/DescriptionList/description-list.stories.tsx +3 -3
- package/src/components/DescriptionList/description-list.tsx +10 -10
- package/src/components/Dialog/dialog.tsx +4 -1
- package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
- package/src/components/Field/field-context.ts +17 -11
- package/src/components/Field/field-controls.spec.md +44 -37
- package/src/components/Field/field-types.ts +14 -12
- package/src/components/Field/field-wrapper.tsx +59 -43
- package/src/components/Field/field.anatomy.stories.tsx +6 -6
- package/src/components/Field/field.principles.stories.tsx +5 -28
- package/src/components/Field/field.spec.md +4 -4
- package/src/components/Field/field.stories.tsx +103 -72
- package/src/components/Field/field.tsx +36 -4
- package/src/components/Field/form-validation.spec.md +2 -0
- package/src/components/Field/use-form-validation.ts +1 -1
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
- package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
- package/src/components/FileItem/file-item.tsx +10 -8
- package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
- package/src/components/FileUpload/file-upload.spec.md +3 -2
- package/src/components/FileUpload/file-upload.tsx +5 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.spec.md +1 -1
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
- package/src/components/FileViewer/file-viewer.tsx +3 -2
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
- package/src/components/HoverCard/hover-card.spec.md +2 -2
- package/src/components/HoverCard/hover-card.tsx +4 -2
- package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
- package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
- package/src/components/InlineEdit/inline-edit.spec.md +71 -46
- package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
- package/src/components/InlineEdit/inline-edit.tsx +211 -125
- package/src/components/Input/input.anatomy.stories.tsx +15 -15
- package/src/components/Input/input.principles.stories.tsx +3 -3
- package/src/components/Input/input.spec.md +4 -4
- package/src/components/Input/input.stories.tsx +3 -3
- package/src/components/Input/input.tsx +13 -13
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.spec.md +6 -2
- package/src/components/LinkInput/link-input.stories.tsx +8 -8
- package/src/components/LinkInput/link-input.tsx +21 -19
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.tsx +8 -2
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
- package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.spec.md +6 -6
- package/src/components/NumberInput/number-input.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.tsx +17 -5
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
- package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
- package/src/components/PeoplePicker/people-picker.tsx +39 -20
- package/src/components/PeoplePicker/person-display.tsx +3 -3
- package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
- package/src/components/Popover/popover.principles.stories.tsx +49 -28
- package/src/components/Popover/popover.spec.md +4 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
- package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
- package/src/components/README.md +1 -0
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
- package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
- package/src/components/RadioGroup/radio-group.tsx +19 -14
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
- package/src/components/Rating/rating.principles.stories.tsx +3 -3
- package/src/components/Rating/rating.spec.md +2 -2
- package/src/components/Rating/rating.stories.tsx +4 -18
- package/src/components/Rating/rating.tsx +5 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +5 -2
- package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
- package/src/components/SegmentedControl/segmented-control.tsx +6 -3
- package/src/components/Select/select.anatomy.stories.tsx +13 -7
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +9 -1
- package/src/components/Select/select.stories.tsx +41 -27
- package/src/components/Select/select.tsx +44 -26
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
- package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
- package/src/components/SelectMenu/select-menu.tsx +38 -5
- package/src/components/SelectionControl/boolean-value.tsx +2 -2
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
- package/src/components/Separator/separator.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
- package/src/components/Sheet/sheet.tsx +4 -1
- package/src/components/Sidebar/sidebar.tsx +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
- package/src/components/Slider/slider.principles.stories.tsx +6 -6
- package/src/components/Slider/slider.spec.md +13 -1
- package/src/components/Slider/slider.stories.tsx +44 -32
- package/src/components/Slider/slider.tsx +13 -4
- package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +4 -2
- package/src/components/Steps/steps.stories.tsx +4 -56
- package/src/components/Steps/steps.tsx +31 -7
- package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +4 -4
- package/src/components/Switch/switch.stories.tsx +3 -3
- package/src/components/Switch/switch.tsx +16 -10
- package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
- package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
- package/src/components/Tabs/tabs.spec.md +5 -2
- package/src/components/Tabs/tabs.stories.tsx +36 -44
- package/src/components/Tabs/tabs.tsx +101 -36
- package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
- package/src/components/Tag/tag.principles.stories.tsx +4 -4
- package/src/components/Tag/tag.spec.md +3 -1
- package/src/components/Tag/tag.tsx +5 -3
- package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
- package/src/components/Textarea/textarea.spec.md +5 -5
- package/src/components/Textarea/textarea.tsx +24 -24
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
- package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
- package/src/components/TimePicker/time-picker.spec.md +6 -5
- package/src/components/TimePicker/time-picker.stories.tsx +3 -3
- package/src/components/TimePicker/time-picker.tsx +24 -14
- package/src/components/Toast/toast.principles.stories.tsx +1 -1
- package/src/components/Toast/toast.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
- package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.spec.md +9 -3
- package/src/components/Tooltip/tooltip.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.tsx +12 -2
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
- package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
- package/src/components/TreeView/tree-view.spec.md +8 -6
- package/src/components/TreeView/tree-view.stories.tsx +9 -43
- package/src/components/TreeView/tree-view.tsx +36 -0
- package/src/index.ts +13 -10
- package/src/lib/drag-visual.ts +2 -2
- package/src/lib/utils.ts +19 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
- package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
- package/src/tokens/categorical-color.ts +5 -5
- package/src/tokens/color/color.spec.md +4 -4
- package/src/tokens/color/primitives.css +9 -2
- package/src/tokens/opacity/opacity.spec.md +1 -1
- package/src/tokens/orphan-tokens.spec.md +1 -1
- package/src/tokens/typography/typography.spec.md +2 -0
- package/src/tokens/uiSize/uiSize.css +5 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
|
@@ -68,7 +68,7 @@ export const Overview: Story = {
|
|
|
68
68
|
<table className="text-caption border-collapse">
|
|
69
69
|
<thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
|
|
70
70
|
<tbody>
|
|
71
|
-
<tr><Td mono>children</Td><Td mono>
|
|
71
|
+
<tr><Td mono>children</Td><Td mono>ReactElement</Td><Td mono>—</Td><Td>anchor trigger element(Popover asChild Slot 單 element 契約,2026-07-05 型別收緊)</Td></tr>
|
|
72
72
|
<tr><Td mono>open / onOpenChange</Td><Td mono>boolean / (o) => void</Td><Td mono>—</Td><Td>controlled 控制(多步 tour 必用)</Td></tr>
|
|
73
73
|
<tr><Td mono>defaultOpen</Td><Td mono>boolean</Td><Td mono>—</Td><Td>uncontrolled 初始開啟狀態</Td></tr>
|
|
74
74
|
<tr><Td mono>kind</Td><Td mono>'tips' | 'new-features' | ReactNode</Td><Td mono>—</Td><Td>有值則渲染 Header(tour-level title);'tips'→「使用技巧」、'new-features'→「新功能介紹」、ReactNode→自訂;multi-step tour 建議傳</Td></tr>
|
|
@@ -126,9 +126,9 @@ export const Inspector: Story = {
|
|
|
126
126
|
</div>
|
|
127
127
|
<Coachmark
|
|
128
128
|
open
|
|
129
|
-
image={hasImage ? <MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Sparkles} label="
|
|
130
|
-
title="
|
|
131
|
-
description="
|
|
129
|
+
image={hasImage ? <MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Sparkles} label="AI 續寫" /> : undefined}
|
|
130
|
+
title="讓 AI 幫你續寫草稿"
|
|
131
|
+
description="選取一段文字,AI 會依前後文續寫並保留你的語氣;不滿意可以一鍵重新產生。"
|
|
132
132
|
step={hasStep ? { current: 2, total: 3 } : undefined}
|
|
133
133
|
onPrev={hasPrev ? () => {} : undefined}
|
|
134
134
|
onSkip={hasSkip ? () => {} : undefined}
|
|
@@ -137,7 +137,7 @@ export const Inspector: Story = {
|
|
|
137
137
|
side="right"
|
|
138
138
|
align="start"
|
|
139
139
|
>
|
|
140
|
-
<Button variant="primary" size="sm" startIcon={Sparkles}>
|
|
140
|
+
<Button variant="primary" size="sm" startIcon={Sparkles}>AI 續寫</Button>
|
|
141
141
|
</Coachmark>
|
|
142
142
|
</div>
|
|
143
143
|
</div>
|
|
@@ -158,7 +158,7 @@ export const UsageGuidance: Story = {
|
|
|
158
158
|
image={<MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Bot} label="AI 助理" />}
|
|
159
159
|
title="試試新的 AI 助理"
|
|
160
160
|
description="在任何文件中按下 AI 按鈕,讓 Claude 幫你摘要、翻譯或改寫內容。"
|
|
161
|
-
|
|
161
|
+
isLastStep
|
|
162
162
|
onNext={() => {}}
|
|
163
163
|
side="bottom"
|
|
164
164
|
align="start"
|
|
@@ -306,7 +306,7 @@ export const Overview = {
|
|
|
306
306
|
<thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
|
|
307
307
|
<tbody>
|
|
308
308
|
{[
|
|
309
|
-
['mode', "'edit'|'
|
|
309
|
+
['mode', "'edit'|'view'|'readonly'|'disabled'", "'edit'", 'FieldMode 四模式;顯式傳入時永遠最優先,不被 disabled 覆蓋'],
|
|
310
310
|
['size', "'sm'|'md'|'lg'", "'md'", '尺寸,與 Button 共用 field-height token'],
|
|
311
311
|
['options', 'ComboboxOption[]', '—', '選項列表(extends SelectMenuOption:value / label / icon / avatar / description / disabled / group)'],
|
|
312
312
|
['value', 'string[]', '[]', '已選中的值陣列'],
|
|
@@ -410,6 +410,7 @@ const InspectorInner = () => {
|
|
|
410
410
|
value={value}
|
|
411
411
|
onChange={setValue}
|
|
412
412
|
placeholder="選擇分類"
|
|
413
|
+
aria-label="產品分類"
|
|
413
414
|
className="w-72"
|
|
414
415
|
/>
|
|
415
416
|
</div>
|
|
@@ -551,6 +552,7 @@ export const ColorMatrix = {
|
|
|
551
552
|
size="sm"
|
|
552
553
|
disabled={st === 'disabled'}
|
|
553
554
|
onChange={() => {}}
|
|
555
|
+
aria-label={`產品分類(${st})`}
|
|
554
556
|
/>
|
|
555
557
|
<TokenAnnotation colors={st === 'disabled' ? TOKEN_MAP.disabled.default : TOKEN_MAP.edit[st]} />
|
|
556
558
|
</td>
|
|
@@ -567,6 +569,7 @@ export const ColorMatrix = {
|
|
|
567
569
|
error={st !== 'disabled'}
|
|
568
570
|
disabled={st === 'disabled'}
|
|
569
571
|
onChange={() => {}}
|
|
572
|
+
aria-label={`產品分類(錯誤態、${st})`}
|
|
570
573
|
/>
|
|
571
574
|
<TokenAnnotation colors={st === 'disabled' ? TOKEN_MAP.disabled.default : ERROR_COLORS[st]} />
|
|
572
575
|
</td>
|
|
@@ -588,10 +591,10 @@ export const ColorMatrix = {
|
|
|
588
591
|
<tr key={m}>
|
|
589
592
|
<Td mono>{m}</Td>
|
|
590
593
|
<td className="p-3 border-b border-divider align-top min-w-[180px]">
|
|
591
|
-
<Combobox mode={m} options={categoryOptions} value={['electronics', 'food']} size="sm" />
|
|
594
|
+
<Combobox mode={m} options={categoryOptions} value={['electronics', 'food']} size="sm" aria-label={`產品分類(${m})`} />
|
|
592
595
|
</td>
|
|
593
596
|
<td className="p-3 border-b border-divider align-top min-w-[160px]">
|
|
594
|
-
<Combobox mode={m} options={categoryOptions} value={[]} size="sm" />
|
|
597
|
+
<Combobox mode={m} options={categoryOptions} value={[]} size="sm" aria-label={`產品分類(${m}、空值)`} />
|
|
595
598
|
</td>
|
|
596
599
|
<td className="p-3 border-b border-divider align-top min-w-[160px]">
|
|
597
600
|
<TokenAnnotation colors={TOKEN_MAP[m].default} />
|
|
@@ -726,7 +729,7 @@ export const SizeMatrix = {
|
|
|
726
729
|
<div className="flex flex-col gap-3">
|
|
727
730
|
{SIZES.map((sz) => (
|
|
728
731
|
<div key={sz} className="flex items-center gap-3">
|
|
729
|
-
<Combobox size={sz} options={categoryOptions} value={['electronics', 'food']} onChange={() => {}} className="w-64" />
|
|
732
|
+
<Combobox size={sz} options={categoryOptions} value={['electronics', 'food']} onChange={() => {}} className="w-64" aria-label={`產品分類(size=${sz})`} />
|
|
730
733
|
<span className="text-caption text-fg-secondary font-mono">size="{sz}"</span>
|
|
731
734
|
</div>
|
|
732
735
|
))}
|
|
@@ -778,6 +781,7 @@ export const StateBehavior = {
|
|
|
778
781
|
options={categoryOptions}
|
|
779
782
|
value={overflowV}
|
|
780
783
|
onChange={setOverflowV}
|
|
784
|
+
aria-label="產品分類(單行溢出 +N 範例)"
|
|
781
785
|
/>
|
|
782
786
|
</div>
|
|
783
787
|
<div className="flex flex-col gap-1 text-[11px] text-fg-secondary">
|
|
@@ -814,6 +818,7 @@ export const StateBehavior = {
|
|
|
814
818
|
value={wrapV}
|
|
815
819
|
onChange={setWrapV}
|
|
816
820
|
wrap
|
|
821
|
+
aria-label="產品分類(換行模式範例)"
|
|
817
822
|
/>
|
|
818
823
|
</div>
|
|
819
824
|
</div>
|
|
@@ -846,6 +851,7 @@ export const StateBehavior = {
|
|
|
846
851
|
onChange={setClearV}
|
|
847
852
|
clearable
|
|
848
853
|
className="w-64"
|
|
854
|
+
aria-label="產品分類(清除全部範例)"
|
|
849
855
|
/>
|
|
850
856
|
<button
|
|
851
857
|
type="button"
|
|
@@ -872,6 +878,7 @@ export const StateBehavior = {
|
|
|
872
878
|
value={dismissV}
|
|
873
879
|
onChange={setDismissV}
|
|
874
880
|
className="w-72"
|
|
881
|
+
aria-label="產品分類(個別移除 Tag 範例)"
|
|
875
882
|
/>
|
|
876
883
|
<button
|
|
877
884
|
type="button"
|
|
@@ -60,10 +60,7 @@ export const UsageGuidance: Story = {
|
|
|
60
60
|
<LinkTo kind="Design System/Components/Combobox/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">四模式</span></LinkTo>
|
|
61
61
|
</li>
|
|
62
62
|
<li>
|
|
63
|
-
<LinkTo kind="Design System/Components/Combobox/展示" name="
|
|
64
|
-
</li>
|
|
65
|
-
<li>
|
|
66
|
-
<LinkTo kind="Design System/Components/Combobox/展示" name="單行 vs 換行"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">單行 vs 換行</span></LinkTo>
|
|
63
|
+
<LinkTo kind="Design System/Components/Combobox/展示" name="三種尺寸"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">尺寸與 Button 對齊</span></LinkTo>
|
|
67
64
|
</li>
|
|
68
65
|
<li>
|
|
69
66
|
<LinkTo kind="Design System/Components/Combobox/展示" name="搜尋"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">搜尋</span></LinkTo>
|
|
@@ -81,14 +78,14 @@ export const UsageGuidance: Story = {
|
|
|
81
78
|
title="Combobox 的 sweet spot — 多選 + 空間受限 + 選項數 6+"
|
|
82
79
|
note="Tag / 分類 / 協作成員 / 通知訂閱。使用者快速加選、移除,label 自帶語意不需描述"
|
|
83
80
|
>
|
|
84
|
-
<Combobox options={categoryOptions} value={tags} onChange={setTags} />
|
|
81
|
+
<Combobox options={categoryOptions} value={tags} onChange={setTags} aria-label="商品分類(多選 Tag 範例)" />
|
|
85
82
|
</Rule>
|
|
86
83
|
|
|
87
84
|
<Rule
|
|
88
85
|
title="❌ 單選:用 Select"
|
|
89
86
|
note="Combobox 永遠多選——單選塞進來使用者每次要手動先移除舊 Tag 再選新的,多餘的互動"
|
|
90
87
|
>
|
|
91
|
-
<Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} />
|
|
88
|
+
<Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} aria-label="商品分類(單選反例——應改用 Select)" />
|
|
92
89
|
<Label warn>↑ 只選一個 electronics → 應該用 Select,一次點擊完成切換</Label>
|
|
93
90
|
</Rule>
|
|
94
91
|
|
|
@@ -104,6 +101,7 @@ export const UsageGuidance: Story = {
|
|
|
104
101
|
]}
|
|
105
102
|
value={['terms']}
|
|
106
103
|
onChange={() => {}}
|
|
104
|
+
aria-label="同意項目"
|
|
107
105
|
/>
|
|
108
106
|
<Label warn>↑ 條款勾選是「完整閱讀後同意」→ 用 Checkbox stack 全露內容</Label>
|
|
109
107
|
</Rule>
|
|
@@ -121,6 +119,7 @@ export const UsageGuidance: Story = {
|
|
|
121
119
|
]}
|
|
122
120
|
value={['eng-fe']}
|
|
123
121
|
onChange={() => {}}
|
|
122
|
+
aria-label="部門"
|
|
124
123
|
/>
|
|
125
124
|
<Label warn>↑ 用縮排偽造階層 → 沒有展開收合、不能按父節點全選、破壞資料結構</Label>
|
|
126
125
|
</Rule>
|
|
@@ -141,7 +140,7 @@ export const WrapRule: Story = {
|
|
|
141
140
|
title="單行(預設)— Table cell、空間受限的 Form"
|
|
142
141
|
note="固定高度,與 Input / Select 等欄位並排對齊。多於可見寬度的 Tag 以 +N 指示器代替,hover 可看完整清單"
|
|
143
142
|
>
|
|
144
|
-
<Combobox options={categoryOptions} value={single} onChange={setSingle} />
|
|
143
|
+
<Combobox options={categoryOptions} value={single} onChange={setSingle} aria-label="商品分類(單行溢出範例)" />
|
|
145
144
|
<Label>↑ 單行:高度固定,超出的 Tag → +N</Label>
|
|
146
145
|
</Rule>
|
|
147
146
|
|
|
@@ -149,7 +148,7 @@ export const WrapRule: Story = {
|
|
|
149
148
|
title="多行 wrap — 空間充裕的 Form"
|
|
150
149
|
note="高度隨選中數量展開,每個 Tag 都完整可見。適合填答型表單——使用者一眼看到所有選項,不需 hover 溢出指示器"
|
|
151
150
|
>
|
|
152
|
-
<Combobox wrap options={categoryOptions} value={wrapped} onChange={setWrapped} />
|
|
151
|
+
<Combobox wrap options={categoryOptions} value={wrapped} onChange={setWrapped} aria-label="商品分類(多行 wrap 範例)" />
|
|
153
152
|
<Label>↑ 多行:完整展開,無溢出</Label>
|
|
154
153
|
</Rule>
|
|
155
154
|
|
|
@@ -189,7 +188,7 @@ export const TagOperationRule: Story = {
|
|
|
189
188
|
title="Tag 只能被「移除」,不能被「編輯」或「重排」"
|
|
190
189
|
note="每個 Tag 右側的 X 是唯一被允許的互動——保持 Tag 的心智模型單純:它代表一個已選中的選項,要換就刪了重選"
|
|
191
190
|
>
|
|
192
|
-
<Combobox options={categoryOptions} value={value} onChange={setValue} />
|
|
191
|
+
<Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="商品分類(Tag 移除範例)" />
|
|
193
192
|
<Label>↑ 點 Tag 的 X 移除;右側 clear all 一次清除;新增從 dropdown 選擇</Label>
|
|
194
193
|
</Rule>
|
|
195
194
|
|
|
@@ -205,7 +204,7 @@ export const TagOperationRule: Story = {
|
|
|
205
204
|
title="已選中的選項在下拉裡以打勾標示,再點一次即取消"
|
|
206
205
|
note="桌機(預設)走自建浮層選單:已選項保留在清單中並以打勾呈現,再點一次即移除——避免使用者跨越下拉與 field 才能對照已選狀態。手機 / 觸控裝置改走原生 select,已選項則不重複出現在原生下拉"
|
|
207
206
|
>
|
|
208
|
-
<Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} />
|
|
207
|
+
<Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} aria-label="商品分類(已選項打勾範例)" />
|
|
209
208
|
<Label>↑ 打開 dropdown,Electronics 仍在清單裡並打勾,可再點一次取消</Label>
|
|
210
209
|
</Rule>
|
|
211
210
|
</div>
|
|
@@ -223,7 +222,7 @@ export const OverflowRule: Story = {
|
|
|
223
222
|
title="+N 指示器是單行模式的必要元件"
|
|
224
223
|
note="使用者必須知道「還有多少沒看到」——沒有 +N 的單行會誤導使用者以為選項已完整顯示。Hover 可看完整清單"
|
|
225
224
|
>
|
|
226
|
-
<Combobox options={categoryOptions} value={value} onChange={setValue} />
|
|
225
|
+
<Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="商品分類(+N 溢出指示範例)" />
|
|
227
226
|
<Label>↑ 窄容器內多個 Tag,自動出現 +N</Label>
|
|
228
227
|
</Rule>
|
|
229
228
|
|
|
@@ -124,7 +124,7 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
|
|
|
124
124
|
|
|
125
125
|
## Loading
|
|
126
126
|
|
|
127
|
-
`loading?: boolean`(forward 給 SelectMenu SSOT,2026-05-15 audit B
|
|
127
|
+
`loading?: boolean`(forward 給 SelectMenu SSOT,2026-05-15 audit B 補;措辭對齊 `select.spec.md`「Loading」2026-07-04 Q3 拍板 — 不清空 stale options):spinner 只在**無可顯示選項時**佔 empty slot 顯 `<Empty icon={<CircularProgress size={48}/>}/>`(cmdk `CommandEmpty` 機制;已有 options 時保留顯示,不取代)。Trigger 不變,user 隨時可開。對齊 MUI Autocomplete「loading 只在無 suggestions 時顯 loadingText」共識(cite 詳 select.spec.md 同段)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
@@ -132,7 +132,7 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
|
|
|
132
132
|
|
|
133
133
|
- **Disabled**:Field SSOT own(`Field/field-controls.spec.md`)。trigger / tag dismiss / 搜尋 input 全部 disabled,token 走 M24 state precedence(`text-fg-disabled`);已選 Tag 的 dismiss X 自動隱藏(見「readonly / disabled 的 Tag」段)。
|
|
134
134
|
- **Loading**:已 codify(見「Loading」段)。
|
|
135
|
-
- **Empty(no search results)**:dropdown body 內渲
|
|
135
|
+
- **Empty(no search results)**:dropdown body 內渲 `emptyText`(Combobox 暴露 `emptyText` prop 並 forward 給 SelectMenu;未傳時走 SelectMenu 預設「沒有符合的選項」)。Combobox **暴露 `creatable` / `onCreate` / `createLabel` prop 並 forward 給 SelectMenu**(2026-07-18 user 拍板;搜尋非空且無完全同名既有選項時,dropdown 顯 create row `Plus + createLabel`)——邏輯/顯示/互動 SSOT 住在 SelectMenu(`select-menu.tsx` :271-275 顯隱 / render)。僅 searchable 桌機路徑生效(native mobile 不支援)。對齊 Ant tags / react-select Creatable。
|
|
136
136
|
- **Empty(no value selected)**:multi mode `value=[]` 時 trigger 顯 placeholder(如「請選擇」);empty state 不渲 tag 區。
|
|
137
137
|
- **Dark mode / density**:走 Field + SelectMenu SSOT 自動 adapt。
|
|
138
138
|
|
|
@@ -145,6 +145,10 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
|
|
|
145
145
|
- multi mode 可附 `min` / `max` selected count 限制(consumer 自驗,Combobox 不獨立 own validation rules)
|
|
146
146
|
- Validation timing:預設 onBlur + onSubmit,onChange 不立即 validate(避免邊選邊紅)
|
|
147
147
|
|
|
148
|
+
## Ref 契約(cross-mode 例外,2026-07-17 user 拍板)
|
|
149
|
+
|
|
150
|
+
Combobox 是 **4-mode field**(edit / view / readonly / disabled),各 mode 渲染**本質不同的 subtree**(edit = trigger + hidden select;view/readonly = `ReadonlyMultiSelect`)。**`ref` 只保證在 edit mode 指向 trigger root(`__triggerRef`)**;view / readonly / disabled mode **不保證穩定 root**(對齊 React「avoid over-exposing DOM nodes in higher-level components」)。需在任意 mode 取穩定 DOM root 的 consumer 應在外層自包一層容器,不依賴 Combobox `ref` 跨 mode 一致。與 T1 RadioGroup / Switch 的跨 mode 缺口採同一哲學(記錄例外,不硬造統一 host)。
|
|
151
|
+
|
|
148
152
|
---
|
|
149
153
|
|
|
150
154
|
## 禁止事項
|
|
@@ -26,7 +26,7 @@ const meta: Meta<typeof Combobox> = {
|
|
|
26
26
|
export default meta
|
|
27
27
|
type Story = StoryObj<typeof Combobox>
|
|
28
28
|
|
|
29
|
-
// @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add
|
|
29
|
+
// @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add view mode card to Modes story only.
|
|
30
30
|
/* ── 四模式 ── */
|
|
31
31
|
export const Modes: Story = {
|
|
32
32
|
name: '四模式',
|
|
@@ -39,8 +39,8 @@ export const Modes: Story = {
|
|
|
39
39
|
<Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="類別(edit mode demo)" />
|
|
40
40
|
</div>
|
|
41
41
|
<div>
|
|
42
|
-
<h3 className="text-body font-bold text-foreground mb-2">
|
|
43
|
-
<Combobox mode="
|
|
42
|
+
<h3 className="text-body font-bold text-foreground mb-2">view</h3>
|
|
43
|
+
<Combobox mode="view" options={categoryOptions} value={value} aria-label="類別(view 模式示範)" />
|
|
44
44
|
</div>
|
|
45
45
|
<div>
|
|
46
46
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
@@ -61,7 +61,7 @@ export const Modes: Story = {
|
|
|
61
61
|
|
|
62
62
|
/* ── 尺寸與 Button 對齊 ── */
|
|
63
63
|
export const SizeAlignment: Story = {
|
|
64
|
-
name: '
|
|
64
|
+
name: '三種尺寸',
|
|
65
65
|
render: () => {
|
|
66
66
|
const [sm, setSm] = React.useState(['electronics', 'food', 'lifestyle'])
|
|
67
67
|
const [md, setMd] = React.useState(['electronics', 'food', 'lifestyle'])
|
|
@@ -71,7 +71,7 @@ export const SizeAlignment: Story = {
|
|
|
71
71
|
<div className="flex flex-col gap-4">
|
|
72
72
|
{(['sm', 'md', 'lg'] as const).map(size => (
|
|
73
73
|
<div key={size} className="flex items-center gap-3">
|
|
74
|
-
<Combobox size={size} options={categoryOptions} value={states[size][0]} onChange={states[size][1]} className="max-w-xs" />
|
|
74
|
+
<Combobox size={size} options={categoryOptions} value={states[size][0]} onChange={states[size][1]} className="max-w-xs" aria-label={`商品分類(size=${size})`} />
|
|
75
75
|
<Button variant="primary" size={size}>送出</Button>
|
|
76
76
|
<span className="text-caption text-fg-muted">size="{size}"</span>
|
|
77
77
|
</div>
|
|
@@ -81,37 +81,10 @@ export const SizeAlignment: Story = {
|
|
|
81
81
|
},
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const init = ['electronics', 'food', 'lifestyle', 'clothing', 'furniture']
|
|
89
|
-
const [v1, setV1] = React.useState(init)
|
|
90
|
-
const [v2, setV2] = React.useState(init)
|
|
91
|
-
return (
|
|
92
|
-
<div className="flex flex-col gap-6 w-72">
|
|
93
|
-
<div>
|
|
94
|
-
<h3 className="text-body font-bold text-foreground mb-2">單行(預設)</h3>
|
|
95
|
-
<p className="text-caption text-fg-muted mb-3">塞不下的自動收進 +N,hover 顯示隱藏項</p>
|
|
96
|
-
<Combobox options={categoryOptions} value={v1} onChange={setV1} />
|
|
97
|
-
</div>
|
|
98
|
-
<div>
|
|
99
|
-
<h3 className="text-body font-bold text-foreground mb-2">單行 readonly</h3>
|
|
100
|
-
<Combobox mode="readonly" options={categoryOptions} value={init} />
|
|
101
|
-
</div>
|
|
102
|
-
<div>
|
|
103
|
-
<h3 className="text-body font-bold text-foreground mb-2">換行(wrap)</h3>
|
|
104
|
-
<p className="text-caption text-fg-muted mb-3">高度隨內容長,badges 自動換行</p>
|
|
105
|
-
<Combobox options={categoryOptions} value={v2} onChange={setV2} wrap />
|
|
106
|
-
</div>
|
|
107
|
-
<div>
|
|
108
|
-
<h3 className="text-body font-bold text-foreground mb-2">換行 readonly</h3>
|
|
109
|
-
<Combobox mode="readonly" options={categoryOptions} value={init} wrap />
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
)
|
|
113
|
-
},
|
|
114
|
-
}
|
|
84
|
+
// @story-trait-rationale: 原 WrapModes(單行 vs 換行)retired 2026-07-17(Dim 24 earn-existence)—
|
|
85
|
+
// 單行/wrap × edit/readonly 矩陣已由 anatomy「狀態行為」(單行溢出 + readonly 溢出 + edit/readonly wrap)
|
|
86
|
+
// 完整覆蓋機制,wrap 選擇原則由 principles「Wrap 模式選擇」(WrapRule)owns。展示層不重演矩陣(三層定位);
|
|
87
|
+
// principles 使用指引頁對應 LinkTo(單行 vs 換行)同步移除。
|
|
115
88
|
|
|
116
89
|
/* ── 搜尋 ── */
|
|
117
90
|
export const Searchable: Story = {
|
|
@@ -1,5 +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
|
-
// @renderer-symmetry-allow: ComboboxTagStack(
|
|
2
|
+
// @renderer-symmetry-allow: ComboboxTagStack(view path)接 consumer tagRenderer 是 Stream C 下 cycle 工作 — 2026-05-12 先 ship Issues 2/3/4 surgical fixes(placeholder vocabulary + cell surface metrics + placeholder truncate),tagRenderer view-path unify deferred per field-controls.spec.md 共享 contract a。當前 multi=1 顯示已透過 PeoplePicker tagRenderer(people-picker.tsx:426-444)PersonDisplay SSOT 對齊;其他 Combobox consumer 走 default `<Tag>` 純文字 backward-compat。
|
|
3
3
|
// code-quality-allow: file-size — Combobox 含 NativeCombobox/CustomCombobox/useOverflowCount/OverflowTagList/ComboboxTagStack 5 子元件 + 共用 helpers,split-into-files 會破壞 measurement closures + 重複 type definitions。
|
|
4
4
|
import * as React from 'react'
|
|
5
5
|
import { X, ChevronDown } from 'lucide-react'
|
|
@@ -237,7 +237,7 @@ interface OverflowTagListProps {
|
|
|
237
237
|
* 2026-05-14 I4 fix(per codex M31 verdict + user 抓「display overflow 有 avatar / edit 無」):
|
|
238
238
|
* Optional renderer for hidden items in `+N` overflow popover。Default fallback = `<Tag>{label}</Tag>`
|
|
239
239
|
* (純文字 chip,backward-compat)。Consumer pass 此 prop 讓 hidden items 顯示同 avatar 視覺
|
|
240
|
-
* (對齊
|
|
240
|
+
* (對齊 view path MultiPersonDisplay overflow popover Tag avatar SSOT)。
|
|
241
241
|
*/
|
|
242
242
|
renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode
|
|
243
243
|
onRemove?: (value: string) => void
|
|
@@ -297,7 +297,7 @@ function OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHid
|
|
|
297
297
|
{items.map((item, i) => (
|
|
298
298
|
// 2026-05-14 I5 fix(per codex M31 verdict + user 抓「avatar stack 堆疊方向不一致」):
|
|
299
299
|
// 加 z-index per-index — 前 item z 高(對齊 MultiPersonDisplay zIndex: visible.length - i
|
|
300
|
-
// canonical + MUI AvatarGroup surplus pattern)。
|
|
300
|
+
// canonical + MUI AvatarGroup surplus pattern)。view + edit stack 堆疊方向統一。
|
|
301
301
|
<div key={item.value} ref={el => { tagEls.current[i] = el }} className={cn('shrink-0 max-w-full', tagWrapperClassName)} style={{ zIndex: items.length - i }}>{renderTag(item, i)}</div>
|
|
302
302
|
))}
|
|
303
303
|
<div ref={overflowEl} className={cn('shrink-0', overflowWrapperClassName)}>
|
|
@@ -316,9 +316,9 @@ function OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHid
|
|
|
316
316
|
)
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
// ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='
|
|
319
|
+
// ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='view') ───
|
|
320
320
|
//
|
|
321
|
-
// Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode="
|
|
321
|
+
// Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode="view">`。
|
|
322
322
|
// 本 helper 只負責 tag-stack 內容渲染(OverflowTagList 消費),不包 Field wrapper。
|
|
323
323
|
function ComboboxTagStack({
|
|
324
324
|
value, options, tagSize = 'md', wrap = false, containerRef: externalRef, disabled = false,
|
|
@@ -328,7 +328,7 @@ function ComboboxTagStack({
|
|
|
328
328
|
}) {
|
|
329
329
|
const emptyDisplay = useFieldEmptyDisplay()
|
|
330
330
|
const ownRef = React.useRef<HTMLDivElement>(null)
|
|
331
|
-
if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : '
|
|
331
|
+
if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : 'view')}>{emptyDisplay}</span>
|
|
332
332
|
const items = value.map(v => ({ value: v, label: options?.find(o => o.value === v)?.label ?? v }))
|
|
333
333
|
const disabledClass = disabled ? 'bg-disabled text-fg-disabled' : undefined
|
|
334
334
|
|
|
@@ -345,10 +345,10 @@ function ComboboxTagStack({
|
|
|
345
345
|
)
|
|
346
346
|
|
|
347
347
|
if (externalRef) return content
|
|
348
|
-
// 2026-05-05 v9 fix(Bug 4):
|
|
348
|
+
// 2026-05-05 v9 fix(Bug 4):view path 內 wrapper 必須 `flex-1 min-w-0`,否則在 cell flex
|
|
349
349
|
// parent 下不認領完整可用寬度 → OverflowTagList 量得寬度小於 edit path → 顯 `+N` 多於 edit。
|
|
350
350
|
// edit path tagAreaRef wrapper 已是 `flex-1 min-w-0`(NativeCombobox/CustomCombobox line 258 / 354),
|
|
351
|
-
//
|
|
351
|
+
// view 必對稱才 SSOT。
|
|
352
352
|
// 2026-05-15 F1 Q3 fix(per user round 3 verbatim「單人選取時 Tag 越界蓋 indicator」):
|
|
353
353
|
// `overflow-visible` → `overflow-hidden` 讓 narrow cell width 強制 clip(Tag 內建 truncate
|
|
354
354
|
// 處理 text ellipsis,stack `-ml-0.5` 負 margin 在 wrapper 內不受影響)。對齊
|
|
@@ -384,8 +384,9 @@ export interface ComboboxProps {
|
|
|
384
384
|
/** 啟用搜尋 */
|
|
385
385
|
searchable?: boolean
|
|
386
386
|
/** Loading state(2026-05-15 audit B fix per user verbatim「dropdown 隨時可開,讀取在 panel 中間 CircularProgress」)。
|
|
387
|
-
* Forward 給 SelectMenu primitive SSOT;
|
|
388
|
-
* Trigger 不變(user 隨時可開)
|
|
387
|
+
* Forward 給 SelectMenu primitive SSOT;spinner 只在無可顯示選項時佔 CommandEmpty slot 顯 CircularProgress
|
|
388
|
+
* (已有 options 保留顯示,不取代)。Trigger 不變(user 隨時可開)。
|
|
389
|
+
* 對齊 MUI Autocomplete「loading 只在無 suggestions 時顯 loadingText」+ Field SSOT + Empty 元件 compose。*/
|
|
389
390
|
loading?: boolean
|
|
390
391
|
/** 搜尋框位置:menu(浮層內,預設)或 trigger(inline input) */
|
|
391
392
|
searchIn?: 'menu' | 'trigger'
|
|
@@ -397,6 +398,14 @@ export interface ComboboxProps {
|
|
|
397
398
|
emptyPlaceholder?: string
|
|
398
399
|
/** 搜尋無結果提示(2026-07-04 Q4 拍板接線)— forward SelectMenu primitive SSOT(default「沒有符合的選項」) */
|
|
399
400
|
emptyText?: string
|
|
401
|
+
/** 可建立新選項(creatable tag,2026-07-18 user 拍板 forward)—— 搜尋非空且無完全同名既有選項時,
|
|
402
|
+
* dropdown 顯 create row(Plus + `createLabel`);forward 給底層 SelectMenu(邏輯/顯示/互動 SSOT 住在 SelectMenu)。
|
|
403
|
+
* 僅 searchable 桌機路徑生效(需打字);native mobile 路徑不支援。對齊 Ant tags / react-select Creatable。 */
|
|
404
|
+
creatable?: boolean
|
|
405
|
+
/** 建立新選項 callback(forward SelectMenu `onCreate`)。 */
|
|
406
|
+
onCreate?: (value: string) => void
|
|
407
|
+
/** create row 文字格式(forward SelectMenu `createLabel`,預設「直接使用「{query}」」)。 */
|
|
408
|
+
createLabel?: (query: string) => string
|
|
400
409
|
/** a11y:無 Field wrapper 時提供 role='combobox' 的 accessible name(axe aria-input-field-name) */
|
|
401
410
|
'aria-label'?: string
|
|
402
411
|
/** Initial open state(uncontrolled)— 對齊 Select.defaultOpen / Radix Popover canonical。
|
|
@@ -416,8 +425,8 @@ export interface ComboboxProps {
|
|
|
416
425
|
tagRenderer?: (item: { value: string; label: string }, onRemove: () => void) => React.ReactNode
|
|
417
426
|
/**
|
|
418
427
|
* 2026-05-14 I4 fix:Optional renderer for hidden items in `+N` overflow popover
|
|
419
|
-
* (對齊
|
|
420
|
-
* pass 此 prop 讓 hidden items 顯 avatar + name(同
|
|
428
|
+
* (對齊 view path MultiPersonDisplay overflow popover 含 avatar SSOT)。PeoplePicker stack
|
|
429
|
+
* pass 此 prop 讓 hidden items 顯 avatar + name(同 view path)。Default fallback
|
|
421
430
|
* `<Tag>{label}</Tag>` 純文字 backward-compat。
|
|
422
431
|
*/
|
|
423
432
|
renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode
|
|
@@ -477,8 +486,8 @@ export interface ComboboxProps {
|
|
|
477
486
|
visibleCountOverride?: number
|
|
478
487
|
/**
|
|
479
488
|
* Display 是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)
|
|
480
|
-
* — DataTable cell
|
|
481
|
-
* 設 true 時
|
|
489
|
+
* — DataTable cell view↔edit 像素級對齊用。預設 false(裸 tag stack,backward compat)。
|
|
490
|
+
* 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,
|
|
482
491
|
* 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。
|
|
483
492
|
*/
|
|
484
493
|
showDisplayEndIcon?: boolean
|
|
@@ -487,7 +496,7 @@ export interface ComboboxProps {
|
|
|
487
496
|
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反)
|
|
488
497
|
const getIconSize = (size: string) => ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
489
498
|
|
|
490
|
-
// ── Shared readonly/disabled/
|
|
499
|
+
// ── Shared readonly/disabled/view render ─────────────────────────────────
|
|
491
500
|
|
|
492
501
|
function ReadonlyMultiSelect({
|
|
493
502
|
mode, variant: variantProp, width, size, options, value, wrap, className, showDisplayEndIcon = false,
|
|
@@ -504,13 +513,13 @@ function ReadonlyMultiSelect({
|
|
|
504
513
|
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
505
514
|
const hasTags = (value?.length ?? 0) > 0
|
|
506
515
|
|
|
507
|
-
// mode='
|
|
516
|
+
// mode='view'(Phase B2 2026-05-05):純內容輸出 — tag stack 不包 Field wrapper / 不 reserve 高度。
|
|
508
517
|
// 對齊原 ComboboxDisplay sub-component(retired)。
|
|
509
518
|
// Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,
|
|
510
|
-
// 與 edit 同結構消除 cell
|
|
511
|
-
if (resolvedMode === '
|
|
519
|
+
// 與 edit 同結構消除 cell view↔edit 像素偏移(Layer-B padding mismatch)。
|
|
520
|
+
if (resolvedMode === 'view') {
|
|
512
521
|
if (!showDisplayEndIcon) {
|
|
513
|
-
// 2026-05-14 I2 fix(spec contract (e)
|
|
522
|
+
// 2026-05-14 I2 fix(spec contract (e) view typography canonical):empty bare span 套
|
|
514
523
|
// `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field family 統一。
|
|
515
524
|
if (!hasTags) return <span className={cn(fieldDisplayTextClass(sz), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
|
|
516
525
|
return (
|
|
@@ -519,8 +528,8 @@ function ReadonlyMultiSelect({
|
|
|
519
528
|
}
|
|
520
529
|
return (
|
|
521
530
|
<div
|
|
522
|
-
className={cn(fieldWrapperStyles({ mode: '
|
|
523
|
-
data-field-mode="
|
|
531
|
+
className={cn(fieldWrapperStyles({ mode: 'view', variant, width, size: sz }), hasTags && tagPadding[sz], className)}
|
|
532
|
+
data-field-mode="view"
|
|
524
533
|
>
|
|
525
534
|
{hasTags ? (
|
|
526
535
|
<ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />
|
|
@@ -538,8 +547,8 @@ function ReadonlyMultiSelect({
|
|
|
538
547
|
<div ref={containerRef}
|
|
539
548
|
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), hasTags && tagPadding[sz],
|
|
540
549
|
// 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):
|
|
541
|
-
// readonly/disabled path 對齊 L293
|
|
542
|
-
// M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟
|
|
550
|
+
// readonly/disabled path 對齊 L293 view wrapper 已 ship 的 overflow-hidden fix。
|
|
551
|
+
// M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 view 不對稱。
|
|
543
552
|
// 2026-06-27 對齊 edit path(L598-617):wrap 時 items-start + chevron self-start/tagHeight 鎖第一行;
|
|
544
553
|
// paddingRight: var(--field-px) re-assert 右緣 12px(tagPadding 對稱 calc 會吃掉右緣,跟 edit 一致)。
|
|
545
554
|
wrap ? 'flex-wrap items-start py-1' : 'overflow-hidden', className)}
|
|
@@ -586,7 +595,7 @@ function NativeCombobox({
|
|
|
586
595
|
const fieldCtx = useFieldContext()
|
|
587
596
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
588
597
|
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
589
|
-
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="
|
|
598
|
+
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="view"> 漏 cascade
|
|
590
599
|
const resolvedMode = useResolvedFieldMode({ mode, disabled })
|
|
591
600
|
const iconSize = getIconSize(size)
|
|
592
601
|
const showClear = clearable && value.length > 0 && resolvedMode === 'edit'
|
|
@@ -633,7 +642,7 @@ function NativeCombobox({
|
|
|
633
642
|
onClick={(e) => { if (e.target === e.currentTarget) { selectRef.current?.showPicker?.(); selectRef.current?.focus() } }}>
|
|
634
643
|
{/* 2026-05-18 F2 sync(per user verbatim「modifying 修好 PeoplePicker stack 後改壞 Combobox tag display」
|
|
635
644
|
+ 「tag 應該要判斷所在空間最多可以呈現幾個tag(包括+n)去自動判斷何時要變成+n」):
|
|
636
|
-
edit path tagArea 對齊
|
|
645
|
+
edit path tagArea 對齊 view path L293 已 ship 的 `overflow-hidden` fix。原 `overflow-visible`
|
|
637
646
|
讓 tag 視覺越界蓋 chevron / +N indicator(useOverflowCount measurement 對但 CSS overflow 仍露)。
|
|
638
647
|
M10 violation root cause:2026-05-15 F1 Q3 只 fix display path,edit + Native(L518)沒同步。 */}
|
|
639
648
|
<div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative', nakedCellRowModeAlign, wrap ? 'flex-wrap' : 'overflow-hidden')} style={{ gap: GAP }}
|
|
@@ -670,6 +679,9 @@ function CustomCombobox({
|
|
|
670
679
|
searchAriaLabel = '搜尋選項', // i18n-allow: DS default
|
|
671
680
|
emptyPlaceholder = '選擇…', // i18n-allow: DS default
|
|
672
681
|
emptyText,
|
|
682
|
+
creatable = false,
|
|
683
|
+
onCreate,
|
|
684
|
+
createLabel,
|
|
673
685
|
defaultOpen = false,
|
|
674
686
|
onOpenChange,
|
|
675
687
|
__triggerRef,
|
|
@@ -688,7 +700,7 @@ function CustomCombobox({
|
|
|
688
700
|
const fieldCtx = useFieldContext()
|
|
689
701
|
const error = useResolvedFieldInvalid(errorProp)
|
|
690
702
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
691
|
-
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="
|
|
703
|
+
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="view"> 漏 cascade
|
|
692
704
|
const resolvedMode = useResolvedFieldMode({ mode, disabled })
|
|
693
705
|
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
694
706
|
const iconSize = getIconSize(size)
|
|
@@ -797,7 +809,7 @@ function CustomCombobox({
|
|
|
797
809
|
if (e.key === 'Escape') setOpen(false)
|
|
798
810
|
}}>
|
|
799
811
|
{/* 2026-05-18 #6A Round 1 Step 2/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:648):
|
|
800
|
-
CustomCombobox edit non-wrap tagArea 對齊 L293
|
|
812
|
+
CustomCombobox edit non-wrap tagArea 對齊 L293 view + L451 readonly + L518 native edit 已 ship 的 overflow-hidden fix。
|
|
801
813
|
原 overflow-visible 讓 tag 越界蓋 chevron / +N indicator(user 圖三)。M10 propagation 完整 4-path align。 */}
|
|
802
814
|
<div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative', nakedCellRowModeAlign, wrap ? 'flex-wrap' : 'overflow-hidden')} style={{ gap: tagAreaGap, paddingLeft: tagAreaPaddingLeftPx }}>
|
|
803
815
|
{value.length > 0 ? (
|
|
@@ -863,6 +875,9 @@ function CustomCombobox({
|
|
|
863
875
|
value={value}
|
|
864
876
|
onValueChange={onChange as (value: string | string[]) => void}
|
|
865
877
|
multiple
|
|
878
|
+
creatable={creatable}
|
|
879
|
+
onCreate={onCreate}
|
|
880
|
+
createLabel={createLabel}
|
|
866
881
|
searchable={searchable && searchIn === 'menu'}
|
|
867
882
|
searchPlaceholder={searchPlaceholder}
|
|
868
883
|
size={size}
|
|
@@ -20,7 +20,7 @@ Command 是**搜尋 + 鍵盤導覽的指令清單**——提供搜尋框、分
|
|
|
20
20
|
|
|
21
21
|
**實作基礎**:shadcn passthrough——基於 cmdk + Radix Dialog(Command Palette 模式)。本 DS 保留 shadcn 原結構,視覺樣式以 inline Tailwind class 直接掛在 cmdk primitive 上(`command.tsx`),token 值對齊(非結構繼承)MenuItem / Input / Empty 的 canonical token——改 MenuItem 不會自動連動 Command。
|
|
22
22
|
|
|
23
|
-
**分類**:Internal primitive——由 SelectMenu 消費(Select / Combobox / PeoplePicker 透過 SelectMenu 使用)。App
|
|
23
|
+
**分類**:Internal primitive——由 SelectMenu 消費(Select / Combobox / PeoplePicker 透過 SelectMenu 使用)。App **不從 root barrel front-door 直接 import** Command 家族;若要 Command Palette 類 UX,經 per-component subpath `@qijenchen/design-system/components/Command` 取用 `CommandDialog`(自行包裝確認後使用,對齊 `.claude/rules/ui-development.md`「Root barrel front-door 排除」— internal ≠ 禁用;cmdk + Radix Dialog 包裝,showcase「CommandPalette」story 消費)。
|
|
24
24
|
|
|
25
25
|
**Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
|
|
26
26
|
|
|
@@ -66,7 +66,7 @@ Command 通常由 `SelectMenu` 或自訂 Command Palette 元件消費——直
|
|
|
66
66
|
- **SelectMenu**:Select / Combobox / PeoplePicker 的 searchable 浮層(**由 Field 觸發**,帶有 input field + 選中值回填)
|
|
67
67
|
- **獨立 Command Palette**(Cmd+K):也用 Command 但**不在 Field 觸發**——透過全域快捷鍵開啟,用於跨頁面搜尋 / 快速動作入口
|
|
68
68
|
|
|
69
|
-
兩者底層都消費 Command。Field 場景用 SelectMenu(已處理 input binding);非 Field 場景(Cmd+K)用 `CommandDialog`(cmdk + Radix Dialog 包裝)。
|
|
69
|
+
兩者底層都消費 Command。Field 場景用 SelectMenu(已處理 input binding);非 Field 場景(Cmd+K)用 `CommandDialog`(經 subpath `@qijenchen/design-system/components/Command` 取用,cmdk + Radix Dialog 包裝)。
|
|
70
70
|
|
|
71
71
|
---
|
|
72
72
|
|
|
@@ -97,7 +97,7 @@ Consumer 無需額外處理 a11y,保留 cmdk 原結構 + 使用 `<CommandInput>`
|
|
|
97
97
|
- **Disabled item**:`<CommandItem disabled>` 透過 cmdk 內建支援,視覺繼承 MenuItem SSOT(`text-fg-disabled` + `aria-disabled=true` + 鍵盤導覽自動 skip + Enter 不觸發 onSelect)。skip 是「不進導覽清單」(cmdk `:not([aria-disabled="true"])` selector)— ↑/↓ 直接跳到下一個可選項,無中途 highlight。
|
|
98
98
|
- **Group heading 不可選中**:heading 是 `aria-hidden` 裝飾 div(group container `role="presentation"`),不參與導覽與選取;SR 經 items wrapper `role="group"` + `aria-labelledby` 取得群組語意。
|
|
99
99
|
- **Empty 後持續打字**:cmdk 每個 keystroke 重新過濾(`filtered.count` 驅動),`<CommandEmpty>` 持續顯示直到有 match;input 不鎖、不清空。
|
|
100
|
-
- **Loading**:Command 本身非 async surface。async option fetch 應由 consumer(SelectMenu / Cmd+K palette)在外層處理 —
|
|
100
|
+
- **Loading**:Command 本身非 async surface。async option fetch 應由 consumer(SelectMenu / Cmd+K palette)在外層處理 — 在 `<CommandEmpty>` slot 內渲 `<Empty icon={<CircularProgress size={48}/>}/>`(spinner 只在無可顯示選項時出現;已有 options 保留顯示,不取代 — 對齊 `select.spec.md`「Loading」2026-07-04 拍板措辭 + `empty.spec.md`「現有消費者」SelectMenu loading SSOT,禁止事項見其「禁止事項」loading 條)。Command primitive 不獨立 own loading prop。
|
|
101
101
|
- **Empty(no results)**:`<CommandEmpty>` 自動偵測 search filter result = 0 時渲;consumer 必傳 fallback 文案(預設 cmdk 不渲)。
|
|
102
102
|
- **Dark mode / density**:Command 的 inline Tailwind class 直接消費 semantic token(`bg-neutral-hover` / `text-fg-muted` / `text-fg-disabled` 等),token 在 dark mode 自動切值——非透過 MenuItem / Input / Empty primitive 連動。density 不獨立 own(由 consumer SelectMenu 控)。
|
|
103
103
|
|
|
@@ -48,7 +48,7 @@ const CommandInput = React.forwardRef<
|
|
|
48
48
|
React.ElementRef<typeof CommandPrimitive.Input>,
|
|
49
49
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
|
50
50
|
>(({ className, ...props }, ref) => (
|
|
51
|
-
<div className="flex items-center border-b border-divider px-3" cmdk-input-wrapper="">
|
|
51
|
+
<div className="flex shrink-0 items-center border-b border-divider px-3" cmdk-input-wrapper="">
|
|
52
52
|
<Search className="mr-2 h-4 w-4 shrink-0 text-fg-muted" />
|
|
53
53
|
<CommandPrimitive.Input
|
|
54
54
|
ref={ref}
|
|
@@ -80,7 +80,14 @@ const CommandList = React.forwardRef<
|
|
|
80
80
|
React.ElementRef<typeof CommandPrimitive.List>,
|
|
81
81
|
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
|
82
82
|
>(({ className, ...props }, ref) => (
|
|
83
|
-
|
|
83
|
+
/* @story-baseline: overlay-surface.spec.md#Viewport-aware-scroll-chain-invariant(M25 SSOT owner)
|
|
84
|
+
owner spec: overlay-surface.spec.md:34/53/347-362 —— 「浮層 body 永遠 flex-1 min-h-0 overflow-y-auto;
|
|
85
|
+
中間 wrapper 都必 flex flex-col h-full min-h-0;viewport 太小 body 內壓縮捲動」。
|
|
86
|
+
conflicting code(修前): 本 ScrollArea 固定 max-h-300 無 flex-1 → 在夾住的 SelectMenu PopoverContent
|
|
87
|
+
(max-h=available-height)內撐破外殼、底部選項被裁(320px viewport 實測 bottom 425 > 320 溢出)。
|
|
88
|
+
修: 加 flex-1 min-h-0(對齊 M25 canonical + HoverCard/Popover),max-h-300 降為上限。Command root 已
|
|
89
|
+
`flex h-full flex-col`(command.tsx:23)= chain 完整;非 flex 容器內 flex-1 為 no-op(spec:34 backward compat)。 */
|
|
90
|
+
<ScrollArea className="flex-1 min-h-0 max-h-[var(--menu-max-height,300px)]">
|
|
84
91
|
<CommandPrimitive.List ref={ref} className={cn("overflow-x-hidden", className)} {...props} />
|
|
85
92
|
</ScrollArea>
|
|
86
93
|
))
|