@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
|
@@ -74,64 +74,57 @@ export const UsageGuidance: Story = {
|
|
|
74
74
|
export const RuleMinuteStepForMeetings: Story = {
|
|
75
75
|
name: '會議時段用 15 分鐘間隔',
|
|
76
76
|
render: () => (
|
|
77
|
-
<div className="flex gap-
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
</
|
|
77
|
+
<div className="flex flex-col gap-4">
|
|
78
|
+
<p className="text-caption text-fg-secondary max-w-prose">
|
|
79
|
+
會議排程以 15 分鐘為粒度是世界級慣例(Google Calendar / Outlook / Notion Calendar
|
|
80
|
+
的時間選單預設都是 15)。用預設 minuteStep=1 會讓使用者困在挑「9:07 還是 9:08」,
|
|
81
|
+
失去會議排程的本質——這類情境一律設 minuteStep=15。
|
|
82
|
+
</p>
|
|
83
|
+
<div className="flex gap-8">
|
|
84
|
+
<div className="flex flex-col gap-1.5">
|
|
85
|
+
<h3 className="text-caption font-medium text-foreground">✅ minuteStep=15</h3>
|
|
86
|
+
<Field>
|
|
87
|
+
<FieldLabel>專案週會時間</FieldLabel>
|
|
88
|
+
<TimePicker value="09:15" onChange={() => {}} minuteStep={15} />
|
|
89
|
+
</Field>
|
|
90
|
+
</div>
|
|
91
|
+
<div className="flex flex-col gap-1.5">
|
|
92
|
+
<h3 className="text-caption font-medium text-fg-muted">❌ 預設 minuteStep=1(會議排程無意義)</h3>
|
|
93
|
+
<Field>
|
|
94
|
+
<FieldLabel>專案週會時間</FieldLabel>
|
|
95
|
+
<TimePicker value="09:07" onChange={() => {}} />
|
|
96
|
+
</Field>
|
|
97
|
+
</div>
|
|
91
98
|
</div>
|
|
92
99
|
</div>
|
|
93
100
|
),
|
|
94
101
|
}
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*/
|
|
101
|
-
export const RuleRangeComposition: Story = {
|
|
102
|
-
name: '時間範圍用兩個 TimePicker 組合,不內建',
|
|
103
|
-
render: () => {
|
|
104
|
-
const [open, setOpen] = React.useState('10:00')
|
|
105
|
-
const [close, setClose] = React.useState('22:00')
|
|
106
|
-
return (
|
|
107
|
-
<Field>
|
|
108
|
-
<FieldLabel>營業時段(兩個 TimePicker + →)</FieldLabel>
|
|
109
|
-
<div className="flex items-center gap-2">
|
|
110
|
-
<TimePicker value={open} onChange={setOpen} />
|
|
111
|
-
<span className="text-fg-muted">→</span>
|
|
112
|
-
<TimePicker value={close} onChange={setClose} />
|
|
113
|
-
</div>
|
|
114
|
-
</Field>
|
|
115
|
-
)
|
|
116
|
-
},
|
|
117
|
-
}
|
|
103
|
+
// Dim 24 retire(2026-07-16):原 RuleRangeComposition(營業時段雙 TimePicker + →)與「展示」層
|
|
104
|
+
// 的「店家營業時間」(ShopBusinessHours)near-identical(同值 10:00/22:00、同結構),且其規則
|
|
105
|
+
// (TimePicker 不內建 Range,用兩個並列組合)已由本頁 UsageGuidance「何時不用」條目文字說明。
|
|
106
|
+
// 重複範例退役;範圍組合的 live demo 見「展示 → 店家營業時間」(UsageGuidance 已 LinkTo 指向)。
|
|
118
107
|
|
|
119
108
|
/**
|
|
120
109
|
* 規則:清除用 X 行內動作,不要用文字按鈕
|
|
121
|
-
* 設定 clearable 後,TimePicker 會自動在欄位尾端渲染一個 X 行內動作來清空值,
|
|
122
|
-
* 點擊即清空。不要自己擺一顆「清除」文字按鈕——統一用 X 圖示符合全站慣例。
|
|
123
110
|
*/
|
|
124
111
|
export const RuleClearNoLabelButton: Story = {
|
|
125
112
|
name: '清除用 X 行內動作,不用文字按鈕',
|
|
126
113
|
render: () => {
|
|
127
114
|
const [t, setT] = React.useState<string>('14:30')
|
|
128
115
|
return (
|
|
129
|
-
<div className="flex flex-col gap-
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
116
|
+
<div className="flex flex-col gap-4">
|
|
117
|
+
<p className="text-caption text-fg-secondary max-w-prose">
|
|
118
|
+
設定 clearable 後,TimePicker 會自動在欄位尾端渲染一個 X 行內動作來清空值,點擊即清空。
|
|
119
|
+
不要自己擺一顆「清除」文字按鈕——全站統一用 X 圖示表達「移除已填內容」,與其他欄位的清除慣例一致。
|
|
120
|
+
</p>
|
|
121
|
+
<div className="flex flex-col gap-1.5">
|
|
122
|
+
<h3 className="text-caption font-medium text-foreground">✅ clearable=true(自動渲染 X 行內動作)</h3>
|
|
123
|
+
<Field>
|
|
124
|
+
<FieldLabel>提醒時間</FieldLabel>
|
|
125
|
+
<TimePicker value={t} onChange={setT} clearable />
|
|
126
|
+
</Field>
|
|
127
|
+
</div>
|
|
135
128
|
</div>
|
|
136
129
|
)
|
|
137
130
|
},
|
|
@@ -80,7 +80,7 @@ open 軸同樣只開最小 API — **uncontrolled-only**:`defaultOpen`(初始開
|
|
|
80
80
|
value={time} // ISO "HH:mm" or "HH:mm:ss" | null
|
|
81
81
|
onChange={setTime}
|
|
82
82
|
size="sm" | "md" | "lg" // 對齊 field-height family,default md
|
|
83
|
-
mode="edit" | "
|
|
83
|
+
mode="edit" | "view" | "readonly" | "disabled" // view = 純展示值(DataTable cell 用)
|
|
84
84
|
disabled={boolean}
|
|
85
85
|
error={boolean}
|
|
86
86
|
clearable={boolean}
|
|
@@ -105,7 +105,7 @@ open 軸同樣只開最小 API — **uncontrolled-only**:`defaultOpen`(初始開
|
|
|
105
105
|
|
|
106
106
|
### 顯示格式化
|
|
107
107
|
|
|
108
|
-
**
|
|
108
|
+
**View 走 `Intl.DateTimeFormat`**(跨 locale 統一、12h/24h 支援)。`formatOptions` 透傳進去。
|
|
109
109
|
|
|
110
110
|
---
|
|
111
111
|
|
|
@@ -199,7 +199,7 @@ Panel 展開後的 column picker 結構:
|
|
|
199
199
|
詳見 `../Field/field-controls.spec.md`(共用規則)。
|
|
200
200
|
|
|
201
201
|
### Empty 值
|
|
202
|
-
`value={null}` / `value=""` / `value=undefined` 都視為空,trigger 顯示 `placeholder`。
|
|
202
|
+
`value={null}` / `value=""` / `value=undefined` 都視為空,trigger 顯示 `placeholder`。View 模式空值顯示半形 `-`(對齊 `EMPTY_DISPLAY`,text-foreground)。
|
|
203
203
|
|
|
204
204
|
### 驗證時機
|
|
205
205
|
- **每次欄位選取(時 / 分 / 秒任一改變)當下即 commit value 給 `onChange`**(eager commit,非 OK 才送)。OK 鈕(「確定」)只負責關閉 Panel,不另行 commit。`此刻` 按鈕則一次 commit 當前時間並關閉 Panel
|
|
@@ -214,6 +214,7 @@ N/A — TimePicker 是純同步輸入,無 async 狀態。
|
|
|
214
214
|
## A11y 預設
|
|
215
215
|
|
|
216
216
|
- trigger `role="combobox"`,在 `<Field>` 內時以 `aria-labelledby` 指向 field label(`fieldCtx.labelId`)
|
|
217
|
+
- **Standalone(無 `<Field>` 包裹)accessible name**:trigger 無預設 `aria-label`,`<Field>` 外使用時 consumer **必須**自帶 `aria-label` 或 `aria-labelledby`,否則 `role="combobox"` 成為無名稱控件(對齊 Select / Combobox / DatePicker 同家族 standalone 約定)。DS 不為 trigger 塞泛用 fallback name(如「時間」),避免遮蔽 consumer 的具體語意(如「會議開始時間」);Field 內則自動接線無需 consumer 介入。Panel 本體(Popover dialog)另有本 DS 提供的 `aria-label="選擇時間"`,與 trigger name 職責分離
|
|
217
218
|
- Panel 開啟時 trigger `aria-expanded="true"` + `aria-haspopup="dialog"`
|
|
218
219
|
- 每欄 `role="listbox"`(`aria-label` 為 `hours` / `minutes` / `seconds`),item `role="option" aria-selected`
|
|
219
220
|
- Screen reader 經 trigger 的 label + 內層可見值文字朗讀目前選取時間(目前值以可見 `<span>` 呈現,無額外 `aria-valuetext`)
|
|
@@ -272,9 +273,9 @@ trigger 的互動狀態(focus / invalid / disabled / readonly)完全繼承 `../F
|
|
|
272
273
|
|
|
273
274
|
## 邊界案例
|
|
274
275
|
|
|
275
|
-
- **Disabled**:Field SSOT own;trigger 自動 disabled(`text-fg-disabled` + 不開 picker)
|
|
276
|
+
- **Disabled**:Field SSOT own;trigger 自動 disabled(`text-fg-disabled` + 不開 picker)。顯式 `mode` 優先於 `disabled` prop(`useResolvedFieldMode` prop > disabled),view 分支無 disabled token 邏輯——要 disabled 視覺走 `mode="disabled"`(readonly/disabled 分支 `text-fg-disabled`,時間格式維持)。
|
|
276
277
|
- **Loading**:TimePicker 為 sync UI(time math 在 client),無 loading state。極端 case(後端 disabled-times list)應由 consumer 先 disable trigger 直到 fetch 完成。
|
|
277
|
-
- **Empty(no value)**:`value=null` 為合法 initial state,trigger 顯 placeholder;**未傳 `placeholder` 時 default = 格式遮罩**(`HH:MM`,showSeconds=true 時 `HH:MM:SS`),非固定文案。`null` +
|
|
278
|
+
- **Empty(no value)**:`value=null` 為合法 initial state,trigger 顯 placeholder;**未傳 `placeholder` 時 default = 格式遮罩**(`HH:MM`,showSeconds=true 時 `HH:MM:SS`),非固定文案。`null` + view mode 顯半形 `-`(hyphen + `text-foreground`;`mode="disabled"` → fg-disabled)對齊 Input view empty 慣例。
|
|
278
279
|
- **Empty(disabled all times)**:極端場景(`disabledHours` / `disabledMinutes` 覆蓋全範圍),panel column 全 disabled,鍵盤焦點停留無導覽目標。
|
|
279
280
|
- **Panel 開啟中外部 value 變更**:controlled 單向資料流——欄位選中即時反映新 value,並 scroll-into-view(`behavior:'smooth'`,mount 後的變更;見「Spacing + 結構」的 Scroll-into-view 條)。
|
|
280
281
|
- **Dark mode / density**:走 Field + Popover SSOT 自動 adapt;panel column item 由 MenuItem SSOT 控 density。
|
|
@@ -27,7 +27,7 @@ export default meta
|
|
|
27
27
|
|
|
28
28
|
type Story = StoryObj<typeof TimePicker>
|
|
29
29
|
|
|
30
|
-
// @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with
|
|
30
|
+
// @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with view card.
|
|
31
31
|
/* ── 四模式 ── */
|
|
32
32
|
export const Modes: Story = {
|
|
33
33
|
name: '四模式',
|
|
@@ -38,8 +38,8 @@ export const Modes: Story = {
|
|
|
38
38
|
<TimePicker value="14:30" onChange={() => {}} aria-label="會議時段(edit mode demo)" />
|
|
39
39
|
</div>
|
|
40
40
|
<div>
|
|
41
|
-
<h3 className="text-body font-bold text-foreground mb-2">
|
|
42
|
-
<TimePicker mode="
|
|
41
|
+
<h3 className="text-body font-bold text-foreground mb-2">view</h3>
|
|
42
|
+
<TimePicker mode="view" value="14:30" aria-label="會議時段(view 模式示範)" />
|
|
43
43
|
</div>
|
|
44
44
|
<div>
|
|
45
45
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
@@ -63,7 +63,7 @@ export interface TimeFormatOptions {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// 2026-07-06 D3 perf:Intl.DateTimeFormat 是標準庫最貴 constructor 之一(locale data
|
|
66
|
-
// resolution)。formatTime 無 cheap path,
|
|
66
|
+
// resolution)。formatTime 無 cheap path,view/readonly/edit 每 render 必建;DataTable time 欄
|
|
67
67
|
// 轉發 config 時每 cell × 每次表格 re-render 重建。module-level cache 重用實例(DateTimeFormat
|
|
68
68
|
// 無狀態可安全重用),key = locale|JSON.stringify(options)。行為 Δ=0。
|
|
69
69
|
const dtfCache = new Map<string, Intl.DateTimeFormat>()
|
|
@@ -109,7 +109,10 @@ export interface TimePickerProps
|
|
|
109
109
|
extends TimeFormatOptions,
|
|
110
110
|
Omit<
|
|
111
111
|
React.HTMLAttributes<HTMLDivElement>,
|
|
112
|
-
'
|
|
112
|
+
// 'defaultValue' 明確排除:本元件 controlled-only(time-picker.spec.md「Controlled-only
|
|
113
|
+
// rationale」),不支援 uncontrolled 初始值 — 若不 Omit,HTMLAttributes 會讓 defaultValue
|
|
114
|
+
// 通過型別卻靜默無效(不初始化 draft),與 spec contract 矛盾。
|
|
115
|
+
'onChange' | 'placeholder' | 'defaultValue'
|
|
113
116
|
> {
|
|
114
117
|
mode?: FieldMode
|
|
115
118
|
/** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */
|
|
@@ -141,9 +144,9 @@ export interface TimePickerProps
|
|
|
141
144
|
*/
|
|
142
145
|
endIcon?: LucideIcon | null
|
|
143
146
|
/**
|
|
144
|
-
*
|
|
145
|
-
* — DataTable cell
|
|
146
|
-
* 設 true 時
|
|
147
|
+
* View 態是否渲 endIcon + Field naked wrapper(D-path opt-in,2026-05-08)
|
|
148
|
+
* — DataTable cell view↔edit 像素級對齊用。預設 false(裸 span,backward compat)。
|
|
149
|
+
* 設 true 時 view 也走 fieldWrapperStyles(naked variant)+ ItemSuffix Clock,
|
|
147
150
|
* 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。
|
|
148
151
|
*/
|
|
149
152
|
showDisplayEndIcon?: boolean
|
|
@@ -188,7 +191,7 @@ const TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(
|
|
|
188
191
|
const size = useResolvedFieldSize(sizeProp) // B 組 cascade fix
|
|
189
192
|
const error = useResolvedFieldInvalid(errorProp)
|
|
190
193
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
191
|
-
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="
|
|
194
|
+
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="view"> 漏 cascade
|
|
192
195
|
const resolvedMode = useResolvedFieldMode({ mode, disabled })
|
|
193
196
|
const emptyDisplay = useFieldEmptyDisplay()
|
|
194
197
|
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
@@ -252,21 +255,25 @@ const TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(
|
|
|
252
255
|
setOpen(false)
|
|
253
256
|
}
|
|
254
257
|
|
|
255
|
-
// mode='
|
|
258
|
+
// mode='view'(Phase B2 2026-05-05):純內容輸出 — 對齊原 TimePickerDisplay sub-component(retired)。
|
|
256
259
|
// Default(showDisplayEndIcon=false):無 Field wrapper / 無 Clock icon — backward compat 裸 span。
|
|
257
260
|
// Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix Clock,
|
|
258
|
-
// 與 edit 同結構消除 cell
|
|
259
|
-
if (resolvedMode === '
|
|
261
|
+
// 與 edit 同結構消除 cell view↔edit 像素偏移(Layer-B padding mismatch)。
|
|
262
|
+
if (resolvedMode === 'view') {
|
|
263
|
+
// 2026-07-16 DA3 fix:view 分支補 {...props} spread(aria-label 等 DOM attr 原本靜默丟失;
|
|
264
|
+
// Switch 同型 2026-07-04 已修,本檔漏 — M10 同型)。
|
|
260
265
|
if (!showDisplayEndIcon) {
|
|
261
|
-
// 2026-05-14 I2 fix(spec contract (e)
|
|
266
|
+
// 2026-05-14 I2 fix(spec contract (e) view typography canonical):bare span 套
|
|
262
267
|
// `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)— 對齊 Field family 統一。
|
|
263
|
-
if (!value) return <span className={cn(fieldDisplayTextClass(size), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
|
|
264
|
-
return <span className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{formatTime(value, { formatOptions, locale })}</span>
|
|
268
|
+
if (!value) return <span {...props} ref={ref as React.Ref<HTMLSpanElement>} className={cn(fieldDisplayTextClass(size), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
|
|
269
|
+
return <span {...props} ref={ref as React.Ref<HTMLSpanElement>} className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{formatTime(value, { formatOptions, locale })}</span>
|
|
265
270
|
}
|
|
266
271
|
return (
|
|
267
272
|
<div
|
|
268
|
-
|
|
269
|
-
|
|
273
|
+
ref={ref}
|
|
274
|
+
{...props}
|
|
275
|
+
className={cn(fieldWrapperStyles({ mode: 'view', variant, size }), className)}
|
|
276
|
+
data-field-mode="view"
|
|
270
277
|
>
|
|
271
278
|
<span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && fieldEmptyColorClass(resolvedMode))}>
|
|
272
279
|
{value ? formatTime(value, { formatOptions, locale }) : emptyDisplay}
|
|
@@ -284,6 +291,9 @@ const TimePicker = React.forwardRef<HTMLDivElement, TimePickerProps>(
|
|
|
284
291
|
if (!isEditable) {
|
|
285
292
|
return (
|
|
286
293
|
<div
|
|
294
|
+
// 2026-07-16 DA3 fix:非-edit 分支補 ref 轉發(forwardRef<HTMLDivElement> 原本只有 edit
|
|
295
|
+
// 與 bare-span view 接 ref,readonly/disabled 及 endIcon-view div 靜默丟失 — 同 view props 漏接)。
|
|
296
|
+
ref={ref}
|
|
287
297
|
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}
|
|
288
298
|
data-field-mode={resolvedMode}
|
|
289
299
|
aria-disabled={resolvedMode === 'disabled' ? true : undefined}
|
|
@@ -45,7 +45,7 @@ export const UsageGuidance: Story = {
|
|
|
45
45
|
<LinkTo kind="Design System/Components/Toast/展示" name="有標題與描述"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">有 Title + Description</span></LinkTo>
|
|
46
46
|
</li>
|
|
47
47
|
<li>
|
|
48
|
-
<LinkTo kind="Design System/Components/Toast/展示" name="
|
|
48
|
+
<LinkTo kind="Design System/Components/Toast/展示" name="點擊觸發通知"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">點擊觸發通知</span></LinkTo>
|
|
49
49
|
</li>
|
|
50
50
|
</ul>
|
|
51
51
|
<p className="text-fg-muted mt-3">判斷不確定時:先看下方「何時用 / 何時不用」的對照;若訊息重要到使用者必須看到、或需要使用者確認,就不該用 Toast,改用 Alert(持久顯示)或 Dialog(阻斷確認)。</p>
|
|
@@ -245,9 +245,9 @@ const InspectorInner = () => {
|
|
|
245
245
|
<div className="px-16 py-16 rounded-lg bg-canvas border border-divider flex items-center justify-center">
|
|
246
246
|
<Tooltip defaultOpen>
|
|
247
247
|
<TooltipTrigger asChild>
|
|
248
|
-
<Button variant="secondary" startIcon={Settings} size="sm"
|
|
248
|
+
<Button variant="secondary" startIcon={Settings} size="sm">欄位設定</Button>
|
|
249
249
|
</TooltipTrigger>
|
|
250
|
-
<TooltipContent side={side}
|
|
250
|
+
<TooltipContent side={side}>調整資料表的欄位顯示與排序</TooltipContent>
|
|
251
251
|
</Tooltip>
|
|
252
252
|
</div>
|
|
253
253
|
|
|
@@ -351,7 +351,15 @@ export const Inspector = {
|
|
|
351
351
|
|
|
352
352
|
export const PlacementReference = {
|
|
353
353
|
name: '方向與間距',
|
|
354
|
-
render: () =>
|
|
354
|
+
render: () => {
|
|
355
|
+
// 四方向以工具列常見操作示範,方位由外部 mono 標籤標示,Tooltip 提供對應說明。
|
|
356
|
+
const placementDemo: Record<SideKey, { label: string; tip: string }> = {
|
|
357
|
+
top: { label: '複製連結', tip: '複製此頁面的公開分享連結' },
|
|
358
|
+
right: { label: '封存專案', tip: '封存後移至封存區,隨時可還原' },
|
|
359
|
+
bottom: { label: '重新整理', tip: '重新載入最新資料' },
|
|
360
|
+
left: { label: '更多操作', tip: '檢視全部可用的操作' },
|
|
361
|
+
}
|
|
362
|
+
return (
|
|
355
363
|
<div className="flex flex-col gap-8">
|
|
356
364
|
<div className="flex flex-col gap-1">
|
|
357
365
|
<H3>四方向 Placement</H3>
|
|
@@ -365,9 +373,9 @@ export const PlacementReference = {
|
|
|
365
373
|
<div className="px-8 py-8 rounded-lg bg-canvas border border-divider flex items-center justify-center w-full">
|
|
366
374
|
<Tooltip defaultOpen>
|
|
367
375
|
<TooltipTrigger asChild>
|
|
368
|
-
<Button variant="tertiary" size="sm">{s}</Button>
|
|
376
|
+
<Button variant="tertiary" size="sm">{placementDemo[s].label}</Button>
|
|
369
377
|
</TooltipTrigger>
|
|
370
|
-
<TooltipContent side={s}
|
|
378
|
+
<TooltipContent side={s}>{placementDemo[s].tip}</TooltipContent>
|
|
371
379
|
</Tooltip>
|
|
372
380
|
</div>
|
|
373
381
|
</div>
|
|
@@ -397,7 +405,8 @@ export const PlacementReference = {
|
|
|
397
405
|
<Desc>transform-origin 使用 --radix-tooltip-content-transform-origin,zoom 效果從觸發器方向展開。</Desc>
|
|
398
406
|
</div>
|
|
399
407
|
</div>
|
|
400
|
-
|
|
408
|
+
)
|
|
409
|
+
},
|
|
401
410
|
}
|
|
402
411
|
|
|
403
412
|
// ── Accessibility ─────────────────────────────────────────────────────────
|
|
@@ -52,7 +52,7 @@ export const UsageGuidance: Story = {
|
|
|
52
52
|
<LinkTo kind="Design System/Components/Tooltip/展示" name="非 Button 元素"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">非 Button 元素</span></LinkTo>
|
|
53
53
|
</li>
|
|
54
54
|
<li>
|
|
55
|
-
<LinkTo kind="Design System/Components/Tooltip/展示" name="
|
|
55
|
+
<LinkTo kind="Design System/Components/Tooltip/展示" name="基本用法"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">基本用法</span></LinkTo>
|
|
56
56
|
</li>
|
|
57
57
|
<li>
|
|
58
58
|
<LinkTo kind="Design System/Components/Tooltip/展示" name="長文字"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">長文字</span></LinkTo>
|
|
@@ -189,13 +189,13 @@ export const NeedsTooltipRule: Story = {
|
|
|
189
189
|
title="✅ 截斷文字用 tooltip 顯示完整內容(僅當實際被截斷時)"
|
|
190
190
|
note="Tooltip 是資訊補救 — 文字被 truncate 時才顯示完整內容。沒被截斷就不該顯示 tooltip(避免過度互動)"
|
|
191
191
|
>
|
|
192
|
-
<Tooltip>
|
|
192
|
+
<Tooltip defaultOpen>
|
|
193
193
|
<TooltipTrigger asChild>
|
|
194
194
|
<div className="w-32 truncate px-3 py-1 border border-border rounded-md cursor-default">
|
|
195
|
-
|
|
195
|
+
2026 亞洲市場品牌改版與官網重構
|
|
196
196
|
</div>
|
|
197
197
|
</TooltipTrigger>
|
|
198
|
-
<TooltipContent
|
|
198
|
+
<TooltipContent>2026 亞洲市場品牌改版與官網重構</TooltipContent>
|
|
199
199
|
</Tooltip>
|
|
200
200
|
<Label>↑ 模式示意(此靜態範例恆顯示;實務上應偵測文字真被截斷 `scrollWidth > clientWidth` 時才掛 tooltip)</Label>
|
|
201
201
|
</Rule>
|
|
@@ -55,7 +55,11 @@ Tooltip 的判斷標準是:**畫面上的資訊是否已經足夠讓使用者
|
|
|
55
55
|
|
|
56
56
|
## 與 Button icon-only 的關係
|
|
57
57
|
|
|
58
|
-
Button 的 `iconOnly` 模式已內建自動 tooltip(以 `aria-label` 驅動),開發者不需要額外包 `<Tooltip
|
|
58
|
+
Button 的 `iconOnly` 模式已內建自動 tooltip(以 `aria-label` 驅動),開發者不需要額外包 `<Tooltip>`。
|
|
59
|
+
|
|
60
|
+
**例外——`iconOnly` + `asChild`**:當 `iconOnly` 同時搭配 `asChild` 時,內建 tooltip wrapper **不啟動**(Radix Slot 只接受單一 child,Button 主動補 tooltip 會破壞單 child 規則)。此時 consumer 必須**自行傳入 child 的 `aria-label`** 給螢幕閱讀器,並視需要自行包 `<Tooltip>`(見 `../Button/button.spec.md` 與 `button.tsx` 的 asChild 警告)。
|
|
61
|
+
|
|
62
|
+
只有在非 Button 元素需要 tooltip 時,才手動使用 Tooltip 元件。
|
|
59
63
|
|
|
60
64
|
## 內容完整性
|
|
61
65
|
|
|
@@ -90,6 +94,7 @@ Tooltip 最大寬度 **280px**(見 `.tsx` 的 `max-w-[280px]`)——超過
|
|
|
90
94
|
- **觸控裝置**:無 hover,tooltip 無法觸發——必要資訊不可只靠 tooltip 承載(見「何時不用」「禁止事項」)
|
|
91
95
|
- **長文字**:超過 max-width 280px 自動換行、完整呈現不截斷(見「最大寬度」「內容完整性」)
|
|
92
96
|
- **貼近 viewport 邊**:Radix 自動翻邊 + `collisionPadding` 8px 呼吸距離(見「Edge collision」)
|
|
97
|
+
- **空內容**:`TooltipContent` 的 `children` 為 `null` / `undefined` / `false` / 空字串時**不掛浮層**——不渲染帶 padding 的空 `role="tooltip"` 殼,trigger 原樣保留。Tooltip 是資訊補救機制(見「何時用」),沒有補充內容就不該出現。實作於 `tooltip.tsx` 的 `TooltipContent` 以空值 guard 提早 return null 落地
|
|
93
98
|
|
|
94
99
|
## 禁止事項
|
|
95
100
|
|
|
@@ -98,6 +103,7 @@ Tooltip 最大寬度 **280px**(見 `.tsx` 的 `max-w-[280px]`)——超過
|
|
|
98
103
|
- ❌ 不要把 tooltip 當作必要資訊的唯一載體——tooltip 需要 hover 才能看到,觸控裝置無法觸發
|
|
99
104
|
- ❌ 不要為個別 tooltip 設定不同的延遲時間——全產品統一一組參數
|
|
100
105
|
- ❌ 不要在 tooltip 內截斷資訊——tooltip 是資訊終點,內容必須完整
|
|
106
|
+
- ❌ 不要對 `TooltipContent` 傳空內容——空 tooltip 是無意義的視覺雜訊(空值時元件不掛浮層,見「邊界狀態」)
|
|
101
107
|
|
|
102
108
|
---
|
|
103
109
|
|
|
@@ -105,11 +111,11 @@ Tooltip 最大寬度 **280px**(見 `.tsx` 的 `max-w-[280px]`)——超過
|
|
|
105
111
|
|
|
106
112
|
Tooltip 是**單一職責 hover 提示 primitive**(一句話補充),刻意無變體:
|
|
107
113
|
|
|
108
|
-
- **無 ColorMatrix**:Tooltip 固定一種視覺(
|
|
114
|
+
- **無 ColorMatrix**:Tooltip 固定一種視覺(`--tooltip` bg + white text,內部 wrapper 強制 `data-theme="dark"`——不隨頁面主題反轉,dark mode 下 `--tooltip` 有自己的深色值),無 variant / severity / hue。若需要有色 hint,那是 Popover / HoverCard 的職責。故無 color matrix。
|
|
109
115
|
- **無 SizeMatrix**:Tooltip 無 size prop,尺寸由內容 + max-width 常數決定(本 spec「最大寬度」段)。不提供 sm/md/lg tier——短文字 hint 不需要尺寸變體。
|
|
110
116
|
- **無 StateBehavior**:Tooltip 是 passive 出現 / 消失(hover / focus 觸發,見「出現時機」段),無 hover / selected / active / disabled 這類互動元件 state。開 / 關行為由 Radix primitive 處理,寫在 `Overview` 的 usage 說明已足夠。
|
|
111
117
|
|
|
112
|
-
對應 anatomy story:保留 `Overview` + `Inspector`(
|
|
118
|
+
對應 anatomy story:保留 `Overview` + `Inspector`(side 切換 + token 對照) + 元件特有 `PlacementReference`(4 種 side 方向對照 + side-aware 動畫表;Tooltip 走 `align="center"` 輕量浮層例外,見「Align 對齊」段,無 align 軸矩陣)。
|
|
113
119
|
|
|
114
120
|
---
|
|
115
121
|
|
|
@@ -23,7 +23,16 @@ const TooltipTrigger = TooltipPrimitive.Trigger
|
|
|
23
23
|
const TooltipContent = React.forwardRef<
|
|
24
24
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
25
25
|
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
26
|
-
>(({ className, sideOffset = OVERLAY_SIDE_OFFSET, collisionPadding = OVERLAY_COLLISION_PADDING, style, children, ...props }, ref) =>
|
|
26
|
+
>(({ className, sideOffset = OVERLAY_SIDE_OFFSET, collisionPadding = OVERLAY_COLLISION_PADDING, style, children, ...props }, ref) => {
|
|
27
|
+
// 空內容不掛浮層:children 為 null / undefined / false / 空字串時不渲染帶 padding 的空
|
|
28
|
+
// role="tooltip" 殼(見 spec「邊界狀態」)。Tooltip 是資訊補救機制,無補充內容即不出現,
|
|
29
|
+
// trigger 由 TooltipTrigger 原樣保留。
|
|
30
|
+
const isEmptyContent =
|
|
31
|
+
children == null ||
|
|
32
|
+
children === false ||
|
|
33
|
+
(typeof children === 'string' && children.trim() === '')
|
|
34
|
+
if (isEmptyContent) return null
|
|
35
|
+
return (
|
|
27
36
|
// collisionPadding default 8px:避免 tooltip 貼 viewport 邊(Radix avoidCollisions 預設 true 但 padding 0 會貼邊)
|
|
28
37
|
// 消費 OVERLAY_COLLISION_PADDING overlay 家族 canonical(與 Popover 一致;HoverCard 特例 12 補 rounding)避免 viewport edge clipping
|
|
29
38
|
<TooltipPrimitive.Portal>
|
|
@@ -48,7 +57,8 @@ const TooltipContent = React.forwardRef<
|
|
|
48
57
|
<div data-theme="dark" className="contents">{children}</div>
|
|
49
58
|
</TooltipPrimitive.Content>
|
|
50
59
|
</TooltipPrimitive.Portal>
|
|
51
|
-
)
|
|
60
|
+
)
|
|
61
|
+
})
|
|
52
62
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
|
53
63
|
|
|
54
64
|
// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)
|
|
@@ -283,11 +283,11 @@ export const ColorMatrix: Story = {
|
|
|
283
283
|
<H3>Hover + Selected 並存的實際渲染</H3>
|
|
284
284
|
<Desc>以下 `Documents/Photos/beach.jpg` 為 selected row,可 hover 任一其他 row 觀察 neutral-hover。</Desc>
|
|
285
285
|
<div className="border border-border rounded-lg p-4 max-w-md">
|
|
286
|
-
<TreeView selectedIds={selected} onSelectedChange={setSelected} defaultExpandedIds={['docs', 'photos']}>
|
|
287
|
-
<TreeItem id="docs" label="Documents
|
|
286
|
+
<TreeView aria-label="色彩狀態範例檔案樹" selectedIds={selected} onSelectedChange={setSelected} defaultExpandedIds={['docs', 'photos']}>
|
|
287
|
+
<TreeItem id="docs" label="Documents" icon={Folder}>
|
|
288
288
|
<TreeItem id="resume" label="Resume.pdf" icon={FileText} />
|
|
289
289
|
<TreeItem id="photos" label="Photos" icon={Folder}>
|
|
290
|
-
<TreeItem id="beach" label="beach.jpg
|
|
290
|
+
<TreeItem id="beach" label="beach.jpg" icon={Image} />
|
|
291
291
|
<TreeItem id="trip" label="trip.jpg" icon={Image} />
|
|
292
292
|
</TreeItem>
|
|
293
293
|
</TreeItem>
|
|
@@ -307,11 +307,11 @@ export const IndentMatrix: Story = {
|
|
|
307
307
|
<H3>indentStep = chevronSize + gap-2</H3>
|
|
308
308
|
<Desc>每層 indent 剛好是 chevron(16 / 20px)+ gap-2(8px)的距離——跟 item-layout 的 prefix-content gap 一致。讓 tree indent 視覺跟 item-layout 融為一體,不是獨立數字系統。</Desc>
|
|
309
309
|
<div className="border border-border rounded-lg p-4 max-w-md">
|
|
310
|
-
<TreeView defaultExpandedIds={['
|
|
311
|
-
<TreeItem id="
|
|
312
|
-
<TreeItem id="
|
|
313
|
-
<TreeItem id="
|
|
314
|
-
<TreeItem id="
|
|
310
|
+
<TreeView aria-label="品牌資產資料夾樹" defaultExpandedIds={['brand', 'website', 'images']}>
|
|
311
|
+
<TreeItem id="brand" label="品牌資產" icon={Folder}>
|
|
312
|
+
<TreeItem id="website" label="網站" icon={Folder}>
|
|
313
|
+
<TreeItem id="images" label="圖片" icon={Folder}>
|
|
314
|
+
<TreeItem id="hero" label="首頁橫幅.png" icon={Image} />
|
|
315
315
|
</TreeItem>
|
|
316
316
|
</TreeItem>
|
|
317
317
|
</TreeItem>
|
|
@@ -323,15 +323,17 @@ export const IndentMatrix: Story = {
|
|
|
323
323
|
<H3>葉節點 chevron placeholder</H3>
|
|
324
324
|
<Desc>同層有展開 icon、有的沒有 → label 不會對齊。TreeView 自動給葉節點留透明 chevron placeholder,label 永遠對齊 column。</Desc>
|
|
325
325
|
<div className="border border-border rounded-lg p-4 max-w-md">
|
|
326
|
-
<TreeView defaultExpandedIds={['
|
|
327
|
-
<TreeItem id="
|
|
328
|
-
<TreeItem id="
|
|
329
|
-
<TreeItem id="
|
|
330
|
-
|
|
326
|
+
<TreeView aria-label="設計交付資料夾樹" defaultExpandedIds={['delivery']}>
|
|
327
|
+
<TreeItem id="delivery" label="設計交付" icon={Folder}>
|
|
328
|
+
<TreeItem id="spec" label="元件規格.pdf" icon={FileText} />
|
|
329
|
+
<TreeItem id="assets" label="切版素材" icon={Folder}>
|
|
330
|
+
<TreeItem id="icons" label="圖示集.svg" icon={Image} />
|
|
331
|
+
</TreeItem>
|
|
332
|
+
<TreeItem id="checklist" label="交付清單.md" icon={FileText} />
|
|
331
333
|
</TreeItem>
|
|
332
334
|
</TreeView>
|
|
333
335
|
</div>
|
|
334
|
-
<p className="text-footnote text-fg-muted mt-3">↑
|
|
336
|
+
<p className="text-footnote text-fg-muted mt-3">↑ 葉節點(元件規格.pdf / 交付清單.md)與可展開資料夾(切版素材)label 左側對齊 — 不因有無 chevron 位移</p>
|
|
335
337
|
</div>
|
|
336
338
|
</div>
|
|
337
339
|
),
|
|
@@ -78,9 +78,24 @@ export const UsageGuidance: Story = {
|
|
|
78
78
|
<Section title="何時不用 + 替代方案">
|
|
79
79
|
<Rule
|
|
80
80
|
title='❌ 互斥展開(同時只開一個):用 Accordion type="single"'
|
|
81
|
-
note=
|
|
81
|
+
note='TreeView 預設允許任意多個節點同時展開。平面設定分段若需要「展開一個、其他自動收合」的互斥語意,用 Accordion type="single"(非 TreeView)'
|
|
82
82
|
>
|
|
83
|
-
<
|
|
83
|
+
<div className="border border-border rounded-lg p-3 w-80">
|
|
84
|
+
<TreeView aria-label="帳號設定分段" selectionMode="none" defaultExpandedIds={['account', 'notify', 'privacy']}>
|
|
85
|
+
<TreeItem id="account" label="帳號設定">
|
|
86
|
+
<TreeItem id="account-email" label="電子郵件" />
|
|
87
|
+
<TreeItem id="account-password" label="密碼" />
|
|
88
|
+
</TreeItem>
|
|
89
|
+
<TreeItem id="notify" label="通知偏好">
|
|
90
|
+
<TreeItem id="notify-email" label="信件通知" />
|
|
91
|
+
<TreeItem id="notify-push" label="推播通知" />
|
|
92
|
+
</TreeItem>
|
|
93
|
+
<TreeItem id="privacy" label="隱私與安全">
|
|
94
|
+
<TreeItem id="privacy-2fa" label="兩步驟驗證" />
|
|
95
|
+
</TreeItem>
|
|
96
|
+
</TreeView>
|
|
97
|
+
</div>
|
|
98
|
+
<Label warn>↑ 三個設定分段在 TreeView 裡可同時展開;要「展開一個自動收其他」的互斥手風琴,用 Accordion type="single"</Label>
|
|
84
99
|
</Rule>
|
|
85
100
|
</Section>
|
|
86
101
|
|
|
@@ -101,10 +116,10 @@ export const UsageGuidance: Story = {
|
|
|
101
116
|
</Rule>
|
|
102
117
|
|
|
103
118
|
<Rule
|
|
104
|
-
title="❌
|
|
105
|
-
note="Sidebar
|
|
119
|
+
title="❌ 純視覺分段(設計時可列舉的固定選單):用 SidebarGroup 不用 TreeView"
|
|
120
|
+
note="Sidebar 主選單只接受 1 層可列舉項目——設計時就固定死、不會 runtime 新增的分段,用 SidebarGroup 純視覺分段即可。真階層 user data(專案 / 子專案、部門樹,即使只有 2 層、未來會長)才用 TreeView(見 sidebar.spec.md「判斷規則」)"
|
|
106
121
|
>
|
|
107
|
-
<Label warn
|
|
122
|
+
<Label warn>固定分段用 SidebarGroup 就夠,不需要 TreeView 的遞迴 overhead;user data 樹則一律 TreeView</Label>
|
|
108
123
|
</Rule>
|
|
109
124
|
</Section>
|
|
110
125
|
</div>
|
|
@@ -174,16 +189,34 @@ export const IndentRule: Story = {
|
|
|
174
189
|
note="同層 siblings 有展開 icon、有的沒有 → label 不對齊。TreeView 自動給葉節點留 chevron 位置(透明 placeholder),consumer 不需介入"
|
|
175
190
|
>
|
|
176
191
|
<div className="border border-border rounded-lg p-3 w-80">
|
|
177
|
-
<TreeView defaultExpandedIds={['
|
|
178
|
-
<TreeItem id="
|
|
179
|
-
<TreeItem id="
|
|
180
|
-
<TreeItem id="
|
|
181
|
-
<TreeItem id="
|
|
192
|
+
<TreeView aria-label="行銷素材資料夾樹" defaultExpandedIds={['assets', 'social']}>
|
|
193
|
+
<TreeItem id="assets" label="行銷素材" icon={Folder}>
|
|
194
|
+
<TreeItem id="hero" label="活動主視覺.png" icon={Image} />
|
|
195
|
+
<TreeItem id="social" label="社群貼文" icon={Folder}>
|
|
196
|
+
<TreeItem id="story" label="限動範本.psd" icon={FileText} />
|
|
182
197
|
</TreeItem>
|
|
183
198
|
</TreeItem>
|
|
184
199
|
</TreeView>
|
|
185
200
|
</div>
|
|
186
|
-
<Label>↑
|
|
201
|
+
<Label>↑ 「活動主視覺.png」是葉,「社群貼文」可展開——兩者 label 依然垂直對齊</Label>
|
|
202
|
+
</Rule>
|
|
203
|
+
|
|
204
|
+
<Rule
|
|
205
|
+
title="❌ 混用有 icon / 無 icon 的節點"
|
|
206
|
+
note="Chevron 有自動佔位(leaf 也留等寬空白),但 icon 無自動佔位——同層有些節點傳 icon、有些沒傳,label 起點會直接錯開。要嘛全傳 icon,要嘛全不傳(見 spec「Icon 一致性原則」)"
|
|
207
|
+
>
|
|
208
|
+
<div className="border border-border rounded-lg p-3 w-80">
|
|
209
|
+
<TreeView aria-label="icon 混用反例檔案樹" defaultExpandedIds={['src', 'public']}>
|
|
210
|
+
<TreeItem id="src" label="src" icon={Folder}>
|
|
211
|
+
<TreeItem id="app" label="App.tsx" icon={FileText} />
|
|
212
|
+
<TreeItem id="readme" label="README.md" />
|
|
213
|
+
</TreeItem>
|
|
214
|
+
<TreeItem id="public" label="public">
|
|
215
|
+
<TreeItem id="favicon" label="favicon.ico" icon={Image} />
|
|
216
|
+
</TreeItem>
|
|
217
|
+
</TreeView>
|
|
218
|
+
</div>
|
|
219
|
+
<Label warn>↑ 「README.md」「public」沒傳 icon → label 起點比有 icon 的節點前移,視覺節奏錯開</Label>
|
|
187
220
|
</Rule>
|
|
188
221
|
</div>
|
|
189
222
|
),
|