@qijenchen/design-system 0.1.0-beta.61 → 0.1.0-beta.63
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/CLAUDE.md +6 -6
- package/dist/components/Accordion/accordion.d.ts +1 -1
- package/dist/components/Accordion/accordion.js +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Alert/alert.d.ts +2 -2
- package/dist/components/Alert/alert.js +4 -3
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +4 -3
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts +1 -1
- package/dist/components/Avatar/avatar.js +2 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Badge/badge.d.ts +1 -1
- package/dist/components/Badge/badge.js +2 -1
- package/dist/components/Badge/badge.js.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button.d.ts +5 -5
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +4 -3
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +1 -1
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +80 -69
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +5 -3
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Checkbox/checkbox-group.d.ts +2 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +9 -3
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +8 -3
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +2 -2
- package/dist/components/Chip/chip.js +3 -2
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/CircularProgress/circular-progress.d.ts +1 -1
- package/dist/components/CircularProgress/circular-progress.js +2 -1
- package/dist/components/CircularProgress/circular-progress.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +4 -4
- package/dist/components/Coachmark/coachmark.js +2 -1
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +17 -13
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts +4 -0
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DateGrid/date-grid.d.ts +8 -4
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +2 -2
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +6 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.js +1 -1
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- 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 +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +0 -1
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Empty/empty.d.ts +1 -1
- package/dist/components/Empty/empty.js.map +1 -1
- package/dist/components/Field/field-wrapper.js +1 -1
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +1 -0
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts +8 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +7 -3
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +25 -14
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +5 -1
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +2 -1
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts +6 -2
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +5 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +2 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +4 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -2
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +6 -2
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/Popover/popover.d.ts +1 -1
- package/dist/components/Popover/popover.js +2 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +9 -4
- package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +6 -0
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +4 -0
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +14 -4
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +4 -0
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +6 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/selection-item.d.ts +5 -1
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
- package/dist/components/SelectionControl/selection-item.js +3 -1
- package/dist/components/SelectionControl/selection-item.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +6 -5
- 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.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +3 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Skeleton/skeleton.d.ts +1 -1
- package/dist/components/Skeleton/skeleton.js +2 -1
- package/dist/components/Skeleton/skeleton.js.map +1 -1
- package/dist/components/Slider/slider.d.ts +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +7 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +1 -1
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +9 -6
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +5 -5
- package/dist/components/Switch/switch.js +3 -3
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.js +1 -1
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Textarea/textarea.js +1 -1
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.js +1 -1
- package/dist/components/TimePicker/time-columns.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +2 -1
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Toast/toast.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts +1 -1
- package/dist/components/Tooltip/tooltip.js +2 -1
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +4 -4
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +3 -3
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +3 -3
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/patterns/header-canonical/chrome-header.d.ts +3 -2
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -1
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +3 -2
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
- package/ds-canonical/hooks/_log-fire.sh +3 -1
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +21 -1
- package/ds-canonical/hooks/check_audit_sample_escape.sh +6 -3
- package/ds-canonical/hooks/check_chrome_header_avatar_canonical.sh +8 -0
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +321 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +75 -12
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +15 -1
- package/ds-canonical/hooks/check_field_family_invariants.sh +12 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +137 -0
- package/ds-canonical/hooks/check_propose_discipline.sh +147 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +11 -1
- package/ds-canonical/hooks/check_story_invariants.sh +63 -9
- package/ds-canonical/hooks/check_storybook_addon_packaging.sh +151 -0
- package/ds-canonical/hooks/check_tailwind_wildcard_in_docs.sh +8 -2
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +25 -4
- package/ds-canonical/hooks/lib/_token_hygiene.sh +9 -1
- package/ds-canonical/hooks/session_start_governance_check.sh +7 -2
- package/ds-canonical/hooks/stop_self_audit.sh +2 -2
- package/ds-canonical/hooks/tests/test_check_addon_subdir_ship.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +12 -0
- package/ds-canonical/hooks/tests/test_check_consumer_app_story_title.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +6 -4
- package/ds-canonical/hooks/tests/test_check_consumer_no_ds_catalog.sh +7 -4
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +6 -4
- package/ds-canonical/hooks/tests/test_check_data_table_size_num_to_meta_width.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_fork_user_plugin_install.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +9 -0
- package/ds-canonical/hooks/tests/test_check_propose_cite_required.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +10 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +10 -0
- package/ds-canonical/hooks/tests/test_check_storybook_addon_preset_cjs.sh +3 -2
- package/ds-canonical/references/build-ui-canonicals.md +2 -2
- package/ds-canonical/references/composition-fidelity.md +3 -3
- package/ds-canonical/references/naming-conventions.md +1 -0
- package/ds-canonical/references/ssot-consultation.md +1 -1
- package/ds-canonical/references/ssot-index.md +7 -7
- package/ds-canonical/rules/meta-patterns.md +5 -5
- package/ds-canonical/rules/self-verify.md +1 -1
- package/ds-canonical/rules/story-rules.md +2 -0
- package/ds-canonical/rules/ui-development.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +11 -2
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +15 -15
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +4 -3
- package/ds-story-manifest.json +15 -21
- package/llms-full.txt +9 -5
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
- package/src/components/Accordion/accordion.spec.md +22 -5
- package/src/components/Accordion/accordion.tsx +1 -1
- package/src/components/Alert/alert.anatomy.stories.tsx +4 -4
- package/src/components/Alert/alert.principles.stories.tsx +5 -5
- package/src/components/Alert/alert.spec.md +16 -11
- package/src/components/Alert/alert.stories.tsx +5 -5
- package/src/components/Alert/alert.tsx +2 -2
- package/src/components/AppShell/app-shell.principles.stories.tsx +68 -21
- package/src/components/AppShell/app-shell.spec.md +17 -24
- package/src/components/AppShell/app-shell.tsx +4 -3
- package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +3 -3
- package/src/components/AspectRatio/aspect-ratio.spec.md +15 -1
- package/src/components/Avatar/avatar.anatomy.stories.tsx +1 -1
- package/src/components/Avatar/avatar.principles.stories.tsx +8 -8
- package/src/components/Avatar/avatar.spec.md +25 -54
- package/src/components/Avatar/avatar.tsx +2 -2
- package/src/components/Badge/badge.principles.stories.tsx +2 -2
- package/src/components/Badge/badge.spec.md +22 -13
- package/src/components/Badge/badge.tsx +1 -1
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +5 -2
- package/src/components/Breadcrumb/breadcrumb.spec.md +25 -25
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +7 -32
- package/src/components/Breadcrumb/breadcrumb.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +2 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +20 -6
- package/src/components/BulkActionBar/bulk-action-bar.tsx +2 -2
- package/src/components/Button/button.anatomy.stories.tsx +2 -2
- package/src/components/Button/button.spec.md +19 -17
- package/src/components/Button/button.stories.tsx +1 -1
- package/src/components/Button/button.tsx +10 -9
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +37 -17
- package/src/components/Calendar/calendar.tsx +26 -22
- package/src/components/Carousel/carousel.anatomy.stories.tsx +6 -6
- package/src/components/Carousel/carousel.principles.stories.tsx +1 -1
- package/src/components/Carousel/carousel.spec.md +23 -3
- package/src/components/Carousel/carousel.tsx +19 -4
- package/src/components/Chart/chart.anatomy.stories.tsx +1 -1
- package/src/components/Chart/chart.spec.md +20 -1
- package/src/components/Checkbox/checkbox-group.tsx +2 -1
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.principles.stories.tsx +2 -2
- package/src/components/Checkbox/checkbox.spec.md +35 -15
- package/src/components/Checkbox/checkbox.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.tsx +14 -3
- package/src/components/Chip/chip.anatomy.stories.tsx +5 -5
- package/src/components/Chip/chip.principles.stories.tsx +9 -3
- package/src/components/Chip/chip.spec.md +8 -9
- package/src/components/Chip/chip.tsx +2 -2
- package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +6 -6
- package/src/components/CircularProgress/circular-progress.spec.md +10 -11
- package/src/components/CircularProgress/circular-progress.stories.tsx +36 -43
- package/src/components/CircularProgress/circular-progress.tsx +1 -1
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +1 -1
- package/src/components/Coachmark/coachmark.principles.stories.tsx +14 -29
- package/src/components/Coachmark/coachmark.spec.md +21 -13
- package/src/components/Coachmark/coachmark.tsx +4 -4
- package/src/components/Combobox/combobox.anatomy.stories.tsx +28 -28
- package/src/components/Combobox/combobox.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.spec.md +25 -7
- package/src/components/Combobox/combobox.tsx +12 -3
- package/src/components/Command/command.anatomy.stories.tsx +1 -1
- package/src/components/Command/command.principles.stories.tsx +8 -8
- package/src/components/Command/command.spec.md +18 -8
- package/src/components/Command/command.tsx +8 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +1 -1
- package/src/components/DataTable/data-table.anatomy.stories.tsx +9 -7
- package/src/components/DataTable/data-table.principles.stories.tsx +3 -3
- package/src/components/DataTable/data-table.spec.md +15 -11
- package/src/components/DataTable/data-table.stories.tsx +58 -13
- package/src/components/DataTable/data-table.tsx +13 -0
- package/src/components/DataTable/filter-operators.spec.md +19 -27
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +8 -8
- package/src/components/DateGrid/date-grid.principles.stories.tsx +7 -7
- package/src/components/DateGrid/date-grid.spec.md +17 -14
- package/src/components/DateGrid/date-grid.tsx +8 -4
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +11 -15
- package/src/components/DatePicker/date-picker.principles.stories.tsx +8 -8
- package/src/components/DatePicker/date-picker.spec.md +40 -36
- package/src/components/DatePicker/date-picker.stories.tsx +23 -53
- package/src/components/DatePicker/date-picker.tsx +12 -6
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.principles.stories.tsx +4 -18
- package/src/components/DescriptionList/description-list.spec.md +9 -3
- package/src/components/DescriptionList/description-list.stories.tsx +2 -18
- package/src/components/DescriptionList/description-list.tsx +1 -1
- package/src/components/Dialog/dialog.principles.stories.tsx +1 -1
- package/src/components/Dialog/dialog.spec.md +26 -11
- package/src/components/Dialog/dialog.stories.tsx +159 -184
- package/src/components/Dialog/dialog.tsx +2 -1
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +2 -2
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +16 -17
- package/src/components/DropdownMenu/dropdown-menu.spec.md +10 -15
- package/src/components/DropdownMenu/dropdown-menu.stories.tsx +13 -15
- package/src/components/DropdownMenu/dropdown-menu.tsx +12 -2
- package/src/components/Empty/empty.spec.md +19 -18
- package/src/components/Empty/empty.tsx +1 -1
- package/src/components/Field/field-controls.spec.md +52 -41
- package/src/components/Field/field-wrapper.tsx +2 -2
- package/src/components/Field/field.anatomy.stories.tsx +6 -5
- package/src/components/Field/field.principles.stories.tsx +8 -7
- package/src/components/Field/field.spec.md +42 -20
- package/src/components/Field/field.stories.tsx +9 -7
- package/src/components/Field/field.tsx +6 -3
- package/src/components/Field/form-validation.spec.md +20 -19
- package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +16 -15
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +5 -1
- package/src/components/FieldControlGroup/field-control-group.spec.md +17 -1
- package/src/components/FieldControlGroup/field-control-group.stories.tsx +9 -9
- package/src/components/FieldControlGroup/field-control-group.tsx +4 -3
- package/src/components/FileItem/file-item.anatomy.stories.tsx +7 -17
- package/src/components/FileItem/file-item.principles.stories.tsx +7 -7
- package/src/components/FileItem/file-item.spec.md +24 -24
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +4 -2
- package/src/components/FileUpload/file-upload.principles.stories.tsx +10 -12
- package/src/components/FileUpload/file-upload.spec.md +37 -8
- package/src/components/FileUpload/file-upload.tsx +5 -3
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +16 -11
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +4 -4
- package/src/components/FileViewer/file-viewer.spec.md +7 -19
- package/src/components/FileViewer/file-viewer.stories.tsx +3 -3
- package/src/components/FileViewer/file-viewer.tsx +42 -16
- package/src/components/HoverCard/hover-card.spec.md +20 -10
- package/src/components/HoverCard/hover-card.stories.tsx +1 -1
- package/src/components/HoverCard/hover-card.tsx +12 -1
- package/src/components/Input/input.anatomy.stories.tsx +4 -4
- package/src/components/Input/input.principles.stories.tsx +4 -31
- package/src/components/Input/input.spec.md +16 -4
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.spec.md +14 -1
- package/src/components/Menu/menu-item.principles.stories.tsx +5 -5
- package/src/components/Menu/menu-item.spec.md +24 -12
- package/src/components/Menu/menu-item.tsx +7 -3
- package/src/components/Notice/notice.principles.stories.tsx +7 -7
- package/src/components/Notice/notice.spec.md +7 -5
- package/src/components/Notice/notice.tsx +5 -1
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.principles.stories.tsx +13 -35
- package/src/components/NumberInput/number-input.spec.md +19 -0
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +4 -3
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +2 -5
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +9 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -42
- package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -3
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +11 -2
- package/src/components/PeoplePicker/people-picker.spec.md +26 -12
- package/src/components/PeoplePicker/people-picker.stories.tsx +14 -15
- package/src/components/PeoplePicker/people-picker.tsx +12 -4
- package/src/components/Popover/popover.spec.md +20 -11
- package/src/components/Popover/popover.tsx +2 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.principles.stories.tsx +29 -25
- package/src/components/ProfileCard/profile-card.spec.md +30 -10
- package/src/components/ProfileCard/profile-card.tsx +12 -7
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +7 -5
- package/src/components/ProgressBar/progress-bar.spec.md +9 -1
- package/src/components/ProgressBar/progress-bar.stories.tsx +1 -1
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +6 -3
- package/src/components/RadioGroup/radio-group.principles.stories.tsx +6 -13
- package/src/components/RadioGroup/radio-group.spec.md +7 -1
- package/src/components/RadioGroup/radio-group.tsx +10 -0
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -0
- package/src/components/Rating/rating.principles.stories.tsx +9 -6
- package/src/components/Rating/rating.spec.md +13 -7
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +44 -24
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +51 -57
- package/src/components/ScrollArea/scroll-area.spec.md +5 -7
- package/src/components/ScrollArea/scroll-area.stories.tsx +110 -60
- package/src/components/ScrollArea/scroll-area.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +15 -14
- package/src/components/SegmentedControl/segmented-control.stories.tsx +1 -1
- package/src/components/Select/select.anatomy.stories.tsx +12 -11
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +34 -8
- package/src/components/Select/select.stories.tsx +2 -2
- package/src/components/Select/select.tsx +18 -3
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +2 -2
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +5 -5
- package/src/components/SelectMenu/select-menu.spec.md +19 -12
- package/src/components/SelectMenu/select-menu.stories.tsx +34 -27
- package/src/components/SelectMenu/select-menu.tsx +14 -3
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.spec.md +13 -2
- package/src/components/SelectionControl/selection-item.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.tsx +8 -2
- package/src/components/Separator/separator.principles.stories.tsx +2 -2
- package/src/components/Separator/separator.spec.md +11 -5
- package/src/components/Sheet/sheet.anatomy.stories.tsx +7 -6
- package/src/components/Sheet/sheet.principles.stories.tsx +18 -38
- package/src/components/Sheet/sheet.spec.md +9 -11
- package/src/components/Sheet/sheet.stories.tsx +2 -2
- package/src/components/Sheet/sheet.tsx +6 -5
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +42 -33
- package/src/components/Sidebar/sidebar.principles.stories.tsx +4 -4
- package/src/components/Sidebar/sidebar.spec.md +22 -17
- package/src/components/Sidebar/sidebar.stories.tsx +16 -0
- package/src/components/Sidebar/sidebar.tsx +15 -7
- package/src/components/Skeleton/skeleton.anatomy.stories.tsx +2 -2
- package/src/components/Skeleton/skeleton.principles.stories.tsx +20 -7
- package/src/components/Skeleton/skeleton.spec.md +6 -4
- package/src/components/Skeleton/skeleton.stories.tsx +34 -26
- package/src/components/Skeleton/skeleton.tsx +1 -1
- package/src/components/Slider/slider.principles.stories.tsx +3 -3
- package/src/components/Slider/slider.spec.md +16 -12
- package/src/components/Slider/slider.stories.tsx +2 -18
- package/src/components/Slider/slider.tsx +6 -2
- package/src/components/Steps/steps.anatomy.stories.tsx +3 -3
- package/src/components/Steps/steps.principles.stories.tsx +9 -12
- package/src/components/Steps/steps.spec.md +31 -25
- package/src/components/Steps/steps.stories.tsx +5 -40
- package/src/components/Steps/steps.tsx +17 -12
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +13 -0
- package/src/components/Switch/switch.tsx +3 -3
- package/src/components/Tabs/tabs.anatomy.stories.tsx +4 -4
- package/src/components/Tabs/tabs.principles.stories.tsx +1 -1
- package/src/components/Tabs/tabs.spec.md +13 -6
- package/src/components/Tabs/tabs.stories.tsx +3 -3
- package/src/components/Tabs/tabs.tsx +2 -2
- package/src/components/Tag/tag.anatomy.stories.tsx +15 -15
- package/src/components/Tag/tag.principles.stories.tsx +1 -1
- package/src/components/Tag/tag.spec.md +25 -5
- package/src/components/Textarea/textarea.anatomy.stories.tsx +3 -3
- package/src/components/Textarea/textarea.principles.stories.tsx +7 -7
- package/src/components/Textarea/textarea.spec.md +15 -3
- package/src/components/Textarea/textarea.tsx +1 -1
- package/src/components/TimePicker/time-columns.tsx +1 -1
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +8 -2
- package/src/components/TimePicker/time-picker.spec.md +23 -3
- package/src/components/TimePicker/time-picker.tsx +5 -3
- package/src/components/Toast/toast.anatomy.stories.tsx +1 -1
- package/src/components/Toast/toast.spec.md +7 -4
- package/src/components/Toast/toast.stories.tsx +12 -6
- package/src/components/Toast/toast.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.spec.md +11 -8
- package/src/components/Tooltip/tooltip.tsx +1 -1
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +25 -9
- package/src/components/TreeView/tree-view.principles.stories.tsx +5 -5
- package/src/components/TreeView/tree-view.spec.md +11 -9
- package/src/components/TreeView/tree-view.stories.tsx +5 -3
- package/src/components/TreeView/tree-view.tsx +8 -5
- package/src/patterns/action-bar/action-bar.spec.md +11 -4
- package/src/patterns/element-anatomy/element-anatomy.spec.md +8 -6
- package/src/patterns/element-anatomy/inline-action.spec.md +18 -18
- package/src/patterns/element-anatomy/item-anatomy.spec.md +47 -42
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -6
- package/src/patterns/element-anatomy/item-anatomy.tsx +3 -3
- package/src/patterns/header-canonical/chrome-header.tsx +3 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +24 -11
- package/src/patterns/header-canonical/header-canonical.stories.tsx +9 -9
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +22 -12
- package/src/patterns/overlay-surface/overlay-surface.spec.md +43 -39
- package/src/patterns/overlay-surface/overlay-surface.tsx +3 -2
- package/src/patterns/resize-handle/resize-handle.spec.md +10 -1
- package/src/patterns/resize-handle/resize-handle.stories.tsx +7 -7
- package/src/tokens/README.md +5 -2
- package/src/tokens/color/color.spec.md +17 -10
- package/src/tokens/color/semantic.css +2 -0
- package/src/tokens/density/density.spec.md +4 -14
- package/src/tokens/elevation/elevation.spec.md +7 -8
- package/src/tokens/layoutSpace/layoutSpace.spec.md +20 -27
- package/src/tokens/motion/motion.spec.md +15 -7
- package/src/tokens/opacity/opacity.spec.md +15 -26
- package/src/tokens/orphan-tokens.spec.md +14 -3
- package/src/tokens/radius/radius.spec.md +13 -15
- package/src/tokens/token-system.spec.md +10 -13
- package/src/tokens/typography/typography.spec.md +8 -12
- package/src/tokens/uiSize/uiSize.spec.md +28 -16
- /package/ds-canonical/hooks/{check_addon_subdir_ship.sh → retired/2026-06-11-prune-merge/check_addon_subdir_ship.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_app_story_title.sh → retired/2026-06-11-prune-merge/check_consumer_app_story_title.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_ds_primitive_misuse.sh → retired/2026-06-11-prune-merge/check_consumer_ds_primitive_misuse.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_no_ds_catalog.sh → retired/2026-06-11-prune-merge/check_consumer_no_ds_catalog.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_story_baseline.sh → retired/2026-06-11-prune-merge/check_consumer_story_baseline.sh} +0 -0
- /package/ds-canonical/hooks/{check_data_table_size_num_to_meta_width.sh → retired/2026-06-11-prune-merge/check_data_table_size_num_to_meta_width.sh} +0 -0
- /package/ds-canonical/hooks/{check_fork_user_plugin_install.sh → retired/2026-06-11-prune-merge/check_fork_user_plugin_install.sh} +0 -0
- /package/ds-canonical/hooks/{check_plugin_freshness.sh → retired/2026-06-11-prune-merge/check_plugin_freshness.sh} +0 -0
- /package/ds-canonical/hooks/{check_propose_cite_required.sh → retired/2026-06-11-prune-merge/check_propose_cite_required.sh} +0 -0
- /package/ds-canonical/hooks/{check_propose_plain_chinese.sh → retired/2026-06-11-prune-merge/check_propose_plain_chinese.sh} +0 -0
- /package/ds-canonical/hooks/{check_storybook_addon_preset_cjs.sh → retired/2026-06-11-prune-merge/check_storybook_addon_preset_cjs.sh} +0 -0
|
@@ -48,11 +48,11 @@ Sheet 是**從畫面邊緣滑入的浮層面板**。**消費者 API = 右側滑
|
|
|
48
48
|
|
|
49
49
|
| | Sheet | Dialog |
|
|
50
50
|
|---|---|---|
|
|
51
|
-
| 位置 |
|
|
51
|
+
| 位置 | 畫面右側滑入(消費者 API 僅 `side="right"`;top/bottom/left 為 DS 內部基建) | 畫面居中 |
|
|
52
52
|
| 視覺重量 | 較輕(單邊) | 較重(四周 overlay) |
|
|
53
53
|
| 典型用途 | 側邊工作流程、detail panel | 確認流程、複雜表單 |
|
|
54
54
|
| 阻斷感 | 較弱(使用者視線可繼續掃主頁) | 強(完全聚焦 modal) |
|
|
55
|
-
| 手機體驗 |
|
|
55
|
+
| 手機體驗 | 沿用同一右側 Sheet(mobile 預設占 75% 寬;不借 `side="bottom"`,見「何時用」) | 桌機導向(中央 modal 不符 mobile sheet pattern,浮層遮住主流向) |
|
|
56
56
|
|
|
57
57
|
**判準**:
|
|
58
58
|
- **需要聚焦決策(刪除、確認、複雜表單)→ Dialog**
|
|
@@ -70,7 +70,7 @@ Sheet 是**從畫面邊緣滑入的浮層面板**。**消費者 API = 右側滑
|
|
|
70
70
|
|
|
71
71
|
## Padding SSOT
|
|
72
72
|
|
|
73
|
-
Sheet 的 `SheetHeader` / `
|
|
73
|
+
Sheet 的 `SheetHeader` / `SheetFooter` 消費 `SurfaceHeader` / `SurfaceFooter` primitive;`SheetBody` 用 `<ScrollArea>` wrap + 同一套 overlay-surface padding token(對齊 DialogBody canonical,SSOT 見 `patterns/overlay-surface/overlay-surface.spec.md`「Body overflow canonical」)——padding + 分隔線由 overlay-surface own,Sheet 與 Dialog / Popover 共用,避免 token 漂移。Sheet 特有行為:side variant(`top` / `right` / `bottom` / `left`)決定滑入方向 + height/width 響應式策略,padding 本身對齊 overlay-surface canonical。
|
|
74
74
|
|
|
75
75
|
---
|
|
76
76
|
|
|
@@ -104,8 +104,11 @@ Sheet 為容器,內容由 consumer 決定;focus trap + Escape close + `aria-labe
|
|
|
104
104
|
## 邊界案例
|
|
105
105
|
|
|
106
106
|
- **Disabled**:Sheet 本身無 disabled state(非互動 control,是 surface container);trigger Button 由 consumer 控 disabled。
|
|
107
|
-
- **Loading(panel content loading)**:Sheet 為純容器,不獨立 own loading state。Async body 場景由 consumer 在 body slot 渲 `<Empty icon={<CircularProgress size={48}/>}/>`(對齊 `empty.spec.md:
|
|
107
|
+
- **Loading(panel content loading)**:Sheet 為純容器,不獨立 own loading state。Async body 場景由 consumer 在 body slot 渲 `<Empty icon={<CircularProgress size={48}/>}/>`(對齊 `empty.spec.md:168` loading compose SSOT)或 `<Skeleton>` line-stack 取代 content,不開 / 不關 Sheet 即可。
|
|
108
108
|
- **Empty(no content)**:Sheet 必含 title(`aria-labelledby` 強制要求);body 為空時 consumer 應渲 `<Empty>` placeholder,不渲空白 panel。
|
|
109
|
+
- **Scroll(body 內容超過視口高度)**:`SheetBody` = `<ScrollArea>`(`flex-1 min-h-0`),超高內容在 body 內部捲動,header / footer 固定不動;consumer 不需自寫 `overflow-y-auto`。
|
|
110
|
+
- **誤嵌套降級(nested Sheet)**:禁止事項已禁 nested;若 consumer 不慎嵌套,Radix 的 Esc 與 focus trap 只作用於**最上層** layer(DismissableLayer 只 dismiss highest layer;FocusScope stack 最新 scope active),關閉由上而下逐層。
|
|
111
|
+
- **RTL**:`side` 為物理方向(`right-0` 物理定位),不隨 `dir="rtl"` 自動鏡像。
|
|
109
112
|
- **Dark mode**:overlay-surface SSOT 自動 adapt(`overlay-surface.spec.md`);Sheet 不獨立 own dark token。
|
|
110
113
|
- **Density**:Sheet body density 由 consumer 控(若內含 form / DataTable / Menu 各自有 density 規則);Sheet container 自身不持 density。
|
|
111
114
|
|
|
@@ -137,12 +140,7 @@ Sheet 為容器,內容由 consumer 決定;focus trap + Escape close + `aria-labe
|
|
|
137
140
|
|
|
138
141
|
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
139
142
|
|
|
140
|
-
- `app-shell.spec.md`
|
|
141
|
-
- `density.spec.md`
|
|
142
|
-
|
|
143
|
-
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
144
|
-
|
|
145
|
-
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
146
|
-
|
|
147
143
|
- `accordion.spec.md`
|
|
144
|
+
- `app-shell.spec.md`
|
|
145
|
+
- `dialog.spec.md`
|
|
148
146
|
- `scroll-area.spec.md`
|
|
@@ -25,7 +25,7 @@ export default meta
|
|
|
25
25
|
type Story = StoryObj
|
|
26
26
|
|
|
27
27
|
export const CreateProjectRight: Story = {
|
|
28
|
-
name: '
|
|
28
|
+
name: '建立新專案(右側滑入)',
|
|
29
29
|
render: () => (
|
|
30
30
|
<Sheet>
|
|
31
31
|
<SheetTrigger asChild>
|
|
@@ -73,7 +73,7 @@ export const CreateProjectRight: Story = {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export const EditUserRight: Story = {
|
|
76
|
-
name: '
|
|
76
|
+
name: '編輯成員詳情(右側滑入)',
|
|
77
77
|
render: () => (
|
|
78
78
|
<Sheet>
|
|
79
79
|
<SheetTrigger asChild>
|
|
@@ -18,9 +18,9 @@ import { ScrollArea } from "@/design-system/components/ScrollArea/scroll-area"
|
|
|
18
18
|
*
|
|
19
19
|
* ── 定位(2026-04-21 canonical)──
|
|
20
20
|
* Sheet 給**消費者**用的唯一合法形式 = **右側開啟的 modal**(side="right"),
|
|
21
|
-
* 內部結構跟 `Dialog` 一致:`SheetHeader` / `SheetBody` / `SheetFooter`(
|
|
22
|
-
* `SurfaceHeader` / `
|
|
23
|
-
* 在 `patterns/overlay-surface/`)。side="right" 是 defaultVariants,消費者不傳 side。
|
|
21
|
+
* 內部結構跟 `Dialog` 一致:`SheetHeader` / `SheetBody` / `SheetFooter`(Header / Footer 消費
|
|
22
|
+
* `SurfaceHeader` / `SurfaceFooter` primitive;Body = `ScrollArea` + 內層 padding div,
|
|
23
|
+
* padding token SSOT 在 `patterns/overlay-surface/`)。side="right" 是 defaultVariants,消費者不傳 side。
|
|
24
24
|
*
|
|
25
25
|
* ── 其他 side(top / bottom / left)——**非消費者 API**,內部基建用 ──
|
|
26
26
|
* top / bottom / left 變體保留給 DS 內部基建(例:Sidebar 在小尺寸視口時從 left 滑入)。
|
|
@@ -31,9 +31,10 @@ import { ScrollArea } from "@/design-system/components/ScrollArea/scroll-area"
|
|
|
31
31
|
* - Sheet(side="right")= 側滑 modal,用於「補充資訊 / 多欄位表單 / 編輯 flow」
|
|
32
32
|
* - 兩者 API 結構 1:1 對應,差異只在 side / 動畫 / 初始寬度
|
|
33
33
|
*
|
|
34
|
-
* ── Header /
|
|
34
|
+
* ── Header / Footer 消費 SurfaceXxx SSOT;Body 走 ScrollArea canonical ──
|
|
35
35
|
* 避免 padding 漂移 — Dialog / Popover / Sheet / Coachmark 共用同一套 overlay-surface
|
|
36
|
-
* padding token(px-loose / py-tight),改 overlay-surface.tsx
|
|
36
|
+
* padding token(px-loose / py-tight),改 overlay-surface.tsx 四者自動跟進;
|
|
37
|
+
* SheetBody 同 DialogBody:ScrollArea + 內層 px-loose / pt-tight / pb-bottom(詳 SheetBody comment)。
|
|
37
38
|
*/
|
|
38
39
|
|
|
39
40
|
const Sheet = SheetPrimitive.Root
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
4
|
-
import { LayoutDashboard, Inbox, Users, Settings, Bell } from 'lucide-react'
|
|
4
|
+
import { LayoutDashboard, Inbox, Users, Settings, Bell, Folder, Plus } from 'lucide-react'
|
|
5
5
|
import {
|
|
6
6
|
SidebarProvider,
|
|
7
7
|
SidebarHeader,
|
|
@@ -155,7 +155,7 @@ export const Overview: Story = {
|
|
|
155
155
|
<pre className="text-caption font-mono text-fg-secondary bg-canvas p-4 rounded-md border border-divider leading-relaxed">{`SidebarProvider
|
|
156
156
|
Sidebar
|
|
157
157
|
SidebarHeader ← h-[var(--chrome-header-height)]
|
|
158
|
-
SidebarContent ← flex-1
|
|
158
|
+
SidebarContent ← flex-1 + ScrollArea 捲動
|
|
159
159
|
SidebarGroup ← py-2 + ::before divider
|
|
160
160
|
SidebarGroupLabel ← item-layout row (header mode)
|
|
161
161
|
SidebarGroupContent
|
|
@@ -535,44 +535,53 @@ const CollapsedFrame = ({
|
|
|
535
535
|
// SidebarMenuButton cva 有 variant: { default, meta } 兩個值,本 story 展示 default vs meta 區別
|
|
536
536
|
export const VariantMatrix: Story = {
|
|
537
537
|
name: '變體對照(預設 vs 次要)',
|
|
538
|
+
// 2026-06-11:改用真 SidebarMenuButton 渲染(原為手繪灰塊 mock row,違 production-grade composition fidelity)
|
|
538
539
|
render: () => (
|
|
539
540
|
<div className="flex flex-col gap-6 max-w-md">
|
|
540
541
|
<div className="flex flex-col gap-2">
|
|
541
542
|
<H3>variant="default"(導覽 item)</H3>
|
|
542
|
-
<Desc>正常導覽目的地。文字
|
|
543
|
-
<div className="border border-border rounded-md p-3 bg-surface
|
|
544
|
-
<
|
|
545
|
-
<div className="
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
543
|
+
<Desc>正常導覽目的地。文字 <code>text-fg-secondary</code> + <code>font-medium</code>,參與 single-selection,可 active。</Desc>
|
|
544
|
+
<div className="border border-border rounded-md p-3 bg-surface">
|
|
545
|
+
<SidebarProvider defaultActiveId="dashboard" style={{ minHeight: 'auto' }}>
|
|
546
|
+
<div className="flex flex-col w-full">
|
|
547
|
+
<SidebarMenu>
|
|
548
|
+
<SidebarMenuItem>
|
|
549
|
+
<SidebarMenuButton id="dashboard" startIcon={LayoutDashboard}>Dashboard</SidebarMenuButton>
|
|
550
|
+
</SidebarMenuItem>
|
|
551
|
+
<SidebarMenuItem>
|
|
552
|
+
<SidebarMenuButton id="inbox" startIcon={Inbox}>Inbox</SidebarMenuButton>
|
|
553
|
+
</SidebarMenuItem>
|
|
554
|
+
</SidebarMenu>
|
|
555
|
+
</div>
|
|
556
|
+
</SidebarProvider>
|
|
552
557
|
</div>
|
|
553
558
|
</div>
|
|
554
559
|
|
|
555
560
|
<div className="flex flex-col gap-2">
|
|
556
561
|
<H3>variant="meta"(命令 row,非導覽目的地)</H3>
|
|
557
562
|
<Desc>
|
|
558
|
-
section 底部的命令(「查看更多 / 載入更多 / + 新增專案」)。文字退到
|
|
559
|
-
|
|
563
|
+
section 底部的命令(「查看更多 / 載入更多 / + 新增專案」)。文字退到 <code>text-fg-muted</code> + <code>font-normal</code>,
|
|
564
|
+
視覺重量下沉。<strong>不參與 single-selection</strong>(誤傳 isActive 也不啟動)。對齊 Linear「Show N more」/ Notion「Show more」/ Slack「Show more」/ Gmail Labels「More」共識。
|
|
560
565
|
</Desc>
|
|
561
|
-
<div className="border border-border rounded-md p-3 bg-surface
|
|
562
|
-
<
|
|
563
|
-
<div className="
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
566
|
+
<div className="border border-border rounded-md p-3 bg-surface">
|
|
567
|
+
<SidebarProvider style={{ minHeight: 'auto' }}>
|
|
568
|
+
<div className="flex flex-col w-full">
|
|
569
|
+
<SidebarMenu>
|
|
570
|
+
<SidebarMenuItem>
|
|
571
|
+
<SidebarMenuButton id="checkout" startIcon={Folder}>Checkout Revamp</SidebarMenuButton>
|
|
572
|
+
</SidebarMenuItem>
|
|
573
|
+
<SidebarMenuItem>
|
|
574
|
+
<SidebarMenuButton id="billing" startIcon={Folder}>Billing Migration</SidebarMenuButton>
|
|
575
|
+
</SidebarMenuItem>
|
|
576
|
+
<SidebarMenuItem>
|
|
577
|
+
<SidebarMenuButton variant="meta" startIcon={Plus}>新增專案</SidebarMenuButton>
|
|
578
|
+
</SidebarMenuItem>
|
|
579
|
+
<SidebarMenuItem>
|
|
580
|
+
<SidebarMenuButton variant="meta">查看更多</SidebarMenuButton>
|
|
581
|
+
</SidebarMenuItem>
|
|
582
|
+
</SidebarMenu>
|
|
583
|
+
</div>
|
|
584
|
+
</SidebarProvider>
|
|
576
585
|
</div>
|
|
577
586
|
</div>
|
|
578
587
|
</div>
|
|
@@ -586,7 +595,7 @@ export const StateBehavior: Story = {
|
|
|
586
595
|
<div className="flex flex-col gap-1">
|
|
587
596
|
<H3>狀態行為</H3>
|
|
588
597
|
<Desc>
|
|
589
|
-
Sidebar 層級特有的狀態:collapse / expand 三種模式、mobile offcanvas、active item
|
|
598
|
+
Sidebar 層級特有的狀態:collapse / expand 三種模式、mobile offcanvas、active item single-selection、open state cookie 持久化。
|
|
590
599
|
Item-level default / hover / active / selected / disabled **色彩**由 `ColorMatrix` 作為 state-driven 矩陣完整呈現(共用 item-anatomy row primitive 主檔);本 story 展示 container 層的結構狀態切換。
|
|
591
600
|
</Desc>
|
|
592
601
|
</div>
|
|
@@ -608,7 +617,7 @@ export const StateBehavior: Story = {
|
|
|
608
617
|
<div className="flex flex-col gap-3">
|
|
609
618
|
<span className="text-caption font-medium text-fg-secondary">行為 2:Cmd+B / SidebarTrigger 切換 open state</span>
|
|
610
619
|
<Desc>
|
|
611
|
-
SidebarProvider 內建 Cmd+B (Mac) / Ctrl+B (Win) 全域快捷鍵,同時 SidebarTrigger iconOnly Button 作為視覺 toggle。open state 寫入 cookie(7 天)
|
|
620
|
+
SidebarProvider 內建 Cmd+B (Mac) / Ctrl+B (Win) 全域快捷鍵,同時 SidebarTrigger iconOnly Button 作為視覺 toggle。open state 寫入 cookie(7 天);跨 session 還原需 consumer 讀 cookie 後傳 defaultOpen(詳 spec「持久化與快捷鍵」)。
|
|
612
621
|
</Desc>
|
|
613
622
|
<div className="border border-divider rounded-lg overflow-hidden bg-surface" style={{ width: 480, height: 280 }}>
|
|
614
623
|
<SidebarProvider style={{ minHeight: 'auto', height: '100%' }}>
|
|
@@ -668,7 +677,7 @@ export const StateBehavior: Story = {
|
|
|
668
677
|
<span className="text-caption font-medium text-fg-secondary">行為規則</span>
|
|
669
678
|
<ul className="text-caption text-fg-secondary space-y-1.5 ml-4 list-disc">
|
|
670
679
|
<li>`collapsible="offcanvas"` 用於主內容為主的 app(sidebar 是啟動器,使用者常關);`collapsible="icon"` 用於深度導覽 app(sidebar 是常駐工作區)。</li>
|
|
671
|
-
<li>open state 寫 cookie `sidebar_state`(7 天 max-age)
|
|
680
|
+
<li>open state 寫 cookie `sidebar_state`(7 天 max-age);Provider 只寫不讀,還原由 consumer 讀 cookie 傳 `defaultOpen`(避免 SSR hydration flash)。</li>
|
|
672
681
|
<li>Mobile(<768px)一律走 Sheet overlay,不受 `collapsible` prop 影響——小螢幕 sidebar 永遠不佔固定空間。</li>
|
|
673
682
|
<li>Icon mode 下 active item 的 `bg-neutral-selected` 仍然顯示,但 label 不可見——提供最小視覺指引讓使用者知道「當前在哪」。</li>
|
|
674
683
|
<li>Cmd+B / Ctrl+B 全域快捷鍵由 SidebarProvider 監聽,任何 focus 位置都可觸發——目前未排除文字輸入框,在 input / textarea 內按下仍會 toggle 並攔掉預設行為(無 disableShortcut opt-out)。</li>
|
|
@@ -757,7 +766,7 @@ export const Accessibility = {
|
|
|
757
766
|
render: () => (
|
|
758
767
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
759
768
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
760
|
-
<p className="whitespace-pre-line">{"- 收合切換鍵:Cmd+B(Mac)/ Ctrl+B(Windows)是業界慣例(VS Code / Linear / shadcn 都用),Sidebar 內建並會攔下這組鍵,避免穿透到瀏覽器書籤列。任何焦點位置都能觸發;目前未排除文字輸入框——在 input / textarea 內按下仍會 toggle(無 disableShortcut opt-out)。\n\n- 收合按鈕:SidebarTrigger
|
|
769
|
+
<p className="whitespace-pre-line">{"- 收合切換鍵:Cmd+B(Mac)/ Ctrl+B(Windows)是業界慣例(VS Code / Linear / shadcn 都用),Sidebar 內建並會攔下這組鍵,避免穿透到瀏覽器書籤列。任何焦點位置都能觸發;目前未排除文字輸入框——在 input / textarea 內按下仍會 toggle(無 disableShortcut opt-out)。\n\n- 收合按鈕:SidebarTrigger 內建 aria-label「Toggle Sidebar」,讓螢幕報讀使用者知道按鈕用途;consumer 可傳 aria-label 覆寫(i18n)。SidebarGroupLabel 的收合 chevron 另有 toggleAriaLabel prop(預設「展開或收合」)。\n\n- 當前項目:選中的 menu item 帶 data-active,呈現選取底色(bg-neutral-selected)作為視覺指引;即使收合成 icon-only 模式,選取底色仍然保留,使用者一眼知道現在在哪一頁。\n\n- 手機尺寸:768px 以下自動切換成從旁滑出的抽屜(Sheet),內建焦點鎖定、Esc 關閉、關閉後焦點回到觸發按鈕。"}</p>
|
|
761
770
|
</div>
|
|
762
771
|
),
|
|
763
772
|
}
|
|
@@ -144,16 +144,16 @@ export const UsageGuidance: Story = {
|
|
|
144
144
|
<p>適合 Sidebar 的真實業務場景(點擊跳轉「展示」頁範例):</p>
|
|
145
145
|
<ul className="space-y-1">
|
|
146
146
|
<li>
|
|
147
|
-
<LinkTo kind="Design System/Components/Sidebar/展示" name="完整佈局"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
147
|
+
<LinkTo kind="Design System/Components/Sidebar/展示" name="完整佈局"><span className="text-primary hover:underline font-medium cursor-pointer">Linear 式議題追蹤主導覽(完整佈局)</span></LinkTo>
|
|
148
148
|
</li>
|
|
149
149
|
<li>
|
|
150
|
-
<LinkTo kind="Design System/Components/Sidebar/展示" name="混合內容"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
150
|
+
<LinkTo kind="Design System/Components/Sidebar/展示" name="混合內容"><span className="text-primary hover:underline font-medium cursor-pointer">專案導覽混排群組、徽章與操作(混合內容)</span></LinkTo>
|
|
151
151
|
</li>
|
|
152
152
|
<li>
|
|
153
|
-
<LinkTo kind="Design System/Components/Sidebar/展示" name="抽屜收合(離畫面外)"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
153
|
+
<LinkTo kind="Design System/Components/Sidebar/展示" name="抽屜收合(離畫面外)"><span className="text-primary hover:underline font-medium cursor-pointer">側欄整條滑出畫面外的內容優先工作區(抽屜收合)</span></LinkTo>
|
|
154
154
|
</li>
|
|
155
155
|
<li>
|
|
156
|
-
<LinkTo kind="Design System/Components/Sidebar/展示" name="混合前綴"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
156
|
+
<LinkTo kind="Design System/Components/Sidebar/展示" name="混合前綴"><span className="text-primary hover:underline font-medium cursor-pointer">icon 導覽與 GitHub / Slack / Figma 整合並列對齊(混合前綴)</span></LinkTo>
|
|
157
157
|
</li>
|
|
158
158
|
</ul>
|
|
159
159
|
<p className="text-fg-muted mt-3">判斷不確定時:對照下方「何時不用 / 替代元件」清單;若情境不屬於垂直持久導覽,改用對應的近親元件。</p>
|
|
@@ -37,7 +37,7 @@ benchmark:
|
|
|
37
37
|
# Sidebar 設計原則
|
|
38
38
|
|
|
39
39
|
> **Foundational SSOT rationale**(2026-04-24 approved,cap 800):
|
|
40
|
-
> Sidebar 有獨立 `sidebarMenuButtonVariants` cva(對齊 MenuItem 但獨立實作,同步風險見 item-anatomy.spec「SidebarMenuButton 獨立實作風險」)+ 20+ Sidebar-specific features SSOT(Chrome header/footer 高度 / Collapsible / Icon 模式 / SidebarTrigger 位置 / Mobile 行為 / 持久化 / 快捷鍵 / Group 收合 / Single selection / Inline actions / Keyboard shortcuts),scope > 單一 MenuItem consumer。
|
|
40
|
+
> Sidebar 有獨立 `sidebarMenuButtonVariants` cva(對齊 MenuItem 但獨立實作,同步風險見 item-anatomy.spec「SidebarMenuButton 獨立實作風險」)+ 20+ Sidebar-specific features SSOT(Chrome header/footer 高度 / Collapsible / Icon 模式 / SidebarTrigger 位置 / Mobile 行為 / 持久化 / 快捷鍵 / Group 收合 / Single selection / Inline actions / Keyboard shortcuts),scope > 單一 MenuItem consumer。Full cva consume 提案經二次評估 declined(2026-04-24,詳 `.claude/planning/row-primitive-consolidation.md.rejected.20260424.md`)— ROW_PADDING_BY_SIZE token SSOT 已是 practical best。
|
|
41
41
|
|
|
42
42
|
## 定位
|
|
43
43
|
|
|
@@ -89,7 +89,7 @@ SidebarProvider ← 全域 context(open 狀態、cookie、快捷
|
|
|
89
89
|
│
|
|
90
90
|
└─ TreeView 階層樹(user data、任意深度)
|
|
91
91
|
SidebarFooter ← 底部:user menu、settings 觸發器
|
|
92
|
-
SidebarTrigger ← 展開 /
|
|
92
|
+
SidebarTrigger ← 展開 / 收合按鈕(放 sidebar 外,詳「SidebarTrigger 位置」段)
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
**不使用 shadcn 原版的 `SidebarMenuSub` / `SidebarMenuSubItem`**——見下方內容形態規則。
|
|
@@ -239,7 +239,7 @@ Gmail / Linear 的標準版型:上方 SidebarGroup 放扁平主導覽(Sideba
|
|
|
239
239
|
|
|
240
240
|
放在 SidebarHeader / SidebarFooter 裡的元件必須能容納在這個高度內:
|
|
241
241
|
|
|
242
|
-
- Avatar: `size={24}` —— **chrome header avatar canonical(density-fixed / row-size-fixed)**。consumer 用 **raw `<Avatar size={24}>`**(chrome header 不是 row context → 不該用 `<ItemAvatar>`)。對應 CSS local token `--chrome-header-avatar-size: 1.5rem`(`header-canonical.css`),sidebar 收合對齊公式消費此 token。詳 `header-canonical.spec.md`「4.5 Chrome header avatar SSOT」段 + `item-anatomy.spec.md
|
|
242
|
+
- Avatar: `size={24}` —— **chrome header avatar canonical(density-fixed / row-size-fixed)**。consumer 用 **raw `<Avatar size={24}>`**(chrome header 不是 row context → 不該用 `<ItemAvatar>`)。對應 CSS local token `--chrome-header-avatar-size: 1.5rem`(`header-canonical.css`),sidebar 收合對齊公式消費此 token。詳 `header-canonical.spec.md`「4.5 Chrome header avatar SSOT」段 + `item-anatomy.spec.md`「Scope 例外:Chrome header 不是 row context」段。
|
|
243
243
|
- Button: `size="sm"` 或 `size="md"`
|
|
244
244
|
- 單排 title 文字 + icon button
|
|
245
245
|
|
|
@@ -543,7 +543,7 @@ Consumer 不需要任何額外 code——只要加一個 prop:
|
|
|
543
543
|
|
|
544
544
|
`<SidebarMenuButton inlineActions={[...]}>` 支援 suffix 放置 inline action button,搭配 `actionsReveal="hover"` 做 TreeView 風格的 hover-reveal。
|
|
545
545
|
|
|
546
|
-
**宣告式 API**,完全對齊 `
|
|
546
|
+
**宣告式 API**,完全對齊 `patterns/element-anatomy/inline-action.spec.md`(Inline Action SSOT):
|
|
547
547
|
|
|
548
548
|
```tsx
|
|
549
549
|
<SidebarMenuButton
|
|
@@ -565,20 +565,20 @@ Consumer 不需要任何額外 code——只要加一個 prop:
|
|
|
565
565
|
- 處理 Tooltip / `aria-label` / `cursor-pointer`(宣告式 config 自動帶)
|
|
566
566
|
- 計算 button 的 `paddingRight`(host 用 `N×icon + (N-1)×gap + loose + gap` 公式自動算)
|
|
567
567
|
|
|
568
|
-
**規格**(完全繼承
|
|
568
|
+
**規格**(完全繼承 `inline-action.spec.md`):
|
|
569
569
|
|
|
570
570
|
| 項目 | 值 |
|
|
571
571
|
|---|---|
|
|
572
572
|
| Icon 尺寸 | `ICON_SIZE[size]`(16/16/20) |
|
|
573
573
|
| Hover bg 尺寸 | icon + 2(18/18/22) |
|
|
574
|
-
| Hover bg 圓角 | `rounded-md`
|
|
574
|
+
| Hover bg 圓角 | `rounded-md`(全尺寸一致) |
|
|
575
575
|
| Icon 顏色 | `fg-muted` → `foreground` on hover/active |
|
|
576
576
|
| 多個 action 間距 | `gap-2`(8px) |
|
|
577
577
|
| 出現時機 | 預設永遠顯示;`actionsReveal="hover"` → row hover/focus 才淡入 |
|
|
578
578
|
| Icon 模式 | 整個 suffix 隱藏 |
|
|
579
579
|
| Host disabled 時 | 不渲染(遵守宿主 disabled 規則) |
|
|
580
580
|
|
|
581
|
-
**Canonical 實作**:`ItemInlineAction` + `ItemSuffix`(`item-
|
|
581
|
+
**Canonical 實作**:`ItemInlineAction` + `ItemSuffix`(`item-anatomy.tsx`)。未來 DropdownMenuItem / TreeItem / Field / Tag 都應逐步遷移到這個共用元件,消除「每個 host 各自複製 18 行 JSX」的技術債——見 `inline-action.spec.md`(Inline Action SSOT)。
|
|
582
582
|
|
|
583
583
|
**何時用**:
|
|
584
584
|
- ✅ Favorites / Bookmarks 類 user data item 的 hover-reveal 「⋯」/「×」
|
|
@@ -618,6 +618,14 @@ Sheet 開啟狀態**不持久化**。
|
|
|
618
618
|
|
|
619
619
|
---
|
|
620
620
|
|
|
621
|
+
## 常見誤解
|
|
622
|
+
|
|
623
|
+
- 「SidebarMenuSub 可做第 2 層選單」——本 DS 不 export;深度 > 1 一律 TreeView(見「內容形態選擇」)
|
|
624
|
+
- 「Settings 子頁要佔 sidebar 位置」——走 in-page secondary nav / user menu modal(見「Settings 這類有子頁的頁面」)
|
|
625
|
+
- 「點 icon 可順便展開 sidebar」——行為不可預測;重新看階層資料的唯一路徑 = 展開 sidebar(見「Icon 模式的行為規則」)
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
621
629
|
## 禁止事項
|
|
622
630
|
|
|
623
631
|
- ❌ **使用 SidebarMenuSub / 讓 SidebarMenu 超過 1 層**——用 TreeView 或 in-page secondary nav
|
|
@@ -644,7 +652,7 @@ Sheet 開啟狀態**不持久化**。
|
|
|
644
652
|
## 判斷決策樹
|
|
645
653
|
|
|
646
654
|
```
|
|
647
|
-
Variant
|
|
655
|
+
Variant:目前僅 sidebar(floating 刻意不做 / inset 規劃中未實作,見「Variant」段)
|
|
648
656
|
|
|
649
657
|
Collapsible:內容優先低頻導覽 → offcanvas;扁平高頻切換 → icon;超簡單 → none
|
|
650
658
|
|
|
@@ -681,11 +689,11 @@ Item-level default / hover / selected / disabled **色彩**完全共用 item-ana
|
|
|
681
689
|
|
|
682
690
|
## 邊界案例
|
|
683
691
|
|
|
684
|
-
- **Disabled item**:SidebarMenuButton
|
|
692
|
+
- **Disabled item**:SidebarMenuButton `disabled` prop 走 native button disabled(`text-fg-disabled` + 不觸發 onClick + 不可聚焦,鍵盤導覽自動 skip);**不自動設 `aria-disabled`**——cva 另備 `aria-disabled:` 樣式,consumer 自傳 `aria-disabled`(如 asChild 非 button host)時同樣式生效。
|
|
685
693
|
- **Loading(nav data-fetch)**:async nav tree fetch 時 consumer 應在對應 group 內渲 `<Skeleton>` line-stack(常見 3-5 條 sidebar nav skeleton 行)而非 Empty + spinner — Sidebar 是 chrome 不是 panel,loading 用 skeleton 更符合 chrome 持續存在的 affordance。對齊 Atlassian Sidebar / VS Code activity-bar idiom。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
686
694
|
- **Empty(no nav items)**:罕見場景(用戶無權限 / 全空 workspace)。若整個 group 無 item,consumer 應 conditional 不渲該 group(不渲空 group label);若整個 sidebar 無 item,可能該 hide sidebar(走 layout context 不渲)。不渲空白 sidebar。
|
|
687
695
|
- **Dark mode / density**:Sidebar 為 chrome surface,走 chrome-header token 自動 adapt;density 預設 lock 跟隨 app density chrome token,不獨立 own。
|
|
688
|
-
- **Collapsed mode(icon-only)
|
|
696
|
+
- **Collapsed mode(icon-only)**:label / inline actions suffix 隱藏,只留 icon + tooltip;TreeView 整區隱藏,重新看階層資料的唯一路徑 = 展開 sidebar(完整規則見「Icon 模式的行為規則」段)。
|
|
689
697
|
|
|
690
698
|
---
|
|
691
699
|
|
|
@@ -695,17 +703,14 @@ Item-level default / hover / selected / disabled **色彩**完全共用 item-ana
|
|
|
695
703
|
- `../DropdownMenu/dropdown-menu.spec.md` — Header / Footer 常用的下拉選單
|
|
696
704
|
- `../Tabs/tabs.spec.md` — in-page secondary nav(不塞 sidebar 的子頁切換)
|
|
697
705
|
- `../Menu/menu-item.spec.md` — SidebarMenuButton 的 item-layout 共用規則
|
|
698
|
-
- Command
|
|
699
|
-
- Sheet
|
|
706
|
+
- `../Command/command.spec.md` — Command palette,icon 模式下的跳轉逃生艙
|
|
707
|
+
- `../Sheet/sheet.spec.md` — Sheet,暫時性側邊面板的替代(mobile 模式實作基礎,詳「A11y 預設」)
|
|
700
708
|
|
|
701
709
|
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
702
710
|
|
|
703
711
|
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
704
712
|
|
|
705
713
|
- `app-shell.spec.md`
|
|
706
|
-
|
|
707
|
-
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
708
|
-
|
|
709
|
-
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
710
|
-
|
|
711
714
|
- `scroll-area.spec.md`
|
|
715
|
+
- `sheet.spec.md`
|
|
716
|
+
- `tree-view.spec.md`
|
|
@@ -324,6 +324,22 @@ export const MixedContent: Story = {
|
|
|
324
324
|
</SidebarMenuButton>
|
|
325
325
|
</SidebarMenuItem>
|
|
326
326
|
))}
|
|
327
|
+
{/* Disabled favorite(已封存專案):host disabled 時 inline actions
|
|
328
|
+
整組不渲染——hover 也不出現 ⋯/+,不可操作就不暗示可操作
|
|
329
|
+
(sidebar.spec.md「Host disabled 時」+ inline-action.spec.md 宿主 disabled 規則)。 */}
|
|
330
|
+
<SidebarMenuItem>
|
|
331
|
+
<SidebarMenuButton
|
|
332
|
+
startIcon={Folder}
|
|
333
|
+
disabled
|
|
334
|
+
actionsReveal="hover"
|
|
335
|
+
inlineActions={[
|
|
336
|
+
{ icon: MoreVertical, label: '更多動作', onClick: () => {} },
|
|
337
|
+
{ icon: Plus, label: '新增', onClick: () => {} },
|
|
338
|
+
]}
|
|
339
|
+
>
|
|
340
|
+
delta(已封存)
|
|
341
|
+
</SidebarMenuButton>
|
|
342
|
+
</SidebarMenuItem>
|
|
327
343
|
</SidebarMenu>
|
|
328
344
|
</SidebarGroupContent>
|
|
329
345
|
</SidebarGroup>
|
|
@@ -257,7 +257,7 @@ const SidebarProvider = React.forwardRef<
|
|
|
257
257
|
style={wrapperStyle}
|
|
258
258
|
className={cn(
|
|
259
259
|
"group/sidebar-wrapper flex min-h-svh w-full",
|
|
260
|
-
// CSS :has() 偵測 — 只在 uniformPrefix=true(
|
|
260
|
+
// CSS :has() 偵測 — 只在 uniformPrefix=true(opt-in,預設 false;見 sidebar.spec.md「Sidebar 全域 prefix 對齊」)時掛
|
|
261
261
|
// mixing detected → 同時把 --item-icon-size cascade 到 slot 寬(`!` important 蓋
|
|
262
262
|
// 過 wrapperStyle inline,讓 collapsed pl 公式知道「ItemPrefix wrapper 被撐到
|
|
263
263
|
// 24,effective prefix width = 24 非 16」)。
|
|
@@ -731,7 +731,7 @@ const SidebarGroupLabel = React.forwardRef<
|
|
|
731
731
|
|
|
732
732
|
// Collapsible group:label 本身仍是 plain header(保留原本語意),
|
|
733
733
|
// chevron 是 suffix slot 裡的 inline action button,用 Radix Collapsible.Trigger asChild
|
|
734
|
-
// 包住 `ItemInlineActionButton`——視覺規格完全對齊
|
|
734
|
+
// 包住 `ItemInlineActionButton`——視覺規格完全對齊 patterns/element-anatomy/inline-action.spec.md(Inline Action SSOT),
|
|
735
735
|
// 跟 SidebarMenuButton 的 suffix inline action 同一套 canonical 實作。
|
|
736
736
|
//
|
|
737
737
|
// **為什麼 chevron 是 inline action 而非整個 label 是 trigger**:
|
|
@@ -814,9 +814,10 @@ SidebarGroupAction.displayName = "SidebarGroupAction"
|
|
|
814
814
|
|
|
815
815
|
// SidebarMenu — items 容器
|
|
816
816
|
//
|
|
817
|
-
// Prefix 對齊由 `SidebarProvider`
|
|
818
|
-
//
|
|
819
|
-
//
|
|
817
|
+
// Prefix 對齊由 `SidebarProvider` 的 `uniformPrefix`(opt-in,預設 false)全域處理(school B,
|
|
818
|
+
// Notion/Linear 慣例):開啟後,整個 sidebar 子樹同時存在 icon 和 avatar prefix 時,自動套用
|
|
819
|
+
// 固定槽,跨 menu 跨 group 對齊。要啟用,在 `<SidebarProvider uniformPrefix>` 全域 opt-in
|
|
820
|
+
// (explicit > implicit,見 sidebar.spec.md「Sidebar 全域 prefix 對齊」段)。SidebarMenu 沒有
|
|
820
821
|
// per-menu 覆寫——沒有真實 use case,YAGNI。
|
|
821
822
|
const SidebarMenu = React.forwardRef<
|
|
822
823
|
HTMLUListElement,
|
|
@@ -958,7 +959,7 @@ const SidebarMenuButton = React.forwardRef<
|
|
|
958
959
|
startIcon?: LucideIcon
|
|
959
960
|
tooltip?: string | React.ComponentProps<typeof TooltipContent>
|
|
960
961
|
/**
|
|
961
|
-
* Suffix slot 的 inline actions(宣告式 API,對齊
|
|
962
|
+
* Suffix slot 的 inline actions(宣告式 API,對齊 patterns/element-anatomy/inline-action.spec.md)。
|
|
962
963
|
* Host 自動用 `<ItemInlineAction>` 渲染,consumer 只宣告 intent。
|
|
963
964
|
* Icon 模式下自動隱藏。
|
|
964
965
|
*/
|
|
@@ -1046,7 +1047,14 @@ const SidebarMenuButton = React.forwardRef<
|
|
|
1046
1047
|
)
|
|
1047
1048
|
|
|
1048
1049
|
const hasSlot = !!inlineActionsSlot
|
|
1049
|
-
|
|
1050
|
+
// Host disabled 時 inline actions(config + slot)整段不渲染,paddingRight 預留一併取消
|
|
1051
|
+
// (inline-action.spec.md「宿主 disabled 時不渲染」+ sidebar.spec.md「Host disabled 時|不渲染」)。
|
|
1052
|
+
// 必須 render 層 guard:suffix 跟 button 是 sibling(避免巢狀 button),
|
|
1053
|
+
// native disabled 的 pointer-events-none 蓋不到 sibling,CSS 層無從繼承。
|
|
1054
|
+
// aria-disabled 同步 guard——對齊 cva `aria-disabled:` 樣式支線(asChild 非 button host 自傳)。
|
|
1055
|
+
const isDisabled =
|
|
1056
|
+
!!props.disabled || props["aria-disabled"] === true || props["aria-disabled"] === "true"
|
|
1057
|
+
const hasActions = !isDisabled && (hasSlot || (!!inlineActions && inlineActions.length > 0))
|
|
1050
1058
|
|
|
1051
1059
|
// 計算 suffix 所佔寬度:N×icon + (N-1)×gap-2(8px),再加 gap-2 跟 label 之間的間隔
|
|
1052
1060
|
// Slot mode 預設按 1 icon 預留(consumer 寬度自控)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// variant prop。形狀 / 尺寸完全由 consumer 的 className 決定;色彩透過
|
|
5
5
|
// bg-muted 從 theme 繼承(2026-05-20 修 drift,實際 skeleton.tsx:10 用 bg-muted);
|
|
6
6
|
// loading 是唯一狀態(無 hover / focus / active)。
|
|
7
|
-
//
|
|
7
|
+
// 本檔保留 Overview + CommonShapes + DesignPrinciple + Accessibility 四個 story。
|
|
8
8
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
9
9
|
import { Skeleton } from './skeleton'
|
|
10
10
|
import { H3, Desc } from '@/design-system/stories-helpers/anatomy/anatomy-utils'
|
|
@@ -14,7 +14,7 @@ import { H3, Desc } from '@/design-system/stories-helpers/anatomy/anatomy-utils'
|
|
|
14
14
|
* **刻意沒有 size / color / variant**。形狀 / 尺寸完全由 consumer 的 className
|
|
15
15
|
* (Tailwind utilities)決定。底色固定用 `bg-muted`,深淺模式由主題色自動切換。
|
|
16
16
|
*
|
|
17
|
-
* 因此本 spec 只有 Overview + 常見形狀 +
|
|
17
|
+
* 因此本 spec 只有 Overview + 常見形狀 + 設計原則 + 無障礙四個 story,沒有 SizeMatrix /
|
|
18
18
|
* ColorMatrix / StateMatrix——這些概念對 Skeleton 不適用。
|
|
19
19
|
*/
|
|
20
20
|
|
|
@@ -48,7 +48,7 @@ export const UsageGuidance: Story = {
|
|
|
48
48
|
<p>適合 Skeleton 的真實業務場景(點擊跳轉「展示」頁範例):</p>
|
|
49
49
|
<ul className="space-y-1">
|
|
50
50
|
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="個人資料卡載入"><span className="text-primary hover:underline font-medium cursor-pointer">個人資料卡載入</span></LinkTo></li>
|
|
51
|
-
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="任務列表載入"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
51
|
+
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="任務列表載入"><span className="text-primary hover:underline font-medium cursor-pointer">任務列表載入</span></LinkTo></li>
|
|
52
52
|
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="表格列載入"><span className="text-primary hover:underline font-medium cursor-pointer">表格列載入</span></LinkTo></li>
|
|
53
53
|
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="文件載入"><span className="text-primary hover:underline font-medium cursor-pointer">文件載入</span></LinkTo></li>
|
|
54
54
|
<li><LinkTo kind="Design System/Components/Skeleton/展示" name="卡片網格載入"><span className="text-primary hover:underline font-medium cursor-pointer">卡片網格載入</span></LinkTo></li>
|
|
@@ -151,14 +151,27 @@ export const ShapeMatchRule: Story = {
|
|
|
151
151
|
title="✅ 形狀模擬最終內容"
|
|
152
152
|
note="avatar 圓形對應圓形頭像、text 行寬度對應真實文字長度、title 高度對應標題字級。資料回來後使用者不會感到「跳版」"
|
|
153
153
|
>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<div className="flex
|
|
157
|
-
<Skeleton className="h-
|
|
158
|
-
<
|
|
154
|
+
{/* 2026-06-11:改為「載入中 vs 載入完成」對照(原單卡 demo 與使用指引「vs 近親元件」段重複)。 */}
|
|
155
|
+
<div className="flex flex-col gap-2">
|
|
156
|
+
<div className="flex items-center gap-3 border border-border rounded-lg p-3 w-72">
|
|
157
|
+
<Skeleton className="h-10 w-10 rounded-full" />
|
|
158
|
+
<div className="flex flex-col gap-2 flex-1">
|
|
159
|
+
<Skeleton className="h-4 w-32" />
|
|
160
|
+
<Skeleton className="h-3 w-48" />
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
<Label>載入中 — 圓形對應頭像、兩行對應名字 + 最新訊息</Label>
|
|
164
|
+
</div>
|
|
165
|
+
<div className="flex flex-col gap-2">
|
|
166
|
+
<div className="flex items-center gap-3 border border-border rounded-lg p-3 w-72">
|
|
167
|
+
<div className="flex items-center justify-center h-10 w-10 rounded-full bg-primary text-on-emphasis text-body font-medium shrink-0">林</div>
|
|
168
|
+
<div className="flex flex-col gap-0.5 flex-1 min-w-0">
|
|
169
|
+
<span className="text-body font-medium">林雅婷</span>
|
|
170
|
+
<span className="text-caption text-fg-secondary truncate">已傳送設計稿連結,請查收</span>
|
|
171
|
+
</div>
|
|
159
172
|
</div>
|
|
173
|
+
<Label>載入完成 — 形狀一一對應,版面不跳動(Slack DM 列表)</Label>
|
|
160
174
|
</div>
|
|
161
|
-
<Label>圓形 avatar、兩行文字寬度遞減 — 符合 Slack DM 列表</Label>
|
|
162
175
|
</Rule>
|
|
163
176
|
|
|
164
177
|
<Rule
|
|
@@ -54,6 +54,7 @@ Skeleton 是**載入中的內容佔位符**——在資料載入完成前,用
|
|
|
54
54
|
**判準**:
|
|
55
55
|
- **有已知佈局結構需保留 → Skeleton**(佔位、防跳動)
|
|
56
56
|
- **小區塊 / inline 等待 → CircularProgress**(無 value,indeterminate)
|
|
57
|
+
- **長載入換手**(先 Skeleton、超時換 progress):> 3s 的 fallback 規則見「A11y 預設」「替代文字」段
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
@@ -62,7 +63,7 @@ Skeleton 是**載入中的內容佔位符**——在資料載入完成前,用
|
|
|
62
63
|
- ❌ 用 Skeleton 取代 Empty(確定沒有資料的空狀態)——語意不同
|
|
63
64
|
- ❌ 用 Skeleton 取代 error state——錯誤需要明確提示 + 解決路徑
|
|
64
65
|
- ❌ Skeleton 形狀嚴重偏離真實內容——會讓使用者預期被打破、體感更慢
|
|
65
|
-
- ❌ 長時間(> 10s)的 loading 一直用 Skeleton——使用者會懷疑是否卡住,需改用 progress indicator
|
|
66
|
+
- ❌ 長時間(> 10s)的 loading 一直用 Skeleton——使用者會懷疑是否卡住,需改用 progress indicator 或說明文字(10s = 硬性上限;> 3s 起即建議換手,見「A11y 預設」「替代文字」段)
|
|
66
67
|
|
|
67
68
|
---
|
|
68
69
|
|
|
@@ -71,11 +72,11 @@ Skeleton 是**載入中的內容佔位符**——在資料載入完成前,用
|
|
|
71
72
|
Skeleton 是 pure passive primitive(占位用的 opacity-pulse div),刻意無變體:
|
|
72
73
|
|
|
73
74
|
- **無 Inspector**:Skeleton 唯一變因是「形狀」(w / h / rounded),由 consumer 透過 className 決定。互動 Inspector 無 prop 可調——該討論的是「怎麼畫出符合實際內容的形狀」,由 `CommonShapes` story 覆蓋。
|
|
74
|
-
- **無 ColorMatrix**:Skeleton 底色固定為 `bg-muted`(
|
|
75
|
+
- **無 ColorMatrix**:Skeleton 底色固定為 `bg-muted`(對齊 `color.spec.md`「Static Subtle」段「placeholder / 退化」原則;2026-05-20 修正歷史 drift `bg-secondary`)。Dark mode 自動由 semantic token 處理,加 color variant 會誤導成狀態變化(Skeleton 是 loading 中,不該有語意色)。
|
|
75
76
|
- **無 SizeMatrix**:Skeleton 無 size prop,尺寸完全由 consumer className(`w-32 h-4`)或 parent 決定——因為它要精確模擬內容形狀,不能限制成 sm/md/lg tier。
|
|
76
77
|
- **無 StateBehavior**:Skeleton 只有「顯示 / 不顯示」兩態(consumer unmount 即消失),無 hover / focus / active / selected / disabled——非互動元件。
|
|
77
78
|
|
|
78
|
-
對應 anatomy story:保留 `Overview` + 元件特有 `CommonShapes`(避免漂移的標準形狀庫)
|
|
79
|
+
對應 anatomy story:保留 `Overview` + 元件特有 `CommonShapes`(避免漂移的標準形狀庫)+ `DesignPrinciple`(與 CircularProgress 的分界)+ `Accessibility`(2026-05-17 加)。
|
|
79
80
|
|
|
80
81
|
---
|
|
81
82
|
|
|
@@ -87,7 +88,7 @@ Skeleton 是**純視覺 loading placeholder**,預設 ARIA 行為:
|
|
|
87
88
|
- **`aria-busy="true"` 由 consumer 容器 own**:loading region 的容器(如 DataTable / Card / Sidebar group)應設 `aria-busy="true"`,告知 SR「該區域 loading 中」;data ready 後 consumer 移除 `aria-busy` 同時 unmount Skeleton
|
|
88
89
|
- **不取得 focus**:Skeleton 永遠 non-interactive,無鍵盤行為
|
|
89
90
|
- **動畫**:`prefers-reduced-motion: reduce` 用戶自動 stop pulse 動畫(`skeleton.tsx:10` 的 `motion-reduce:animate-none`)。pulse 是自動播放的循環動畫,歸 WCAG 2.2.2 Pause, Stop, Hide(Level A);honor `prefers-reduced-motion` 即滿足。注意非 2.3.3 Animation from Interactions(該 SC 是 Level AAA,僅涵蓋由互動 / 捲動觸發的位移動畫,不適用 auto-play loop)
|
|
90
|
-
- **替代文字**:長時間 loading(>3s)consumer 應 fallback 為 `<Empty icon={<CircularProgress/>} description="載入中..." />`(SR-friendly text)— Skeleton 適合 < 3s 短暫 placeholder
|
|
91
|
+
- **替代文字**:長時間 loading(>3s)consumer 應 fallback 為 `<Empty icon={<CircularProgress/>} description="載入中..." />`(SR-friendly text)— Skeleton 適合 < 3s 短暫 placeholder(3s 為建議換手值;> 10s 仍用 Skeleton 屬「禁止事項」硬性違規)
|
|
91
92
|
- **驗證**:Storybook a11y addon panel 0 critical violation。Skeleton 本身無文字內容、無互動角色,axe 不會要求 label;若 consumer 把 Skeleton 包進有語意的容器,label 由該容器負責
|
|
92
93
|
|
|
93
94
|
## 相關
|
|
@@ -101,4 +102,5 @@ Skeleton 是**純視覺 loading placeholder**,預設 ARIA 行為:
|
|
|
101
102
|
|
|
102
103
|
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
103
104
|
|
|
105
|
+
- `circular-progress.spec.md`
|
|
104
106
|
- `progress-bar.spec.md`
|