@qijenchen/design-system 0.1.0-beta.83 → 0.1.0-beta.85
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 +8 -8
- package/README.md +3 -2
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +1 -1
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +22 -2
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +4 -4
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -2
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +12 -3
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +13 -5
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +7 -1
- 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 +8 -3
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Chart/chart.d.ts.map +1 -1
- package/dist/components/Chart/chart.js +1 -0
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +1 -1
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +8 -4
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +1 -1
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +10 -3
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +5 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +30 -13
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +53 -62
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +10 -4
- 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 +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
- package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-group.js +154 -0
- package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +285 -0
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
- package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
- package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +140 -0
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +5 -6
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +36 -15
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DataTable/filter-operators.js +140 -0
- package/dist/components/DataTable/filter-operators.js.map +1 -0
- package/dist/components/DataTable/filter-tree.js +312 -0
- package/dist/components/DataTable/filter-tree.js.map +1 -0
- package/dist/components/DataTable/index.d.ts +3 -0
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/index.js +12 -1
- package/dist/components/DataTable/index.js.map +1 -1
- package/dist/components/DataTable/lib/column-meta.js +25 -0
- package/dist/components/DataTable/lib/column-meta.js.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +3 -1
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +7 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +105 -74
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +20 -3
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +38 -20
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +45 -5
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +19 -0
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-edit-keys.d.ts +21 -0
- package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
- package/dist/components/Field/field-edit-keys.js +19 -0
- package/dist/components/Field/field-edit-keys.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +20 -1
- 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 +3 -2
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +38 -39
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +2 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Field/index.d.ts.map +1 -1
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +1 -1
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts +1 -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 +7 -2
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
- package/dist/components/FileViewer/image-renderer.js +22 -1
- package/dist/components/FileViewer/image-renderer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +5 -3
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/index.d.ts +2 -0
- package/dist/components/InlineEdit/index.d.ts.map +1 -0
- package/dist/components/InlineEdit/index.js +5 -0
- package/dist/components/InlineEdit/index.js.map +1 -0
- package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
- package/dist/components/InlineEdit/inline-edit.js +164 -0
- package/dist/components/InlineEdit/inline-edit.js.map +1 -0
- package/dist/components/Input/input.d.ts +6 -11
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +43 -13
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +2 -2
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +6 -5
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts +14 -2
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js +25 -3
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +3 -3
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +6 -5
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/pagination.js +1 -1
- package/dist/components/Pagination/pagination.js.map +1 -1
- package/dist/components/PeoplePicker/index.js +7 -1
- package/dist/components/PeoplePicker/index.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +23 -10
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +6 -3
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +19 -14
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/Popover/popover.d.ts.map +1 -1
- package/dist/components/Popover/popover.js +3 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +2 -2
- package/dist/components/ProfileCard/profile-card.js +3 -3
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +15 -9
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +6 -3
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/Select/select.d.ts +46 -5
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +109 -28
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +3 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +8 -1
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
- package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
- package/dist/components/SelectionControl/boolean-value.js +23 -0
- package/dist/components/SelectionControl/boolean-value.js.map +1 -0
- package/dist/components/SelectionControl/index.d.ts +1 -0
- package/dist/components/SelectionControl/index.d.ts.map +1 -1
- package/dist/components/SelectionControl/index.js +2 -0
- package/dist/components/SelectionControl/index.js.map +1 -1
- package/dist/components/Sheet/index.js +2 -1
- package/dist/components/Sheet/sheet.d.ts +7 -1
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js +5 -2
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +9 -4
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +8 -10
- 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.map +1 -1
- package/dist/components/Switch/switch.d.ts +6 -6
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -2
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +15 -1
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +2 -2
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +50 -42
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
- package/dist/components/TimePicker/time-columns.js +42 -38
- 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 +8 -6
- 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 +7 -5
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +56 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +211 -12
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +115 -58
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -108
- package/dist/index.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.js +15 -0
- package/dist/tokens/categorical-color.js.map +1 -1
- package/dist/tokens/motion/motion.d.ts +7 -6
- package/dist/tokens/motion/motion.d.ts.map +1 -1
- package/dist/tokens/motion/motion.js +6 -6
- package/dist/tokens/motion/motion.js.map +1 -1
- package/dist/tokens/motion/overlay-motion.d.ts +19 -0
- package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
- package/dist/tokens/motion/overlay-motion.js +9 -0
- package/dist/tokens/motion/overlay-motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.js +5 -0
- package/dist/tokens/uiSize/icon-size.js.map +1 -0
- package/ds-canonical/fork/governance.lock +31 -19
- package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
- package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
- package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/fork/manifest.json +15 -0
- package/ds-canonical/fork/preamble.md +20 -18
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
- package/ds-canonical/hooks/README.md +1 -1
- package/ds-canonical/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
- package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
- package/ds-canonical/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
- package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
- package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
- package/ds-canonical/hooks/stop_self_audit.sh +31 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
- package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
- package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
- package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
- package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
- package/ds-canonical/references/build-ui-canonicals.md +2 -1
- package/ds-canonical/references/failure-class-registry.json +145 -0
- package/ds-canonical/references/governance-audit-coverage.md +33 -0
- package/ds-canonical/references/item-anatomy-recipe.md +2 -2
- package/ds-canonical/references/scenario-definition.md +6 -9
- package/ds-canonical/references/ssot-consultation.md +2 -2
- package/ds-canonical/references/ssot-index.md +5 -4
- package/ds-canonical/references/story-baseline-registry.json +8 -2
- package/ds-canonical/references/structural-token-retention.md +6 -9
- package/ds-canonical/rules/meta-patterns.md +8 -8
- package/ds-canonical/rules/self-verify.md +4 -3
- package/ds-canonical/rules/story-rules.md +2 -2
- package/ds-canonical/rules/ui-development.md +2 -2
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
- package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
- package/ds-canonical/skills/governance-health/SKILL.md +1 -1
- package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
- package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
- package/ds-canonical/skills/new-component/SKILL.md +5 -5
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
- package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
- package/ds-canonical/skills/story-writing/SKILL.md +3 -3
- package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
- package/ds-story-manifest.json +29 -20
- package/llms-full.txt +22 -1
- package/llms.txt +5 -4
- package/package.json +7 -3
- package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
- package/src/components/Accordion/accordion.stories.tsx +16 -1
- package/src/components/Alert/alert.principles.stories.tsx +1 -1
- package/src/components/Alert/alert.spec.md +8 -10
- package/src/components/Alert/alert.stories.tsx +28 -28
- package/src/components/Alert/alert.tsx +1 -1
- package/src/components/AppShell/_demo-helpers.tsx +6 -3
- package/src/components/AppShell/app-shell.spec.md +4 -4
- package/src/components/AppShell/app-shell.tsx +28 -2
- package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
- package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
- package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
- package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
- package/src/components/Avatar/avatar.spec.md +2 -2
- package/src/components/Avatar/avatar.stories.tsx +8 -6
- package/src/components/Avatar/avatar.tsx +13 -5
- package/src/components/Badge/badge.principles.stories.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -0
- package/src/components/Badge/badge.stories.tsx +4 -2
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
- package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.tsx +18 -3
- package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
- package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
- package/src/components/Calendar/calendar.spec.md +5 -4
- package/src/components/Calendar/calendar.stories.tsx +7 -4
- package/src/components/Calendar/calendar.tsx +26 -7
- package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
- package/src/components/Carousel/carousel.spec.md +2 -2
- package/src/components/Carousel/carousel.tsx +11 -3
- package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
- package/src/components/Chart/chart.principles.stories.tsx +1 -1
- package/src/components/Chart/chart.stories.tsx +2 -8
- package/src/components/Chart/chart.tsx +3 -0
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
- package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.spec.md +13 -26
- package/src/components/Checkbox/checkbox.stories.tsx +11 -8
- package/src/components/Checkbox/checkbox.tsx +18 -13
- package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
- package/src/components/Chip/chip.principles.stories.tsx +1 -1
- package/src/components/Chip/chip.spec.md +5 -4
- package/src/components/Chip/chip.tsx +5 -1
- package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
- package/src/components/CircularProgress/circular-progress.spec.md +3 -3
- package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
- package/src/components/Coachmark/coachmark.spec.md +5 -5
- package/src/components/Coachmark/coachmark.stories.tsx +3 -1
- package/src/components/Coachmark/coachmark.tsx +10 -3
- package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
- package/src/components/Combobox/combobox.tsx +53 -19
- package/src/components/Command/command.anatomy.stories.tsx +2 -2
- package/src/components/Command/command.principles.stories.tsx +1 -1
- package/src/components/Command/command.stories.tsx +42 -10
- package/src/components/DataTable/cell-registry.tsx +86 -63
- package/src/components/DataTable/column-types.ts +10 -1
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
- package/src/components/DataTable/data-table-filter-group.tsx +231 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +16 -430
- package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
- package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
- package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
- package/src/components/DataTable/data-table.spec.md +33 -13
- package/src/components/DataTable/data-table.stories.tsx +16 -17
- package/src/components/DataTable/data-table.tsx +107 -61
- package/src/components/DataTable/filter-operators.spec.md +3 -3
- package/src/components/DataTable/index.ts +3 -0
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
- package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DateGrid/date-grid.tsx +3 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
- package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
- package/src/components/DatePicker/date-picker.spec.md +3 -3
- package/src/components/DatePicker/date-picker.stories.tsx +4 -5
- package/src/components/DatePicker/date-picker.tsx +99 -45
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +3 -3
- package/src/components/DescriptionList/description-list.stories.tsx +7 -6
- package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
- package/src/components/Dialog/dialog.spec.md +9 -0
- package/src/components/Dialog/dialog.stories.tsx +66 -5
- package/src/components/Dialog/dialog.tsx +60 -25
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
- package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
- package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
- package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
- package/src/components/Empty/empty.spec.md +2 -2
- package/src/components/Field/field-context.ts +69 -5
- package/src/components/Field/field-controls.spec.md +62 -8
- package/src/components/Field/field-edit-keys.ts +66 -0
- package/src/components/Field/field-types.ts +58 -9
- package/src/components/Field/field-wrapper.tsx +50 -42
- package/src/components/Field/field.anatomy.stories.tsx +9 -6
- package/src/components/Field/field.spec.md +1 -1
- package/src/components/Field/field.stories.tsx +1 -1
- package/src/components/Field/field.tsx +2 -1
- package/src/components/Field/form-validation.spec.md +3 -3
- package/src/components/Field/index.ts +1 -0
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
- package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
- package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
- package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
- package/src/components/FileItem/file-item.spec.md +5 -8
- package/src/components/FileItem/file-item.stories.tsx +36 -25
- package/src/components/FileItem/file-item.tsx +8 -6
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
- package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
- package/src/components/FileUpload/file-upload.spec.md +1 -1
- package/src/components/FileUpload/file-upload.tsx +1 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
- package/src/components/FileViewer/file-viewer.spec.md +30 -12
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
- package/src/components/FileViewer/file-viewer.tsx +12 -4
- package/src/components/FileViewer/image-renderer.tsx +35 -7
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
- package/src/components/HoverCard/hover-card.spec.md +5 -5
- package/src/components/HoverCard/hover-card.stories.tsx +16 -16
- package/src/components/HoverCard/hover-card.tsx +5 -3
- package/src/components/InlineEdit/index.ts +5 -0
- package/src/components/InlineEdit/inline-edit.spec.md +149 -0
- package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
- package/src/components/InlineEdit/inline-edit.tsx +287 -0
- package/src/components/Input/input.anatomy.stories.tsx +8 -7
- package/src/components/Input/input.principles.stories.tsx +2 -12
- package/src/components/Input/input.spec.md +13 -18
- package/src/components/Input/input.tsx +69 -22
- 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.tsx +11 -10
- package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
- package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
- package/src/components/Menu/menu-item.spec.md +22 -15
- package/src/components/Menu/menu-item.stories.tsx +39 -11
- package/src/components/Menu/menu-item.tsx +38 -4
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.spec.md +16 -3
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
- package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
- package/src/components/NumberInput/number-input.spec.md +4 -4
- package/src/components/NumberInput/number-input.tsx +19 -12
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
- package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
- package/src/components/Pagination/pagination.spec.md +1 -1
- package/src/components/Pagination/pagination.stories.tsx +2 -6
- package/src/components/Pagination/pagination.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
- package/src/components/PeoplePicker/people-picker.spec.md +6 -6
- package/src/components/PeoplePicker/people-picker.tsx +56 -16
- package/src/components/PeoplePicker/person-display.tsx +32 -16
- package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
- package/src/components/Popover/popover.tsx +3 -1
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
- package/src/components/ProfileCard/profile-card.spec.md +3 -3
- package/src/components/ProfileCard/profile-card.tsx +6 -6
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
- package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
- package/src/components/RadioGroup/radio-group.tsx +41 -15
- package/src/components/Rating/rating.spec.md +11 -3
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +7 -3
- package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +17 -4
- package/src/components/Select/select.anatomy.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +29 -17
- package/src/components/Select/select.stories.tsx +33 -0
- package/src/components/Select/select.tsx +190 -36
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
- package/src/components/SelectMenu/select-menu.spec.md +15 -7
- package/src/components/SelectMenu/select-menu.tsx +16 -3
- package/src/components/SelectionControl/boolean-value.tsx +39 -0
- package/src/components/SelectionControl/index.ts +1 -0
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.spec.md +3 -3
- package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
- package/src/components/Separator/separator.spec.md +2 -2
- package/src/components/Separator/separator.stories.tsx +6 -27
- package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.spec.md +2 -2
- package/src/components/Sheet/sheet.tsx +9 -5
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
- package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
- package/src/components/Sidebar/sidebar.spec.md +13 -15
- package/src/components/Sidebar/sidebar.stories.tsx +8 -7
- package/src/components/Sidebar/sidebar.tsx +37 -25
- package/src/components/Skeleton/skeleton.stories.tsx +4 -11
- package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
- package/src/components/Slider/slider.principles.stories.tsx +2 -2
- package/src/components/Slider/slider.spec.md +5 -5
- package/src/components/Slider/slider.tsx +3 -1
- package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +1 -1
- package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
- package/src/components/Switch/switch.principles.stories.tsx +4 -4
- package/src/components/Switch/switch.spec.md +8 -8
- package/src/components/Switch/switch.stories.tsx +9 -24
- package/src/components/Switch/switch.tsx +17 -13
- package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
- package/src/components/Tabs/tabs.spec.md +1 -1
- package/src/components/Tabs/tabs.tsx +21 -1
- package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
- package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
- package/src/components/Textarea/textarea.spec.md +4 -4
- package/src/components/Textarea/textarea.tsx +72 -46
- package/src/components/TimePicker/time-columns.tsx +6 -2
- package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
- package/src/components/TimePicker/time-picker.spec.md +3 -3
- package/src/components/TimePicker/time-picker.tsx +16 -10
- package/src/components/Toast/toast.stories.tsx +7 -4
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
- package/src/components/Tooltip/tooltip.spec.md +1 -1
- package/src/components/Tooltip/tooltip.stories.tsx +4 -39
- package/src/components/Tooltip/tooltip.tsx +8 -6
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
- package/src/components/TreeView/tree-view.spec.md +42 -11
- package/src/components/TreeView/tree-view.stories.tsx +1 -0
- package/src/components/TreeView/tree-view.tsx +322 -17
- package/src/index.ts +588 -60
- package/src/patterns/action-bar/action-bar.spec.md +9 -0
- package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
- package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
- package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
- package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
- package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
- package/src/styles/tokens.css +3 -0
- package/src/tokens/README.md +1 -1
- package/src/tokens/color/color.spec.md +4 -4
- package/src/tokens/color/color.stories.tsx +3 -3
- package/src/tokens/density/density.stories.tsx +16 -3
- package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
- package/src/tokens/motion/motion.css +33 -21
- package/src/tokens/motion/motion.spec.md +32 -15
- package/src/tokens/motion/motion.stories.tsx +58 -5
- package/src/tokens/motion/motion.ts +7 -6
- package/src/tokens/motion/overlay-motion.ts +26 -0
- package/src/tokens/orphan-tokens.spec.md +4 -4
- package/src/tokens/token-system.spec.md +1 -0
- package/src/tokens/uiSize/uiSize.css +1 -1
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
- package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
- package/src/tokens/utility-registry.json +160 -23
|
@@ -62,10 +62,10 @@ export const CompositionRules: Story = {
|
|
|
62
62
|
<p>SelectionItem 是 Family 2 reading-mode row layout primitive,由 Checkbox / RadioGroup 兩個 consumer 在「list-as-page settings」場景消費,**不直接放在 app code**:</p>
|
|
63
63
|
|
|
64
64
|
<h4>Pattern 1 — Checkbox + SelectionItem(多選 settings list)</h4>
|
|
65
|
-
<p>多選 + 每個 row 大塊 description / icon → <LinkTo kind="Design System/Components/Checkbox/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Checkbox</span></LinkTo> 內部消費 SelectionItem(
|
|
65
|
+
<p>多選 + 每個 row 大塊 description / icon → <LinkTo kind="Design System/Components/Checkbox/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Checkbox</span></LinkTo> 內部消費 SelectionItem(control 放 Checkbox indicator / prefix 可選放 icon 或 avatar / content 放 label + description)。對齊 Notion 通知設定 / Slack notification preferences idiom。</p>
|
|
66
66
|
|
|
67
67
|
<h4>Pattern 2 — RadioGroup + SelectionItem(單選 plan picker)</h4>
|
|
68
|
-
<p>單選 + 每個 row 大塊描述(plan tier / tier features)→ <LinkTo kind="Design System/Components/RadioGroup/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">RadioGroup</span></LinkTo> 內部消費 SelectionItem(
|
|
68
|
+
<p>單選 + 每個 row 大塊描述(plan tier / tier features)→ <LinkTo kind="Design System/Components/RadioGroup/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">RadioGroup</span></LinkTo> 內部消費 SelectionItem(control 放 Radio indicator / prefix 可選放 icon 或 avatar / content 多行)。對齊 Stripe plan picker / Linear pricing tier idiom。</p>
|
|
69
69
|
|
|
70
70
|
<h4>Field 包覆規則</h4>
|
|
71
71
|
<p>Checkbox / RadioGroup 在 form context 內 → 外層用 <LinkTo kind="Design System/Components/Field/展示" name="垂直"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Field</span></LinkTo> 統一 label + helper + error(對齊 Field 4-Family Layout 慣例)。Field 處理 wrapper level 的 ARIA + error,SelectionItem 處理 row level 的 layout。</p>
|
|
@@ -26,13 +26,13 @@ SelectionItem 是 **Checkbox 和 RadioGroup 共用的 item 佈局 primitive**—
|
|
|
26
26
|
|
|
27
27
|
**實作基礎**:自建 internal primitive——純視覺佈局 + padding 公式,無 external primitive base。
|
|
28
28
|
|
|
29
|
-
**Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。SelectionItem 是 Family 2 的 SelectionItem variant
|
|
29
|
+
**Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。SelectionItem 是 Family 2 的 SelectionItem variant:`control` slot 放 Checkbox/Radio indicator,`prefix` slot 專供 icon/avatar——兩者是獨立 slot、可並存(如 `<Checkbox icon>` 同時有 indicator + icon,見「結構」段的 3-slot 圖)。
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
33
|
## 何時用 / 何時不用
|
|
34
34
|
|
|
35
|
-
**
|
|
35
|
+
**SelectionItem 是 internal primitive**——不直接使用,透過 Checkbox / RadioGroup 消費。**裸用禁止;內部由 Checkbox / RadioGroup 組合消費允許**——consumer 與展示範例一律走公開 `<Checkbox label>` / `<RadioGroupItem label>` 路徑(自動 wire id/htmlFor);primitive 自家 stories 展示自身 API 為唯一裸用豁免。
|
|
36
36
|
|
|
37
37
|
**icon / avatar prefix 消費路徑(2026-06-12 M30 修)**:`<Checkbox icon={...}>` / `<RadioGroupItem avatar={...}>` 直接轉發本 primitive 的既有槽(本檔「3-slot 結構」+ selection-item.tsx jsDoc 為對齊規則 SSOT)——不需也不准裸用 `<SelectionItem>`。
|
|
38
38
|
|
|
@@ -85,7 +85,7 @@ Checkbox 和 Radio 視覺幾乎完全一致(差異只在形狀 `rounded-md` vs
|
|
|
85
85
|
## 禁止事項
|
|
86
86
|
|
|
87
87
|
- ❌ 直接在 JSX 用 `<SelectionItem>`——透過 Checkbox / Radio 消費
|
|
88
|
-
- ❌ 在 Checkbox / Radio 之外複製 SelectionItem 邏輯——共用源頭一定是 SelectionControl
|
|
88
|
+
- ❌ 在 Checkbox / Radio 之外複製 SelectionItem 邏輯——共用源頭一定是 SelectionItem(`SelectionControl/` 僅為概念群組資料夾名,見「關於資料夾命名」note)
|
|
89
89
|
- ❌ 改動 `py` padding 公式只針對某一 variant——Checkbox 和 Radio 必須同步
|
|
90
90
|
|
|
91
91
|
---
|
|
@@ -114,19 +114,19 @@ export const WithPrefixAvatarBlock: Story = {
|
|
|
114
114
|
</p>
|
|
115
115
|
<SelectionItem
|
|
116
116
|
control={<Checkbox defaultChecked />}
|
|
117
|
-
avatar={{ alt: 'Ada Chen', color: 'indigo' }}
|
|
117
|
+
avatar={{ src: 'https://i.pravatar.cc/64?u=ada-chen', alt: 'Ada Chen', color: 'indigo' }}
|
|
118
118
|
label="Ada Chen"
|
|
119
119
|
description="Design Engineer · Frontend team"
|
|
120
120
|
/>
|
|
121
121
|
<SelectionItem
|
|
122
122
|
control={<Checkbox />}
|
|
123
|
-
avatar={{ alt: '張美真', color: 'magenta' }}
|
|
123
|
+
avatar={{ src: 'https://i.pravatar.cc/64?u=zhang-meizhen', alt: '張美真', color: 'magenta' }}
|
|
124
124
|
label="張美真"
|
|
125
125
|
description="Product Designer · Platform team"
|
|
126
126
|
/>
|
|
127
127
|
<SelectionItem
|
|
128
128
|
control={<Checkbox defaultChecked />}
|
|
129
|
-
avatar={{ alt: '林伯彥', color: 'green' }}
|
|
129
|
+
avatar={{ src: 'https://i.pravatar.cc/64?u=lin-boyan', alt: '林伯彥', color: 'green' }}
|
|
130
130
|
label="林伯彥"
|
|
131
131
|
description="Staff Engineer · Infra team"
|
|
132
132
|
/>
|
|
@@ -78,7 +78,7 @@ Consumer 在 JSX 裡明確放置分隔線的場景:
|
|
|
78
78
|
|
|
79
79
|
## 邊界案例
|
|
80
80
|
|
|
81
|
-
- **Vertical 方向**:`h-full` 取父容器高度——父容器無確定高度(auto)時 separator 高度為 0、不可見;需父容器有確定高度或 flex row 的 stretch
|
|
81
|
+
- **Vertical 方向**:`h-full` 取父容器高度——父容器無確定高度(auto)時 separator 高度為 0、不可見;需父容器有確定高度或 flex row 的 stretch 對齊。**例外(toolbar / action region 群組分隔)**:實務上一律**縮短高度**(`h-6 mx-1` 等),不 full-height — 幾何 SSOT → `patterns/action-bar/action-bar.spec.md`「分隔線幾何」段(2026-07-08 codify;版面切分 divider 不適用、零 gap)
|
|
82
82
|
- **空容器 / 0 寬**:horizontal `w-full` 隨父寬,父寬為 0 時無可見線;Separator 不自帶 min-width / min-height
|
|
83
83
|
- **厚度固定 1px**(`h-px` / `w-px`)、非互動無 hover / focus——無 size / state 變體(見下「為何無 …」段)
|
|
84
84
|
|
|
@@ -88,7 +88,7 @@ Separator 是**視覺分隔 primitive**(一條 1px 線),結構極薄:
|
|
|
88
88
|
|
|
89
89
|
- **無 Inspector**:Separator 唯一變因是 `orientation`(horizontal / vertical),已在 `TokenMatrix` 對照呈現。互動 Inspector 無進一步可調 prop。
|
|
90
90
|
- **無 ColorMatrix**:Separator 固定用 `--divider` token(比 border 更淡的語意分隔色),dark mode 由 semantic token 自動切換。無變體。加 color variant 會誤用成「狀態訊號」(分隔應是中性的)。
|
|
91
|
-
- **無 SizeMatrix**:Separator 固定 1px 厚度(線應該是線),長度由 container 決定(`w-full` / `h-full
|
|
91
|
+
- **無 SizeMatrix**:Separator 固定 1px 厚度(線應該是線),長度由 container 決定(`w-full` / `h-full`;toolbar 群組分隔例外縮短,見「邊界案例」+ action-bar.spec.md「分隔線幾何」)。無 sm/md/lg tier。
|
|
92
92
|
- **無 StateBehavior**:非互動元件,無 hover / focus / active / selected / disabled。
|
|
93
93
|
|
|
94
94
|
對應 anatomy story:保留 `Overview` + `TokenMatrix`(horizontal × vertical + `--divider` vs `--border` 用法對照)。
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
-
import {
|
|
2
|
+
import { User, Bell, Shield } from 'lucide-react'
|
|
3
3
|
import { Separator } from './separator'
|
|
4
4
|
import { DescriptionList, DescriptionItem } from '@/design-system/components/DescriptionList/description-list'
|
|
5
5
|
import { Button } from '@/design-system/components/Button/button'
|
|
6
6
|
import { MenuItem } from '@/design-system/components/Menu/menu-item'
|
|
7
|
-
import {
|
|
8
|
-
DropdownMenu,
|
|
9
|
-
DropdownMenuTrigger,
|
|
10
|
-
DropdownMenuContent,
|
|
11
|
-
DropdownMenuItem,
|
|
12
|
-
DropdownMenuSeparator,
|
|
13
|
-
} from '@/design-system/components/DropdownMenu/dropdown-menu'
|
|
14
7
|
|
|
15
8
|
const meta: Meta<typeof Separator> = {
|
|
16
9
|
title: 'Design System/Components/Separator/展示',
|
|
@@ -76,25 +69,11 @@ export const Vertical: Story = {
|
|
|
76
69
|
),
|
|
77
70
|
}
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<DropdownMenuTrigger asChild>
|
|
85
|
-
<Button variant="tertiary" size="sm" startIcon={MoreVertical}>
|
|
86
|
-
更多操作
|
|
87
|
-
</Button>
|
|
88
|
-
</DropdownMenuTrigger>
|
|
89
|
-
<DropdownMenuContent align="start">
|
|
90
|
-
<DropdownMenuItem startIcon={Pencil}>重新命名</DropdownMenuItem>
|
|
91
|
-
<DropdownMenuItem startIcon={Copy}>複製連結</DropdownMenuItem>
|
|
92
|
-
<DropdownMenuSeparator />
|
|
93
|
-
<DropdownMenuItem startIcon={Trash2}>刪除</DropdownMenuItem>
|
|
94
|
-
</DropdownMenuContent>
|
|
95
|
-
</DropdownMenu>
|
|
96
|
-
),
|
|
97
|
-
}
|
|
72
|
+
// @story-trait-rationale: InDropdownMenu retired 2026-07-14 per audit Dim 24 —
|
|
73
|
+
// 同一「重新命名/複製連結/分隔/刪除」選單完整重複 principles DecorativeSemanticRule
|
|
74
|
+
// (separator.principles.stories.tsx)首例;且 menu 內分隔屬 DropdownMenuSeparator
|
|
75
|
+
// (DropdownMenu owns 該 primitive,見 separator.spec.md 近親分界),非 consumer
|
|
76
|
+
// 手動放置 Separator 的場景 — canonical 範例由 DropdownMenu 展示層 owns。
|
|
98
77
|
|
|
99
78
|
/* ── 在 DescriptionList 之間 ────────────────────────────────────────── */
|
|
100
79
|
export const BetweenSections: Story = {
|
|
@@ -238,7 +238,7 @@ export const StateBehavior: Story = {
|
|
|
238
238
|
<div className="flex flex-col gap-8">
|
|
239
239
|
<div>
|
|
240
240
|
<H3>開啟 / 關閉</H3>
|
|
241
|
-
<Desc>Radix 提供 data-state 切換 + DS Tailwind animate 驅動進離場動畫(slide-in-from-側邊
|
|
241
|
+
<Desc>Radix 提供 data-state 切換 + DS Tailwind animate 驅動進離場動畫(panel slide-in-from-側邊 250ms,consume surfaceMotion / --motion-duration-surface;overlay fade 沿用 tw-animate-css 預設 約 150ms;sheet.tsx sheetVariants),離場鏡像。Modal 狀態鎖 body scroll。</Desc>
|
|
242
242
|
<ul className="text-caption text-fg-muted list-disc pl-5 space-y-1">
|
|
243
243
|
<li>點擊 trigger → 開啟(slide-in from `side`)</li>
|
|
244
244
|
<li>點擊 overlay → 關閉(default;可用 onPointerDownOutside preventDefault 阻止)</li>
|
|
@@ -82,7 +82,7 @@ export const UsageGuidance: Story = {
|
|
|
82
82
|
<LinkTo kind="Design System/Components/Sheet/展示" name="編輯成員詳情(右側滑入)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">編輯成員詳情(右側滑入)</span></LinkTo>
|
|
83
83
|
</li>
|
|
84
84
|
</ul>
|
|
85
|
-
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(
|
|
85
|
+
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見本頁下方「vs 近親」對照段)。</p>
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
88
|
{/* vs 近親 — VsDialogRule — 原 VsDialogRule */}
|
|
@@ -104,7 +104,7 @@ 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
109
|
- **Scroll(body 內容超過視口高度)**:`SheetBody` = `<ScrollArea>`(`flex-1 min-h-0`),超高內容在 body 內部捲動,header / footer 固定不動;consumer 不需自寫 `overflow-y-auto`。
|
|
110
110
|
- **誤嵌套降級(nested Sheet)**:禁止事項已禁 nested;若 consumer 不慎嵌套,Radix 的 Esc 與 focus trap 只作用於**最上層** layer(DismissableLayer 只 dismiss highest layer;FocusScope stack 最新 scope active),關閉由上而下逐層。
|
|
@@ -132,7 +132,7 @@ Sheet 為容器,內容由 consumer 決定;focus trap + Escape close + `aria-labe
|
|
|
132
132
|
- Esc — 關閉
|
|
133
133
|
- Shift+Tab — 反向 focus 循環
|
|
134
134
|
|
|
135
|
-
**Focus**:Radix primitive 自管 focus trap /
|
|
135
|
+
**Focus**:Radix primitive 自管 focus trap / visible ring(per design-system focus-visible canonical)。**Restoration 例外(2026-07-14)**:Radix 內建「關閉回焦 trigger」依賴 `SheetTrigger` 的 triggerRef;**controlled-without-trigger**(如 AppShellAside 手機模式)triggerRef=null + 內建 preventDefault 會讓焦點掉 `<body>` — 必自建 `onCloseAutoFocus` snapshot 還原(先例:AppShellAside app-shell.tsx / DatePicker Range date-picker.tsx:1061;WCAG 2.4.3)。
|
|
136
136
|
|
|
137
137
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
138
138
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "@/design-system/patterns/overlay-surface/overlay-surface"
|
|
13
13
|
import { Button } from "@/design-system/components/Button/button"
|
|
14
14
|
import { ScrollArea } from "@/design-system/components/ScrollArea/scroll-area"
|
|
15
|
+
import { surfaceMotion } from "@/design-system/tokens/motion/overlay-motion"
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Sheet — **右側 Dialog primitive**(給消費者的 canonical)。
|
|
@@ -67,8 +68,9 @@ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
|
|
67
68
|
const sheetVariants = cva(
|
|
68
69
|
// 核心容器 — 無 padding(由 SheetBody / SheetHeader / SheetFooter 自理 padding,
|
|
69
70
|
// 對齊 overlay-surface pattern + Dialog canonical)
|
|
70
|
-
// Animation canonical:
|
|
71
|
-
|
|
71
|
+
// Animation canonical:panel = surfaceMotion 250ms(--motion-duration-surface)雙向一致
|
|
72
|
+
// (D4 audit:500ms 太久 sluggish)+ motion-reduce 豁免
|
|
73
|
+
`fixed z-50 flex flex-col bg-surface-raised shadow-[var(--elevation-200)] transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out ${surfaceMotion}`,
|
|
72
74
|
{
|
|
73
75
|
variants: {
|
|
74
76
|
side: {
|
|
@@ -91,7 +93,9 @@ interface SheetContentProps
|
|
|
91
93
|
VariantProps<typeof sheetVariants> {}
|
|
92
94
|
|
|
93
95
|
// AutoFocus canonical(對齊 Dialog / Material / Polaris)— 見 dialog.tsx handleOpenAutoFocus 註解
|
|
94
|
-
|
|
96
|
+
/** @internal DS 預設 open-focus(首個 body 互動元素)。consumer 傳自訂 onOpenAutoFocus 會覆寫
|
|
97
|
+
* 本預設({...props} 在後),需自訂前置行為(如 AppShellAside opener snapshot)時 import 接力呼叫。 */
|
|
98
|
+
export const handleSheetOpenAutoFocus = (e: Event) => {
|
|
95
99
|
e.preventDefault()
|
|
96
100
|
const content = e.currentTarget as HTMLElement
|
|
97
101
|
const firstBodyTarget = content.querySelector<HTMLElement>(
|
|
@@ -123,7 +127,7 @@ const SheetContent = React.forwardRef<
|
|
|
123
127
|
SheetContent.displayName = SheetPrimitive.Content.displayName
|
|
124
128
|
|
|
125
129
|
// ── SheetHeader:SurfaceHeader + Close X(對齊 DialogHeader canonical)──────────
|
|
126
|
-
// 2026-05-18 audit gap fix:type 對齊 SurfaceHeaderProps,withTabs /
|
|
130
|
+
// 2026-05-18 audit gap fix:type 對齊 SurfaceHeaderProps,withTabs / tabsSlot expose
|
|
127
131
|
// 給 consumer(per header-canonical.spec.md W1 跨 6 consumer 同契約)。Spread 早 forward
|
|
128
132
|
// 過去,只是 TS type 沒 expose 導致 consumer 不能 type-safe 用 `<SheetHeader withTabs>`。
|
|
129
133
|
const SheetHeader = React.forwardRef<
|
|
@@ -152,7 +156,7 @@ SheetHeader.displayName = "SheetHeader"
|
|
|
152
156
|
//
|
|
153
157
|
// ── List-as-region 場景(menu / nav / settings list)──
|
|
154
158
|
// 不再提供 `flush` variant(2026-05-01 移除)。canonical = consumer 用 className override:
|
|
155
|
-
// `<SheetBody className="!px-0 !pt-0 !pb-0"><div className="py-2">{items}</div></SheetBody>`
|
|
159
|
+
// `<SheetBody className="!px-0 !pt-0 !pb-0"><div className="py-2">{items}</div></SheetBody>` ← @tabs-content-gap-ok: JSDoc 文件範例(list-as-region canonical,非 tabs !pt-0 hack;對齊 dialog.tsx 同款 marker)
|
|
156
160
|
// 詳 DialogBody comment + `tokens/layoutSpace/layoutSpace.spec.md`「List-as-region in overlay body」
|
|
157
161
|
// `className` forward 到 **inner content div**(非外層 ScrollArea wrapper)——
|
|
158
162
|
// consumer `<SheetBody className="flex flex-col gap-X">` 期望作用於 children 排列;
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from './sidebar'
|
|
18
18
|
import { ItemAvatar } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
19
19
|
import { Avatar } from '@/design-system/components/Avatar/avatar'
|
|
20
|
+
import { ChromeHeader } from '@/design-system/patterns/header-canonical/chrome-header'
|
|
20
21
|
|
|
21
22
|
const meta: Meta = {
|
|
22
23
|
title: 'Design System/Components/Sidebar/設計規格',
|
|
@@ -115,7 +116,7 @@ const SidebarPreview = ({
|
|
|
115
116
|
<SidebarMenuItem>
|
|
116
117
|
<SidebarMenuButton asChild>
|
|
117
118
|
<button type="button">
|
|
118
|
-
<ItemAvatar alt="Alan Chen" color="blue" />
|
|
119
|
+
<ItemAvatar src="https://i.pravatar.cc/48?u=EMP-1001" alt="Alan Chen" color="blue" />
|
|
119
120
|
<span data-sidebar="menu-label" className="min-w-0 flex-1 truncate">Alan Chen</span>
|
|
120
121
|
</button>
|
|
121
122
|
</SidebarMenuButton>
|
|
@@ -139,7 +140,7 @@ export const Overview: Story = {
|
|
|
139
140
|
<div className="flex flex-col gap-2">
|
|
140
141
|
<H3>結構(Anatomy)</H3>
|
|
141
142
|
<Desc>
|
|
142
|
-
Sidebar 是三段式結構——SidebarHeader
|
|
143
|
+
Sidebar 是三段式結構——SidebarHeader(固定高 `--chrome-header-height`)、SidebarContent(可捲動)、SidebarFooter(高度由內容決定,shrink-0 靠底 + border-t)。
|
|
143
144
|
Content 內放一或多個 SidebarGroup,每個 group 有 py-2 呼吸空間 + 自動內縮分隔線。
|
|
144
145
|
Group 內放 SidebarMenu(扁平 row)或 TreeView(階層 row),兩者共用 item-layout row geometry。
|
|
145
146
|
</Desc>
|
|
@@ -651,10 +652,13 @@ export const StateBehavior: Story = {
|
|
|
651
652
|
</SidebarContent>
|
|
652
653
|
</Sidebar>
|
|
653
654
|
<div className="flex-1 flex flex-col">
|
|
654
|
-
|
|
655
|
+
{/* 2026-07-14 audit Dim 68:主內容 header 消費 ChromeHeader(原手刻 h-10=40px 破壞
|
|
656
|
+
與 SidebarHeader 共用 --chrome-header-height 的兩側 chrome 對齊 — sidebar.spec.md
|
|
657
|
+
「Chrome header 不跟 size 變」段;對齊 sidebar.stories.tsx PageContent baseline)*/}
|
|
658
|
+
<ChromeHeader className="bg-surface">
|
|
655
659
|
<SidebarTrigger />
|
|
656
|
-
<span className="text-
|
|
657
|
-
</
|
|
660
|
+
<span className="text-body-lg font-medium">Dashboard</span>
|
|
661
|
+
</ChromeHeader>
|
|
658
662
|
<div className="flex-1 px-4 py-3 text-caption text-fg-muted">
|
|
659
663
|
點 SidebarTrigger 或按 Cmd/Ctrl+B,觀察 sidebar 縮到 48px(icon mode)。再按一次展開。
|
|
660
664
|
</div>
|
|
@@ -668,7 +672,7 @@ export const StateBehavior: Story = {
|
|
|
668
672
|
<div className="flex flex-col gap-3">
|
|
669
673
|
<span className="text-caption font-medium text-fg-secondary">行為 3:Icon mode 時 label 隱藏 → Tooltip 代償</span>
|
|
670
674
|
<Desc>
|
|
671
|
-
collapse 到 icon mode 時 label 文字隱藏,滑鼠 hover menu button
|
|
675
|
+
collapse 到 icon mode 時 label 文字隱藏,滑鼠 hover menu button(**需 per-button 傳 `tooltip` prop**,opt-in)才出現 Tooltip(顯示 label)補償 — 對齊 Linear / GitHub 慣例,避免 icon-only 狀態讓使用者忘記每個 icon 的含義。SidebarMenuButton 內建此行為(`tooltip` prop)。
|
|
672
676
|
</Desc>
|
|
673
677
|
</div>
|
|
674
678
|
|
|
@@ -678,9 +682,9 @@ export const StateBehavior: Story = {
|
|
|
678
682
|
<ul className="text-caption text-fg-secondary space-y-1.5 ml-4 list-disc">
|
|
679
683
|
<li>`collapsible="offcanvas"` 用於主內容為主的 app(sidebar 是啟動器,使用者常關);`collapsible="icon"` 用於深度導覽 app(sidebar 是常駐工作區)。</li>
|
|
680
684
|
<li>open state 寫 cookie `sidebar_state`(7 天 max-age);Provider 只寫不讀,還原由 consumer 讀 cookie 傳 `defaultOpen`(避免 SSR hydration flash)。</li>
|
|
681
|
-
<li>Mobile(<768px)
|
|
685
|
+
<li>Mobile(<768px)時 `offcanvas`(預設)/ `icon` 走 Sheet overlay,小螢幕不佔固定空間;**`collapsible="none"` 例外**——`none` 在 `isMobile` 判斷前提前 return,mobile 下仍是固定寬度側欄,不進 Sheet。</li>
|
|
682
686
|
<li>Icon mode 下 active item 的 `bg-neutral-selected` 仍然顯示,但 label 不可見——提供最小視覺指引讓使用者知道「當前在哪」。</li>
|
|
683
|
-
<li>Cmd+B / Ctrl+B 全域快捷鍵由 SidebarProvider
|
|
687
|
+
<li>Cmd+B / Ctrl+B 全域快捷鍵由 SidebarProvider 監聽,但有三道 guard(2026-07-05 D4 修):`defaultPrevented`(app editor 已處理同鍵時不 double-fire)/ `isComposing`(IME 組字中不攔)/ 可編輯 target(`input` / `textarea` / `contentEditable` 內按 Cmd/Ctrl+B **不 toggle**,讓位給 bold 等編輯語意)。仍無 `disableShortcut` opt-out。</li>
|
|
684
688
|
</ul>
|
|
685
689
|
</div>
|
|
686
690
|
</div>
|
|
@@ -719,7 +723,7 @@ export const ChromeTokens: Story = {
|
|
|
719
723
|
<tr>
|
|
720
724
|
<Td><TkVal token="--sidebar-width-icon" value="calc(2 × loose + icon)" /></Td>
|
|
721
725
|
<Td mono>calc()</Td>
|
|
722
|
-
<Td>icon 收合模式寬度(2026-05-21 v3 改 geometry formula;md=48 / lg=
|
|
726
|
+
<Td>icon 收合模式寬度(2026-05-21 v3 改 geometry formula;md = 2×16+16 = 48 / lg = 2×24+20 = 68,保證 icon center x 展開/收合一致)</Td>
|
|
723
727
|
</tr>
|
|
724
728
|
<tr>
|
|
725
729
|
<Td><TkVal token="--sidebar-menu-icon-size" value="1rem (16px)" /></Td>
|
|
@@ -738,7 +742,7 @@ export const ChromeTokens: Story = {
|
|
|
738
742
|
<div className="flex flex-col gap-2">
|
|
739
743
|
<H3>Chrome header token(共享)</H3>
|
|
740
744
|
<Desc>
|
|
741
|
-
SidebarHeader /
|
|
745
|
+
SidebarHeader / 主內容 page header 都用這個 token,確保跨元件同高對齊。Density-responsive。(SidebarFooter 為 content-based,高度由內容決定,不消費此 token。)
|
|
742
746
|
</Desc>
|
|
743
747
|
<table className="min-w-full text-left border-collapse">
|
|
744
748
|
<thead>
|
|
@@ -750,7 +754,7 @@ export const ChromeTokens: Story = {
|
|
|
750
754
|
<tbody>
|
|
751
755
|
<tr>
|
|
752
756
|
<Td mono>--chrome-header-height</Td>
|
|
753
|
-
<Td>Sidebar header
|
|
757
|
+
<Td>Sidebar header 固定高度(footer 為 content-based,不消費此 token);density 解析值見 uiSize.spec.md</Td>
|
|
754
758
|
</tr>
|
|
755
759
|
</tbody>
|
|
756
760
|
</table>
|
|
@@ -766,7 +770,7 @@ export const Accessibility = {
|
|
|
766
770
|
render: () => (
|
|
767
771
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
768
772
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
769
|
-
<p className="whitespace-pre-line">{"- 收合切換鍵:Cmd+B(Mac)/ Ctrl+B(Windows)是業界慣例(VS Code / Linear / shadcn 都用),Sidebar
|
|
773
|
+
<p className="whitespace-pre-line">{"- 收合切換鍵:Cmd+B(Mac)/ Ctrl+B(Windows)是業界慣例(VS Code / Linear / shadcn 都用),Sidebar 內建並會攔下這組鍵,避免穿透到瀏覽器書籤列。任何焦點位置都能觸發;任何焦點位置都能觸發,但有三道 guard(2026-07-05 D4):app 已處理同鍵(defaultPrevented)/ IME 組字中(isComposing)/ 可編輯 target(input / textarea / contentEditable 內讓位給 bold 等編輯語意)時不 toggle。仍無 disableShortcut opt-out。\n\n- 收合按鈕:SidebarTrigger 內建 aria-label「切換側邊欄」,讓螢幕報讀使用者知道按鈕用途;consumer 可傳 aria-label 覆寫(i18n)。SidebarGroupLabel 的收合 chevron 另有 toggleAriaLabel prop(預設「展開或收合」)。\n\n- 當前項目:選中的 menu item 帶 data-active,呈現選取底色(bg-neutral-selected)作為視覺指引;即使收合成 icon-only 模式,選取底色仍然保留,使用者一眼知道現在在哪一頁。\n\n- 手機尺寸:768px 以下自動切換成從旁滑出的抽屜(Sheet),內建焦點鎖定、Esc 關閉;關閉後焦點還原走 Radix FocusScope 預設(還原到開啟前聚焦元素),因 mobile Sheet 無顯式 SheetTrigger,不保證回到觸發按鈕。"}</p>
|
|
770
774
|
</div>
|
|
771
775
|
),
|
|
772
776
|
}
|
|
@@ -324,10 +324,10 @@ export const GroupHeaderRules: Story = {
|
|
|
324
324
|
<SidebarGroupContent>
|
|
325
325
|
<SidebarMenu>
|
|
326
326
|
<SidebarMenuItem>
|
|
327
|
-
<SidebarMenuButton startIcon={Folder}>
|
|
327
|
+
<SidebarMenuButton id="web-app" startIcon={Folder}>Web App</SidebarMenuButton>
|
|
328
328
|
</SidebarMenuItem>
|
|
329
329
|
<SidebarMenuItem>
|
|
330
|
-
<SidebarMenuButton startIcon={Folder}>
|
|
330
|
+
<SidebarMenuButton id="mobile-app" startIcon={Folder}>Mobile App</SidebarMenuButton>
|
|
331
331
|
</SidebarMenuItem>
|
|
332
332
|
</SidebarMenu>
|
|
333
333
|
</SidebarGroupContent>
|
|
@@ -373,13 +373,15 @@ export const SettingsScenario: Story = {
|
|
|
373
373
|
若子頁等重要且需一鍵直達,用 SidebarGroupLabel 當純視覺分段標題,子項全部是獨立頂層 SidebarMenuItem。
|
|
374
374
|
少見,只在子項確實高頻使用時才用。
|
|
375
375
|
</Desc>
|
|
376
|
-
|
|
376
|
+
{/* 導覽項必帶穩定 id(sidebar.spec.md「禁止:SidebarMenuButton 不傳 id」)—
|
|
377
|
+
id 進 SidebarProvider 單一 activeId selection 模型,漏 id = 啞 item 無法 active。 */}
|
|
378
|
+
<MiniSidebar activeId="settings-general">
|
|
377
379
|
<SidebarContent>
|
|
378
380
|
<SidebarGroup>
|
|
379
381
|
<SidebarGroupContent>
|
|
380
382
|
<SidebarMenu>
|
|
381
|
-
<SidebarMenuItem><SidebarMenuButton startIcon={Inbox}>Inbox</SidebarMenuButton></SidebarMenuItem>
|
|
382
|
-
<SidebarMenuItem><SidebarMenuButton startIcon={Folder}>Projects</SidebarMenuButton></SidebarMenuItem>
|
|
383
|
+
<SidebarMenuItem><SidebarMenuButton id="inbox" startIcon={Inbox}>Inbox</SidebarMenuButton></SidebarMenuItem>
|
|
384
|
+
<SidebarMenuItem><SidebarMenuButton id="projects" startIcon={Folder}>Projects</SidebarMenuButton></SidebarMenuItem>
|
|
383
385
|
</SidebarMenu>
|
|
384
386
|
</SidebarGroupContent>
|
|
385
387
|
</SidebarGroup>
|
|
@@ -387,9 +389,9 @@ export const SettingsScenario: Story = {
|
|
|
387
389
|
<SidebarGroupLabel>Settings</SidebarGroupLabel>
|
|
388
390
|
<SidebarGroupContent>
|
|
389
391
|
<SidebarMenu>
|
|
390
|
-
<SidebarMenuItem><SidebarMenuButton startIcon={Settings}>General</SidebarMenuButton></SidebarMenuItem>
|
|
391
|
-
<SidebarMenuItem><SidebarMenuButton startIcon={Users}>Team</SidebarMenuButton></SidebarMenuItem>
|
|
392
|
-
<SidebarMenuItem><SidebarMenuButton startIcon={FileText}>Billing</SidebarMenuButton></SidebarMenuItem>
|
|
392
|
+
<SidebarMenuItem><SidebarMenuButton id="settings-general" startIcon={Settings}>General</SidebarMenuButton></SidebarMenuItem>
|
|
393
|
+
<SidebarMenuItem><SidebarMenuButton id="settings-team" startIcon={Users}>Team</SidebarMenuButton></SidebarMenuItem>
|
|
394
|
+
<SidebarMenuItem><SidebarMenuButton id="settings-billing" startIcon={FileText}>Billing</SidebarMenuButton></SidebarMenuItem>
|
|
393
395
|
</SidebarMenu>
|
|
394
396
|
</SidebarGroupContent>
|
|
395
397
|
</SidebarGroup>
|
|
@@ -142,7 +142,7 @@ Sidebar 有兩種正交的內容形態,consumer 嚴格擇一或混用:
|
|
|
142
142
|
|
|
143
143
|
| 形態 | 元件 | 深度 | 數量 | Icon 模式 |
|
|
144
144
|
|------|------|------|------|----------|
|
|
145
|
-
| **扁平導覽** | `SidebarMenu` | **嚴格 1 層** | **有限可列舉** | ✅ 顯示 icon
|
|
145
|
+
| **扁平導覽** | `SidebarMenu` | **嚴格 1 層** | **有限可列舉** | ✅ 顯示 icon(hover tooltip 為 opt-in,需 per-button 傳 `tooltip` prop) |
|
|
146
146
|
| **階層樹** | `TreeView` | 任意 | 任意 | ❌ 整區隱藏 |
|
|
147
147
|
|
|
148
148
|
### 判斷規則
|
|
@@ -191,7 +191,7 @@ Settings 不在 sidebar,從 footer 的 avatar / user menu 觸發 modal 或快
|
|
|
191
191
|
|
|
192
192
|
### 混用
|
|
193
193
|
|
|
194
|
-
Gmail / Linear 的標準版型:上方 SidebarGroup 放扁平主導覽(SidebarMenu),下方 SidebarGroup 放 user data(TreeView)。icon 模式下,扁平區顯示 icon
|
|
194
|
+
Gmail / Linear 的標準版型:上方 SidebarGroup 放扁平主導覽(SidebarMenu),下方 SidebarGroup 放 user data(TreeView)。icon 模式下,扁平區顯示 icon(hover tooltip 需 per-button 傳 `tooltip` prop),TreeView 整段隱藏。
|
|
195
195
|
|
|
196
196
|
---
|
|
197
197
|
|
|
@@ -241,7 +241,7 @@ Gmail / Linear 的標準版型:上方 SidebarGroup 放扁平主導覽(Sideba
|
|
|
241
241
|
|
|
242
242
|
### Chrome 內容的約束
|
|
243
243
|
|
|
244
|
-
放在 SidebarHeader
|
|
244
|
+
放在 SidebarHeader(固定高度 `--chrome-header-height`)裡的元件必須能容納在這個高度內(**SidebarFooter 為 content-based,高度隨內容 flex、不受此固定高度約束**):
|
|
245
245
|
|
|
246
246
|
- 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」段。
|
|
247
247
|
- Button: `size="sm"` 或 `size="md"`
|
|
@@ -487,9 +487,9 @@ variant=meta 把這三件事做成結構性保證:樣式自動退、selection
|
|
|
487
487
|
|
|
488
488
|
## Single selection(整個 sidebar 同時只有一個 active item)
|
|
489
489
|
|
|
490
|
-
|
|
490
|
+
**規則(UX 語意)**:不論 MainNav / TreeView / Favorites / 任何 group,**同一時間只有一個 item 被選中**——sidebar 的核心語意是「當下在哪頁」,多個 active 就失去意義。
|
|
491
491
|
|
|
492
|
-
|
|
492
|
+
**結構性保證(範圍 = `SidebarMenuButton`)**:`SidebarProvider` 內建 single-selection state,`SidebarMenuButton` 接 `id` prop 自動從 context 讀 `isActive`、自動在 `onClick` 呼叫 `setActiveId`。**此結構保證僅涵蓋 `SidebarMenuButton`**:`TreeView` 用自己獨立的 `selectedIds` state、不接 `SidebarContext`,**沒有元件層級的 cross-family auto-deselect**——跨 TreeView 的單選需 consumer 用同一份 `activeId` state 手動橋接(SidebarMenu 與 TreeView 都讀寫同一個 state,見 principles『啟用狀態跨群組單一』story)。
|
|
493
493
|
|
|
494
494
|
```tsx
|
|
495
495
|
// Controlled(router-driven,typical production 用法)
|
|
@@ -539,7 +539,7 @@ Consumer 不需要任何額外 code——只要加一個 prop:
|
|
|
539
539
|
- ❌ 主導覽 group(永遠要看見)
|
|
540
540
|
- ❌ 只有 1-2 個 item 的 group(收合徒增互動成本)
|
|
541
541
|
|
|
542
|
-
**為什麼 prop 放在 `SidebarGroup` 而非 `SidebarGroupLabel`**:「是否可收合」是結構層決定,影響 label(
|
|
542
|
+
**為什麼 prop 放在 `SidebarGroup` 而非 `SidebarGroupLabel`**:「是否可收合」是結構層決定,影響 label 尾端 chevron button(是否為 `Collapsible.Trigger`)+ content(是否被 `Collapsible.Content` 包)兩個 primitive(label 本身維持 `role="presentation"` div,不升格為 button)。放在 label 上會讓 content 不知道該不該被 `Collapsible.Content` 包,形成 prop drilling。group 層用 React context 傳遞是標準做法。
|
|
543
543
|
|
|
544
544
|
---
|
|
545
545
|
|
|
@@ -594,7 +594,9 @@ Consumer 不需要任何額外 code——只要加一個 prop:
|
|
|
594
594
|
|
|
595
595
|
## Mobile 行為
|
|
596
596
|
|
|
597
|
-
`md` breakpoint(768px
|
|
597
|
+
`md` breakpoint(768px)以下,`collapsible="offcanvas"`(預設)/ `"icon"` 自動切 **Sheet 抽屜**——從側邊滑入、覆蓋主內容、點外部或 Esc 關閉。Sheet 寬度用 `--sidebar-width-mobile`,**mobile 沒有 icon 模式**(細列在手機上既占空間又難點)。
|
|
598
|
+
|
|
599
|
+
**例外 — `collapsible="none"`**:`none` 分支在 tsx 於 `isMobile` 判斷**之前**提前 return 固定寬度 `--sidebar-width` div,**不進 Sheet**。故 mobile + `collapsible="none"` 會維持固定 240px 側欄(第三種狀態),非「一律 Sheet」。需 mobile Sheet 行為請用 `offcanvas` 或 `icon`。
|
|
598
600
|
|
|
599
601
|
Sheet 開啟狀態**不持久化**。
|
|
600
602
|
|
|
@@ -616,7 +618,7 @@ Sheet 開啟狀態**不持久化**。
|
|
|
616
618
|
| Token | 預設值 | 用途 |
|
|
617
619
|
|-------|--------|------|
|
|
618
620
|
| `--sidebar-width` | `15rem` (240px) | 展開寬度(2026-05-21 v11 user 拍板 240px;對齊 Linear/Notion/Figma/Polaris/Material Drawer 主流 240–256,5/8 家 = 240。也是 `--sidebar-width-min` AppShell Aside floor 共識值)|
|
|
619
|
-
| `--sidebar-width-icon` | `calc(2 * var(--layout-space-loose) + var(--sidebar-menu-icon-size))` | icon 模式寬度(2026-05-21 v3 撤回 `3rem` hardcode,改 geometry formula 保證 icon center x = loose + icon/2
|
|
621
|
+
| `--sidebar-width-icon` | `calc(2 * var(--layout-space-loose) + var(--sidebar-menu-icon-size))` | icon 模式寬度(2026-05-21 v3 撤回 `3rem` hardcode,改 geometry formula 保證 icon center x = loose + icon/2 在展開/收合一致;**md = 2×16+16 = 48 / lg = 2×24+20 = 68**,跟 chrome-header-height 解耦)|
|
|
620
622
|
| `--sidebar-menu-icon-size` | `1rem` (16px) | sidebar menu icon 大小(per ICON_SIZE.sm/md=16);size=lg 罕見 case override `1.25rem` |
|
|
621
623
|
| `--sidebar-width-mobile` | `18rem` | Mobile sheet 寬度 |
|
|
622
624
|
|
|
@@ -671,10 +673,6 @@ Collapsible:內容優先低頻導覽 → offcanvas;扁平高頻切換 → ic
|
|
|
671
673
|
|
|
672
674
|
---
|
|
673
675
|
|
|
674
|
-
## 為何無 Inspector
|
|
675
|
-
|
|
676
|
-
Sidebar 的決策維度是「結構配置」(variant / collapsible / uniformPrefix / density)不是單一 prop——已由 `Overview`(結構樹)+ `SizeMatrix` + `ColorMatrix` + `StateBehavior` + `ChromeTokens` 五 story 完整覆蓋。互動 Inspector 切單一 prop 不如結構對照,且 Sidebar 外觀需要足夠的 nav 量才能展示——真實展示是 `Overview` 的 SidebarPreview 完整結構。
|
|
677
|
-
|
|
678
676
|
## StateBehavior(Sidebar 層級特有)
|
|
679
677
|
|
|
680
678
|
Item-level default / hover / selected / disabled **色彩**完全共用 item-anatomy row primitive(`patterns/element-anatomy/item-anatomy.spec.md`),由 `ColorMatrix` 用 4 個 state 的完整 token 對照表承載(state-driven 色彩表)。SidebarMenuButton(獨立 cva)無 `:active` press state——對齊 MenuItem / TreeItem 同族 row-button,`--neutral-active` 僅由 inline-action 子按鈕消費(item-anatomy.tsx group-active/action),menu button 本體不套用。Sidebar 的 `StateBehavior` story 則展示 **container 層級的結構狀態切換**:三種 `collapsible` 模式(offcanvas / icon / none)、Cmd+B / SidebarTrigger toggle、icon mode 下 label 隱藏 + Tooltip 代償、跨 session cookie 還原——這些是 shell 層級特有的行為,不存在於 row item primitive。
|
|
@@ -687,8 +685,8 @@ Item-level default / hover / selected / disabled **色彩**完全共用 item-ana
|
|
|
687
685
|
- **Active item**:`SidebarMenuButton` 帶 `id` + 命中 `activeId` 時自動加 `data-active="true"`,呈現選取底色(`bg-neutral-selected`)。**目前僅視覺 + `data-active` attribute,不設 `aria-current="page"`**——SR 讀不到「current page」語意。`variant="meta"` 永不參與 selection(`data-active` 永遠 false)。
|
|
688
686
|
- **快捷鍵不衝突**:`Cmd+B` / `Ctrl+B` 是 industry-standard(VS Code / Linear / shadcn),DS 內建在 `SidebarProvider` 的 `window` keydown handler,判斷 `key==="b" && (metaKey||ctrlKey)` 後 `preventDefault` + toggle,避免穿透到 browser bookmark bar(`Cmd+B` 在 Safari 是 favorites)。**三道 guard(2026-07-05 D4 修)**:(1) `defaultPrevented`——app 層 editor 已處理同快捷鍵時不 double-fire;(2) `isComposing`——IME 組字中不攔;(3) 可編輯 target——`<input>` / `<textarea>` / `contentEditable` 內按 `Cmd/Ctrl+B` 不 toggle(bold 等編輯語意優先,對齊 VS Code / Linear 快捷鍵讓位可編輯區慣例)。**目前無 opt-out prop**(無 `disableShortcut`)。
|
|
689
687
|
- **Collapsed accessible name(2026-07-05 D4 修)**:icon 模式 label 以 `sr-only` 視覺隱藏(非 display:none),SidebarMenuButton 對 SR 保留 accessible name(WCAG 4.1.2);Tooltip 僅 hover 提示、不供名;badge / inline actions 仍 display:none(補充資訊,供名責任在 label)。
|
|
690
|
-
- **Mobile sheet focus trap**:`md` breakpoint 以下切 Sheet 模式時,Radix Dialog 自帶 focus trap + Esc dismiss
|
|
691
|
-
- **Collapsible group**:`<SidebarGroup collapsible>`
|
|
688
|
+
- **Mobile sheet focus trap**:`md` breakpoint 以下切 Sheet 模式時,Radix Dialog 自帶 focus trap + Esc dismiss(詳 sheet.spec.md)。**關閉焦點還原**:mobile Sheet **無顯式 `<SheetTrigger>`**(open state 由外部 `SidebarTrigger` → `setOpenMobile` 控制,非 Radix DialogTrigger),故關閉後焦點還原走 Radix FocusScope 預設(還原到開啟前的聚焦元素),**不保證**回到 `SidebarTrigger`;若需確定性還原,consumer 應把觸發 button 與 Sheet 綁成 `SheetTrigger`。
|
|
689
|
+
- **Collapsible group**:`<SidebarGroup collapsible>` 的**尾端 chevron button**(`Collapsible.Trigger asChild` 包 `ItemInlineActionButton`)帶 `aria-expanded` + `aria-controls` 指向 GroupContent id,SR 可朗讀展開狀態(label 本身維持 `role="presentation"`,不承載 aria-expanded)。
|
|
692
690
|
- **Sticky header / footer focus order**:Tab 順序按 DOM 順序 — Header → Content → Footer,SidebarTrigger 在 Pattern A/B 都位於 page top-left,Tab 第一站即可達。
|
|
693
691
|
- **不使用 `SidebarMenuSub`**:避免 nested menu aria-tree 複雜度,階層交給 TreeView(`role="tree"` + `aria-level`)。
|
|
694
692
|
|
|
@@ -700,7 +698,7 @@ Item-level default / hover / selected / disabled **色彩**完全共用 item-ana
|
|
|
700
698
|
- **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 -->
|
|
701
699
|
- **Empty(no nav items)**:罕見場景(用戶無權限 / 全空 workspace)。若整個 group 無 item,consumer 應 conditional 不渲該 group(不渲空 group label);若整個 sidebar 無 item,可能該 hide sidebar(走 layout context 不渲)。不渲空白 sidebar。
|
|
702
700
|
- **Dark mode / density**:Sidebar 為 chrome surface,走 chrome-header token 自動 adapt;density 預設 lock 跟隨 app density chrome token,不獨立 own。
|
|
703
|
-
- **Collapsed mode(icon-only)**:label / inline actions suffix 隱藏,只留 icon
|
|
701
|
+
- **Collapsed mode(icon-only)**:label / inline actions suffix 隱藏,只留 icon(hover tooltip 為 opt-in — 未傳 `tooltip` prop 的 collapsed button 無 hover 提示,collapsed 導覽 button 建議都傳 `tooltip`);TreeView 整區隱藏,重新看階層資料的唯一路徑 = 展開 sidebar(完整規則見「Icon 模式的行為規則」段)。
|
|
704
702
|
|
|
705
703
|
---
|
|
706
704
|
|
|
@@ -87,13 +87,14 @@ const UserFooter = () => (
|
|
|
87
87
|
<SidebarMenuButton asChild>
|
|
88
88
|
<div role="group" aria-label="當前使用者">
|
|
89
89
|
<ItemAvatar
|
|
90
|
+
src="https://i.pravatar.cc/48?u=EMP-1001"
|
|
90
91
|
alt="Alan Chen"
|
|
91
92
|
color="blue"
|
|
92
93
|
hoverCard={
|
|
93
94
|
<ProfileCard
|
|
94
95
|
name="Alan Chen"
|
|
95
96
|
subtitle="Design|D-0042|EMP-1001"
|
|
96
|
-
avatar={{ alt: 'Alan Chen', color: 'blue' }}
|
|
97
|
+
avatar={{ src: 'https://i.pravatar.cc/80?u=EMP-1001', alt: 'Alan Chen', color: 'blue' }}
|
|
97
98
|
status="online"
|
|
98
99
|
statusMessage="Out of Office: Back on Monday!"
|
|
99
100
|
actions={<ProfileCardDefaultActions />}
|
|
@@ -258,8 +259,9 @@ export const MixedContent: Story = {
|
|
|
258
259
|
</SidebarGroupContent>
|
|
259
260
|
</SidebarGroup>
|
|
260
261
|
|
|
261
|
-
{/* User data:TreeView,icon
|
|
262
|
-
`collapsible` 讓整個 group 可收合——label
|
|
262
|
+
{/* User data:TreeView,icon 模式整區隱藏(下方 group 手動加 group-data-[collapsible=icon]:hidden)。
|
|
263
|
+
`collapsible` 讓整個 group 可收合——label 尾端自動加 chevron button 作為
|
|
264
|
+
Collapsible.Trigger(label 本身維持 presentation div,不升格為 button),
|
|
263
265
|
content 用 Radix Collapsible 包起來。
|
|
264
266
|
群組之間的分隔線由 SidebarGroup 的 [&+&]:before 自動處理。 */}
|
|
265
267
|
<SidebarGroup collapsible className="group-data-[collapsible=icon]:hidden">
|
|
@@ -486,10 +488,9 @@ export const IntegrationSidebar: Story = {
|
|
|
486
488
|
}
|
|
487
489
|
description={
|
|
488
490
|
<>
|
|
489
|
-
<code className="text-caption px-1 bg-neutral-hover rounded">
|
|
490
|
-
{' '}
|
|
491
|
-
|
|
492
|
-
Raycast / Linear integrations 的混用模式。預設關閉(school A,explicit 立場)。
|
|
491
|
+
開啟 <code className="text-caption px-1 bg-neutral-hover rounded">uniformPrefix</code>
|
|
492
|
+
{' '}後,icon 導覽項與帶 logo 的整合項會對齊到同一條左緣,讓文字起點一致
|
|
493
|
+
(如 Notion / Raycast / Linear 的整合區)。預設關閉。
|
|
493
494
|
</>
|
|
494
495
|
}
|
|
495
496
|
/>
|