@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
|
@@ -7,6 +7,7 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|
|
7
7
|
import { cn } from "@/lib/utils"
|
|
8
8
|
import type { FieldMode, FieldVariant } from "@/design-system/components/Field/field-types"
|
|
9
9
|
import { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from "@/design-system/components/Field/field-context"
|
|
10
|
+
import { useControllable } from "@/design-system/hooks/use-controllable"
|
|
10
11
|
import { fieldWrapperStyles } from "@/design-system/components/Field/field-wrapper"
|
|
11
12
|
import { SelectionItem } from "@/design-system/components/SelectionControl/selection-item"
|
|
12
13
|
import { BooleanValueIcon } from "@/design-system/components/SelectionControl/boolean-value"
|
|
@@ -80,8 +81,13 @@ const checkStrokeWidth: Record<string, number> = { sm: 3, md: 3, lg: 2.5 }
|
|
|
80
81
|
|
|
81
82
|
// ── Types ───────────────────────────────────────────────────────────────────
|
|
82
83
|
|
|
84
|
+
// asChild / children 從公開型別 Omit(2026-07-17 d9i6):Checkbox 有**固定 anatomy** —
|
|
85
|
+
// 內部恆渲染 Indicator(Check / Minus 兩子節點),非 Slot host。若保留 Radix `asChild`,
|
|
86
|
+
// consumer 傳入的元素會被 Radix Slot `React.Children.only` 因多子節點在執行期拋錯(失敗記憶索引
|
|
87
|
+
// 已 codify 此 asChild 多子節點 bug class);`children` 同理會被固定 Indicator 覆蓋。需自訂佈局
|
|
88
|
+
// 請用 `label` / `description` / `icon` / `avatar` 一級 props(內部自動包 SelectionItem)。
|
|
83
89
|
export interface CheckboxProps
|
|
84
|
-
extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
|
|
90
|
+
extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, 'asChild' | 'children'>,
|
|
85
91
|
VariantProps<typeof checkboxVariants> {
|
|
86
92
|
/**
|
|
87
93
|
* Inline label。提供時 Checkbox 自動透過 SelectionItem 包裝,
|
|
@@ -111,7 +117,7 @@ export interface CheckboxProps
|
|
|
111
117
|
/**
|
|
112
118
|
* Field mode(2026-05-05 Phase B3 align):
|
|
113
119
|
* edit — 一般可互動 checkbox(預設)
|
|
114
|
-
*
|
|
120
|
+
* view — **純展示**:渲染 Check / X icon(true=勾 / false=叉,無互動 primitive、無 input chrome);
|
|
115
121
|
* 對齊 Carbon read-only / DataTable boolean cell 場景。取代既有 BooleanDisplay。
|
|
116
122
|
* readonly — 同 readOnly prop:checkbox 視覺保留 + 鎖互動 + a11y readonly signal
|
|
117
123
|
* disabled — 同 disabled prop:降色 + 鎖互動
|
|
@@ -143,6 +149,13 @@ const Checkbox = React.forwardRef<
|
|
|
143
149
|
mode,
|
|
144
150
|
// chrome 對 Checkbox 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。
|
|
145
151
|
variant: _chrome,
|
|
152
|
+
// controllable checked triplet(2026-07-17 d26i0):於 wrapper 層取出,交由 useControllable 持有
|
|
153
|
+
// resolved 值,供 edit / view / readonly 三分支共用。原本 view / readonly 分支各自讀 raw prop →
|
|
154
|
+
// uncontrolled(只傳 defaultChecked)在 edit 態 toggle 後切 mode 會丟失目前值(Radix 內部狀態
|
|
155
|
+
// wrapper 讀不到)。移出 props 後 edit 主路徑改由 checked={resolvedChecked} 受控(見下方 rootEl)。
|
|
156
|
+
checked: checkedProp,
|
|
157
|
+
defaultChecked: defaultCheckedProp,
|
|
158
|
+
onCheckedChange,
|
|
146
159
|
id: idProp,
|
|
147
160
|
...props
|
|
148
161
|
},
|
|
@@ -154,7 +167,7 @@ const Checkbox = React.forwardRef<
|
|
|
154
167
|
|
|
155
168
|
// Field context:Checkbox 單獨塞進 Field(binary toggle)時,忽略自己的 label 讓 FieldLabel 接管
|
|
156
169
|
// 2026-05-31 #35:hooks(useFieldContext / useContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。
|
|
157
|
-
// 原 mode='
|
|
170
|
+
// 原 mode='view' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。
|
|
158
171
|
//
|
|
159
172
|
// **例外**:Checkbox 是 CheckboxGroup 的 child 時(multi-select 情境),**每個 checkbox
|
|
160
173
|
// 的 label 是它自己的選項名**,FieldLabel 只是群組名稱 — 此時 label **必須保留**,
|
|
@@ -181,7 +194,7 @@ const Checkbox = React.forwardRef<
|
|
|
181
194
|
const generatedId = React.useId()
|
|
182
195
|
const inputId = idProp ?? (insideGroup ? generatedId : (fieldCtx?.id ?? generatedId))
|
|
183
196
|
|
|
184
|
-
// 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode="
|
|
197
|
+
// 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode="view"> 漏 cascade)
|
|
185
198
|
const resolvedDisabled = useResolvedFieldDisabled(disabled)
|
|
186
199
|
const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })
|
|
187
200
|
const effectiveReadOnly = readOnly || resolvedMode === 'readonly'
|
|
@@ -192,36 +205,74 @@ const Checkbox = React.forwardRef<
|
|
|
192
205
|
// readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)
|
|
193
206
|
const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'
|
|
194
207
|
|
|
195
|
-
// 2026-07-04 修:
|
|
208
|
+
// 2026-07-04 修:view / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props
|
|
196
209
|
// (id/data-*/aria-*)且不轉發 forwardRef ref → consumer 的 aria-label 等靜默失效。
|
|
197
|
-
// 抽出 Radix 專屬
|
|
198
|
-
// RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。
|
|
210
|
+
// 抽出 Radix 專屬 form props(required/name/value 不可落到裸 span/div),其餘 DOM props 於兩分支
|
|
211
|
+
// spread 轉發(與 Switch/RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。
|
|
212
|
+
// (checked/defaultChecked/onCheckedChange 已於上方 top-level destructure 取出交 useControllable;
|
|
213
|
+
// asChild/children 已從 CheckboxProps 型別 Omit — 固定 anatomy 非 Slot host,見型別註解。)
|
|
199
214
|
const {
|
|
200
|
-
checked: checkedProp,
|
|
201
|
-
defaultChecked: defaultCheckedProp,
|
|
202
|
-
onCheckedChange: _onCheckedChange,
|
|
203
215
|
required: _required,
|
|
204
216
|
name: _name,
|
|
205
217
|
value: _value,
|
|
206
|
-
asChild: _asChild,
|
|
207
|
-
children: _children,
|
|
208
218
|
...restDomProps
|
|
209
219
|
} = props
|
|
210
220
|
|
|
211
|
-
// ──
|
|
221
|
+
// ── Resolved checked SSOT(controlled / uncontrolled dual-mode,2026-07-17 d26i0)──────────
|
|
222
|
+
// 對齊 Input / Textarea 既有 canonical(field-controls.spec.md「有值判定」:useControllable 內部
|
|
223
|
+
// resolved value + form.reset bridge)。修 view / readonly 分支原各自讀 raw prop 導致「uncontrolled
|
|
224
|
+
// 切 mode 丟失目前值」的 dual-mode 缺口。controlled(傳 checked)時 useControllable 純 passthrough,
|
|
225
|
+
// edit 行為 Δ=0。
|
|
226
|
+
const isControlled = checkedProp !== undefined
|
|
227
|
+
const [resolvedChecked, setResolvedChecked] = useControllable<boolean | 'indeterminate'>({
|
|
228
|
+
value: checkedProp,
|
|
229
|
+
defaultValue: defaultCheckedProp ?? false,
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// form.reset() bridge(uncontrolled only):wrapper 取得 controllable 主導後,HTML 標準 reset 不發
|
|
233
|
+
// 變更事件 → 手動把 resolvedChecked 歸位 defaultChecked(對齊 input.tsx 同名 bridge)。keyed on
|
|
234
|
+
// resolvedMode:切回 edit 重掛 native Root 時 effect 重跑補掛 listener;view / readonly(Root
|
|
235
|
+
// unmount)時 innerRef 為 null → early return 不掛。
|
|
236
|
+
const innerRef = React.useRef<HTMLButtonElement | null>(null)
|
|
237
|
+
React.useEffect(() => {
|
|
238
|
+
if (isControlled) return
|
|
239
|
+
const form = innerRef.current?.form
|
|
240
|
+
if (!form) return
|
|
241
|
+
const handleReset = () => setResolvedChecked(defaultCheckedProp ?? false)
|
|
242
|
+
form.addEventListener('reset', handleReset)
|
|
243
|
+
return () => form.removeEventListener('reset', handleReset)
|
|
244
|
+
}, [isControlled, resolvedMode, defaultCheckedProp, setResolvedChecked])
|
|
245
|
+
// Merge refs(input.tsx setRef idiom):innerRef 供 reset bridge 取 form,同時轉發 forwardRef ref。
|
|
246
|
+
const setRef = React.useCallback((el: HTMLButtonElement | null) => {
|
|
247
|
+
innerRef.current = el
|
|
248
|
+
if (typeof ref === 'function') ref(el)
|
|
249
|
+
else if (ref) (ref as React.MutableRefObject<HTMLButtonElement | null>).current = el
|
|
250
|
+
}, [ref])
|
|
251
|
+
|
|
252
|
+
// ── mode='view'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────
|
|
212
253
|
// 純展示模式:無互動 primitive、渲染 Check / X icon(true=勾 / false=叉,中性 foreground 色)。
|
|
213
254
|
// boolean 值展示符號 SSOT = SelectionControl/boolean-value.tsx(勾/叉 icon + 中性色 + M22 世界級對照)。取代 BooleanDisplay。
|
|
214
|
-
if (resolvedMode === '
|
|
215
|
-
const isChecked =
|
|
255
|
+
if (resolvedMode === 'view') {
|
|
256
|
+
const isChecked = resolvedChecked === true
|
|
257
|
+
// a11y(2026-07-17 d10i2):BooleanValueIcon 帶 aria-hidden → 裸 span 在 a11y tree 無名,
|
|
258
|
+
// 布林值對螢幕閱讀器完全消失。給 view 容器 role="img" + aria-label 承載值語意(對齊 MUI X
|
|
259
|
+
// DataGrid boolean cell 的 icon role/label 世界級做法);consumer 若自帶 aria-label 則優先。
|
|
260
|
+
const viewAriaLabel = (restDomProps as { 'aria-label'?: string })['aria-label'] ?? (isChecked ? '是' : '否')
|
|
216
261
|
return (
|
|
217
|
-
<span
|
|
262
|
+
<span
|
|
263
|
+
{...restDomProps}
|
|
264
|
+
ref={ref as React.Ref<HTMLSpanElement>}
|
|
265
|
+
role="img"
|
|
266
|
+
aria-label={viewAriaLabel}
|
|
267
|
+
className="inline-flex"
|
|
268
|
+
>
|
|
218
269
|
<BooleanValueIcon checked={isChecked} size={resolvedBoxSize} />
|
|
219
270
|
</span>
|
|
220
271
|
)
|
|
221
272
|
}
|
|
222
273
|
|
|
223
274
|
// ── mode='readonly' in Field(2026-06-12 拍板「灰框 + 勾/叉」;2026-07-09 ✓/— glyph → Check/X icon)─
|
|
224
|
-
// Field 內 readonly boolean = readonly 灰框 chrome +
|
|
275
|
+
// Field 內 readonly boolean = readonly 灰框 chrome + view 同款值語言(勾/叉 icon)。
|
|
225
276
|
// 灰框消費 fieldWrapperStyles 同一 cva = 與 Input readonly 字面同源(SSOT,改一處全動)。
|
|
226
277
|
// 理由:同一張 readonly 表單裡文字控件有 bg-readonly 灰框鎖定訊號,boolean 保留全彩
|
|
227
278
|
// 控件會誤導「仍可操作」(世界級 0/4 用原樣鎖互動:Salesforce=✓ 靜態 glyph /
|
|
@@ -229,7 +280,7 @@ const Checkbox = React.forwardRef<
|
|
|
229
280
|
// Scope:僅 Field 內且無 inline label(FieldLabel 接管 label 的表單欄位場景);
|
|
230
281
|
// standalone readOnly(settings list / SelectionItem row)維持原樣鎖互動不變。
|
|
231
282
|
if (effectiveReadOnly && insideField && effectiveLabel == null) {
|
|
232
|
-
const isChecked =
|
|
283
|
+
const isChecked = resolvedChecked === true
|
|
233
284
|
const boxSize = resolvedBoxSize
|
|
234
285
|
return (
|
|
235
286
|
<div
|
|
@@ -256,8 +307,17 @@ const Checkbox = React.forwardRef<
|
|
|
256
307
|
const rootEl = (
|
|
257
308
|
<CheckboxPrimitive.Root
|
|
258
309
|
id={inputId}
|
|
259
|
-
ref={
|
|
310
|
+
ref={setRef}
|
|
260
311
|
disabled={effectiveDisabled}
|
|
312
|
+
// controllable checked SSOT(2026-07-17 d26i0):Root 受 wrapper resolvedChecked 主導,
|
|
313
|
+
// onCheckedChange 先同步 wrapper 內部 state 再 forward consumer → uncontrolled(只傳
|
|
314
|
+
// defaultChecked)toggle 後切 mode(view / readonly)仍保留目前值。controlled(傳 checked)
|
|
315
|
+
// 時 useControllable 純 passthrough,edit 行為 Δ=0。
|
|
316
|
+
checked={resolvedChecked}
|
|
317
|
+
onCheckedChange={(next) => {
|
|
318
|
+
setResolvedChecked(next)
|
|
319
|
+
onCheckedChange?.(next)
|
|
320
|
+
}}
|
|
261
321
|
aria-readonly={effectiveReadOnly || undefined}
|
|
262
322
|
data-readonly={effectiveReadOnly || undefined}
|
|
263
323
|
tabIndex={effectiveReadOnly ? -1 : undefined}
|
|
@@ -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 = {
|