@qijenchen/design-system 0.1.0-beta.82 → 0.1.0-beta.84
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-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +607 -0
- package/dist/components/DataTable/data-table-filter-panel.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/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 +93 -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 +37 -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 +17 -5
- 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 +36 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +39 -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 +20 -0
- package/ds-canonical/fork/preamble.md +22 -18
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +9 -3
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +7 -0
- package/ds-canonical/fork/skills/performance-audit/SKILL.md +4 -2
- 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 +10 -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_benchmark_citation.sh +5 -3
- 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_ds_anchor_preflight.sh +17 -5
- 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 +36 -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_propose_without_benchmark.sh +6 -2
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +55 -0
- package/ds-canonical/hooks/check_story_determinism.sh +39 -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_benchmark_citation.sh +3 -3
- 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_fork_user_plugin_install.sh +3 -1
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +41 -2
- package/ds-canonical/hooks/tests/test_check_ssot_header_declaration.sh +72 -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/spec-rules.md +1 -1
- package/ds-canonical/rules/story-rules.md +2 -2
- package/ds-canonical/rules/ui-development.md +4 -2
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +9 -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 +57 -68
- 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 +5 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +27 -26
- 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 +2 -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 +7 -5
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
- package/ds-canonical/skills/performance-audit/SKILL.md +2 -2
- 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 +10 -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 +11 -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-panel.tsx +4 -1
- 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 +32 -12
- package/src/components/DataTable/data-table.stories.tsx +16 -17
- package/src/components/DataTable/data-table.tsx +103 -60
- 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/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 +14 -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 +27 -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 +584 -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 +3 -3
- 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.spec.md +1 -1
- package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
- package/src/tokens/utility-registry.json +160 -23
|
@@ -172,14 +172,14 @@ const SidebarProvider = React.forwardRef<
|
|
|
172
172
|
const setOpen = React.useCallback(
|
|
173
173
|
(value: boolean | ((value: boolean) => boolean)) => {
|
|
174
174
|
const openState = typeof value === "function" ? value(open) : value
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
// 受控/非受控分岔依「有沒有傳 open prop」判定(同上方 activeId pattern),
|
|
176
|
+
// 不依「有沒有傳 onOpenChange」——否則 uncontrolled + onOpenChange 場景
|
|
177
|
+
// internal state 永不更新,sidebar 凍結(同 SelectMenu R2 已修 bug class)。
|
|
178
|
+
if (openProp === undefined) _setOpen(openState)
|
|
179
|
+
setOpenProp?.(openState)
|
|
180
180
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
|
181
181
|
},
|
|
182
|
-
[setOpenProp, open]
|
|
182
|
+
[openProp, setOpenProp, open]
|
|
183
183
|
)
|
|
184
184
|
|
|
185
185
|
const toggleSidebar = React.useCallback(() => {
|
|
@@ -306,6 +306,10 @@ const Sidebar = React.forwardRef<
|
|
|
306
306
|
* 從該值起算(`top: viewportInsetTop / height: calc(100svh - viewportInsetTop)`),
|
|
307
307
|
* 讓 global header 不被覆蓋(AppShell primary-header mode 必傳)。
|
|
308
308
|
* 對齊 Mantine `layout="default"` navbar 高度扣 header 慣例。
|
|
309
|
+
*
|
|
310
|
+
* ⚠️ 作用範圍:**僅桌機 `offcanvas` / `icon` 分支**套用 insetStyle。
|
|
311
|
+
* `collapsible="none"`(於 isMobile 前提前 return 固定 div)與 mobile Sheet
|
|
312
|
+
* 兩分支不套此 inset —— 該兩模式下 global header 仍會被覆蓋(未接線)。
|
|
309
313
|
*/
|
|
310
314
|
viewportInsetTop?: string
|
|
311
315
|
}
|
|
@@ -471,13 +475,15 @@ SidebarInput.displayName = "SidebarInput"
|
|
|
471
475
|
|
|
472
476
|
// ── Shell regions ──────────────────────────────────────────────────────────
|
|
473
477
|
|
|
474
|
-
// SidebarHeader
|
|
475
|
-
// -
|
|
476
|
-
//
|
|
478
|
+
// SidebarHeader(固定高度 chrome slot)vs SidebarFooter(content-based):
|
|
479
|
+
// - SidebarHeader:固定高度 `var(--chrome-header-height)`(md=48 / lg=56,density-responsive),
|
|
480
|
+
// 跨元件 chrome header 共享同一個 token,自動跟主內容 page header 對齊
|
|
481
|
+
// - SidebarFooter:高度由內容決定(`shrink-0 py-2 border-t`,不消費 chrome-header-height、
|
|
482
|
+
// 無自身固定高度),見下方 SidebarFooter 定義的 docblock + spec「Chrome 內容的約束」段
|
|
477
483
|
// - 水平 padding 用 loose token(跟 items 的 px 對齊)
|
|
478
484
|
// - 邊框是結構邊界(分隔 fixed/scroll 區),full-width 不內縮
|
|
479
485
|
//
|
|
480
|
-
// 為什麼 density-responsive:chrome 裡放的 button 綁定 field-height token,
|
|
486
|
+
// 為什麼 Header density-responsive:chrome 裡放的 button 綁定 field-height token,
|
|
481
487
|
// 會隨 density 變大。Chrome 如果不跟著放大,lg density 下 padding 會被擠壓。
|
|
482
488
|
const SidebarHeader = React.forwardRef<
|
|
483
489
|
HTMLDivElement,
|
|
@@ -516,10 +522,11 @@ const SidebarHeader = React.forwardRef<
|
|
|
516
522
|
// JS 端透過 WorkspaceBrand RowSizeProvider value="md"
|
|
517
523
|
// + AVATAR_SIZE.inline.md spec-coupled 共識 sync。
|
|
518
524
|
//
|
|
519
|
-
//
|
|
520
|
-
// md density: (48-24)/2 = 12
|
|
521
|
-
// lg
|
|
522
|
-
//
|
|
525
|
+
// Collapsed pl 幾何值(rail-centered,--sidebar-width-icon = 2*loose + menu-icon):
|
|
526
|
+
// md density: (48-24)/2 = 12 · lg density: (68-24)/2 = 22
|
|
527
|
+
// (lg width = 2×24+20 = 68,非 stale 64;avatar-size = 24 both densities)
|
|
528
|
+
// 註:已撤回的 v13 `loose-4` 近似在 lg 給 20,與新 rail-幾何精確值 22 不同 —
|
|
529
|
+
// v14 以 SSOT chain 公式取代該近似,md 兩者恰好都是 12。
|
|
523
530
|
"group-data-[collapsible=icon]:!pl-[calc((var(--sidebar-width-icon)-var(--chrome-header-avatar-size))/2)]",
|
|
524
531
|
"group-data-[collapsible=icon]:!pr-0",
|
|
525
532
|
"transition-[padding] duration-200 ease-linear motion-reduce:duration-0",
|
|
@@ -602,8 +609,9 @@ SidebarContent.displayName = "SidebarContent"
|
|
|
602
609
|
// ── Group ──────────────────────────────────────────────────────────────────
|
|
603
610
|
|
|
604
611
|
// SidebarGroupContext——讓 `SidebarGroupLabel` 和 `SidebarGroupContent` 知道當前
|
|
605
|
-
// 所在的 group 是否 collapsible,以自動切換渲染模式(label
|
|
606
|
-
// `Collapsible.
|
|
612
|
+
// 所在的 group 是否 collapsible,以自動切換渲染模式(label 尾端 chevron button 變
|
|
613
|
+
// `Collapsible.Trigger`、content 變 `Collapsible.Content`;label 本身維持
|
|
614
|
+
// `role="presentation"` div,不升格為 button)。沒有 context 就是舊行為(plain div)。
|
|
607
615
|
type SidebarGroupContextValue = {
|
|
608
616
|
collapsible: boolean
|
|
609
617
|
}
|
|
@@ -617,13 +625,14 @@ function useSidebarGroup() {
|
|
|
617
625
|
* SidebarGroup
|
|
618
626
|
*
|
|
619
627
|
* 預設是非互動的 plain group(div)。當 `collapsible` = true 時自動切換成 Radix
|
|
620
|
-
* Collapsible:SidebarGroupLabel
|
|
621
|
-
*
|
|
628
|
+
* Collapsible:SidebarGroupLabel 尾端自動渲染 chevron button 作為 `Collapsible.Trigger`
|
|
629
|
+
* (承載 aria-expanded / data-state,依 open state 旋轉),SidebarGroupContent 變 Content;
|
|
630
|
+
* label 本身維持 `role="presentation"` div,不升格為 button。
|
|
622
631
|
*
|
|
623
632
|
* ── API 設計決策 ──
|
|
624
633
|
* 為什麼是 group 層級的 prop 而不是 label 層級?因為「group 是否可收合」是結構層
|
|
625
|
-
* 的決定,影響 group
|
|
626
|
-
* animated container)。把 prop 放在 label 上會讓 content 不知道自己該不該被包,
|
|
634
|
+
* 的決定,影響 group 子 primitive 的渲染模式(label 尾端 chevron 變 trigger button、
|
|
635
|
+
* content 變 animated container)。把 prop 放在 label 上會讓 content 不知道自己該不該被包,
|
|
627
636
|
* 形成跨元件的 prop drilling。放在 group 上用 context 傳遞是 React 的標準做法。
|
|
628
637
|
*/
|
|
629
638
|
const SidebarGroup = React.forwardRef<
|
|
@@ -667,8 +676,10 @@ const SidebarGroup = React.forwardRef<
|
|
|
667
676
|
open={open}
|
|
668
677
|
onOpenChange={onOpenChange}
|
|
669
678
|
className={baseClass}
|
|
670
|
-
// Collapsible
|
|
671
|
-
//
|
|
679
|
+
// 註:此 Collapsible.Root 本身**不**自帶 icon 模式隱藏 class(baseClass 無
|
|
680
|
+
// `group-data-[collapsible=icon]:hidden`),icon 模式下預設仍渲染。若要在 icon rail
|
|
681
|
+
// 隱藏整個可收合 group(icon rail 沒空間放展開的 tree),consumer 自行傳
|
|
682
|
+
// `className="group-data-[collapsible=icon]:hidden"` 覆寫。
|
|
672
683
|
{...(props as React.ComponentProps<typeof CollapsiblePrimitive.Root>)}
|
|
673
684
|
>
|
|
674
685
|
{children}
|
|
@@ -872,9 +883,10 @@ SidebarMenuItem.displayName = "SidebarMenuItem"
|
|
|
872
883
|
* - hover: bg-neutral-hover
|
|
873
884
|
* - selected: bg-neutral-selected(data-active=true)
|
|
874
885
|
*
|
|
875
|
-
* Icon 模式:button 保持 w-full 填滿 sidebar icon rail
|
|
876
|
-
*
|
|
877
|
-
*
|
|
886
|
+
* Icon 模式:button 保持 w-full 填滿 sidebar icon rail,**無 height lock / 無 justify-center**
|
|
887
|
+
* (2026-05-21 v4 C* 撤回 `!h-[...]`——row height 永遠 stable,collapsed 只 outer clip);
|
|
888
|
+
* prefix(icon / avatar)靠 `!pl-[calc((rail - prefix-width)/2)]` 公式置中對齊 rail,
|
|
889
|
+
* label span 以 sr-only 視覺隱藏(a11y tree 保留,2026-07-05 D4——SR 仍讀得到 accessible name)。
|
|
878
890
|
*/
|
|
879
891
|
const sidebarMenuButtonVariants = cva(
|
|
880
892
|
[
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
-
// @story-baseline: packages/design-system/src/components/DataTable/data-table.stories.tsx#
|
|
2
|
+
// @story-baseline: packages/design-system/src/components/DataTable/data-table.anatomy.stories.tsx#AlignmentRule
|
|
3
3
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
4
4
|
import type { ColumnDef } from '@tanstack/react-table'
|
|
5
5
|
import { Skeleton } from './skeleton'
|
|
@@ -21,16 +21,9 @@ const meta: Meta = {
|
|
|
21
21
|
export default meta
|
|
22
22
|
type Story = StoryObj
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<div className="flex flex-col gap-2 max-w-md">
|
|
28
|
-
<Skeleton className="h-4 w-full" />
|
|
29
|
-
<Skeleton className="h-4 w-full" />
|
|
30
|
-
<Skeleton className="h-4 w-3/4" />
|
|
31
|
-
</div>
|
|
32
|
-
),
|
|
33
|
-
}
|
|
24
|
+
// Default retired 2026-07-14 per audit Dim 24(story 重複性):「預設」的三行文字骨架
|
|
25
|
+
// pattern 與 DocumentLoading 段落骨架完全同構,且抽象「預設」違「範例必真實業務場景」;
|
|
26
|
+
// 由 UserProfileCard / TaskListLoading / DocumentLoading 等真實情境 story 覆蓋。
|
|
34
27
|
|
|
35
28
|
export const UserProfileCard: Story = {
|
|
36
29
|
name: '個人資料卡載入',
|
|
@@ -39,7 +39,7 @@ export const Overview: Story = {
|
|
|
39
39
|
{[
|
|
40
40
|
['value / defaultValue', 'number[]', '—', '[single] 或 [min, max] range mode'],
|
|
41
41
|
['onValueChange', '(value: number[]) => void', '—', '拖曳中每次值變動'],
|
|
42
|
-
['onValueCommit', '(value: number[]) => void', '—', '
|
|
42
|
+
['onValueCommit', '(value: number[]) => void', '—', '互動結束觸發:滑鼠放開,或鍵盤 Arrow/Page/Home/End 每次有效變更(防抖用)'],
|
|
43
43
|
['min / max', 'number', '0 / 100', '值範圍'],
|
|
44
44
|
['step', 'number', '1', '步進'],
|
|
45
45
|
['size', "'sm' | 'md' | 'lg'", "'md'", '**只影響容器外高**,不影響 track/thumb 尺寸'],
|
|
@@ -175,8 +175,8 @@ export const ColorBindingRule: Story = {
|
|
|
175
175
|
render: () => (
|
|
176
176
|
<div className="flex flex-col gap-8">
|
|
177
177
|
<div>
|
|
178
|
-
<H3>Range 色和 Thumb border
|
|
179
|
-
<Desc>Thumb 坐落在 range 的端點上,border 是 range 的視覺延續。兩者同色時看起來像「range 包住 thumb」——thumb 白底是「被 range 圍住的空心洞」,而不是「thumb 浮在 range
|
|
178
|
+
<H3>Range 色和 Thumb border 色在 rest / disabled 兩態同 token</H3>
|
|
179
|
+
<Desc>Thumb 坐落在 range 的端點上,border 是 range 的視覺延續。兩者同色時看起來像「range 包住 thumb」——thumb 白底是「被 range 圍住的空心洞」,而不是「thumb 浮在 range 上面的異物」。<strong>互動態(hover / active / focus)只動 thumb border 色階</strong>(hover / focus 升 primary-hover、active 深至 primary-active),Range 填色恆 primary — 下表只列 rest / disabled 兩態的綁定。</Desc>
|
|
180
180
|
<div className="overflow-x-auto">
|
|
181
181
|
<table className="text-caption border-collapse">
|
|
182
182
|
<thead><tr><Th>State</Th><Th>Range bg</Th><Th>Thumb border</Th><Th>共享 token</Th></tr></thead>
|
|
@@ -148,8 +148,8 @@ export const PositionAsStateRule: Story = {
|
|
|
148
148
|
</Rule>
|
|
149
149
|
|
|
150
150
|
<Rule
|
|
151
|
-
title="對照 Switch:必須用 opacity(
|
|
152
|
-
note="Switch 的 on/off
|
|
151
|
+
title="對照 Switch:必須用 opacity(顏色是主要 state 載體)"
|
|
152
|
+
note="Switch 的 on/off 主要靠顏色(track bg-primary vs bg-border)承載——thumb 位移與 checked 勾號只是輔助訊號,單獨一顆、無左右對照時不易讀。若灰階 swap,disabled 的 ON 和 OFF track 同灰、主通道消失,使用者難以分辨。必須 opacity 保留顏色"
|
|
153
153
|
>
|
|
154
154
|
<div className="flex items-center gap-4">
|
|
155
155
|
<div className="flex items-center gap-2">
|
|
@@ -123,7 +123,7 @@ Slider 不是 button——它是「當前位置指示器」,底色不該動(動
|
|
|
123
123
|
value={number[]} // controlled
|
|
124
124
|
defaultValue={number[]} // uncontrolled
|
|
125
125
|
onValueChange={(value) => void}
|
|
126
|
-
onValueCommit={(value) => void} //
|
|
126
|
+
onValueCommit={(value) => void} // 互動結束觸發:滑鼠放開,或鍵盤 Arrow/Page/Home/End 每次有效變更
|
|
127
127
|
min={number} // 預設 0
|
|
128
128
|
max={number} // 預設 100
|
|
129
129
|
step={number} // 預設 1
|
|
@@ -186,18 +186,18 @@ Radix Slider 原生支援多 thumb——只要 `value` / `defaultValue` 傳長
|
|
|
186
186
|
|
|
187
187
|
**Slider 用灰階不用 opacity**。這是系統內重要的判準,反覆確認後的結論——系統有兩個 disabled 處理派別,Slider 屬於**灰階派**(跟 Button / Checkbox 同家族)。判準比「多色彩 vs 單色彩」更精準,是:
|
|
188
188
|
|
|
189
|
-
### 判準:**顏色是否是 semantic state
|
|
189
|
+
### 判準:**顏色是否是 semantic state 的主載體?**
|
|
190
190
|
|
|
191
191
|
| 元件 | 顏色的角色 | State 載體 | Disabled 策略 |
|
|
192
192
|
|---|---|---|---|
|
|
193
|
-
| **Switch** | `bg-primary` vs `bg-border` 是 on/off
|
|
193
|
+
| **Switch** | `bg-primary` vs `bg-border` 是 on/off 的**最強視覺差異**(thumb 位移與 check icon 只是弱輔助線索,灰階低對比下難辨——見 switch.spec.md「Disabled 用 opacity」)| **顏色是 state 主載體** | **`opacity-disabled`** — 必須保留色彩身分,否則灰階後狀態區辨大幅下降 |
|
|
194
194
|
| **Checkbox** | 勾了有 checkmark,沒勾沒 checkmark——**形狀**決定 state,顏色只是美學 | **形狀(checkmark)** | **灰階 swap**(`bg-disabled`)— 灰色框裡的 checkmark 仍清楚可辨 |
|
|
195
195
|
| **Button** | Primary 色是品牌美學,不是 state | — | **灰階 swap** |
|
|
196
196
|
| **Slider** | Range 藍色是「已選長度」的美學視覺,**位置 + 長度是 state**,顏色只是裝飾 | **位置(thumb)+ 長度(range 佔比)** | **灰階 swap** — 灰色 range 跟灰色 thumb 的位置/長度仍然完全可辨 |
|
|
197
197
|
|
|
198
198
|
### 論證摘要
|
|
199
199
|
|
|
200
|
-
Disabled slider 要傳達的兩件事——thumb 位置、range 長度——**完全不依賴顏色**(灰階後 x 座標與填滿佔比一模一樣),失去藍色零資訊損失,故走灰階派(同 Checkbox:state 由形狀 / 位置承載、顏色是裝飾)。Switch 是唯一 opacity 特例:on/off
|
|
200
|
+
Disabled slider 要傳達的兩件事——thumb 位置、range 長度——**完全不依賴顏色**(灰階後 x 座標與填滿佔比一模一樣),失去藍色零資訊損失,故走灰階派(同 Checkbox:state 由形狀 / 位置承載、顏色是裝飾)。Switch 是唯一 opacity 特例:on/off 的主載體是顏色(thumb 位移 / check icon 只是弱輔助線索),灰階會讓兩態近乎無法區分——此 rationale 不適用 Slider。
|
|
201
201
|
|
|
202
202
|
### 為什麼 shadcn / Material 3 用 opacity 仍然不是理由
|
|
203
203
|
|
|
@@ -236,7 +236,7 @@ Slider 無獨立 `readOnly` prop;但在 `<Field mode="readonly">` 內(2026-06-12
|
|
|
236
236
|
|
|
237
237
|
- 「Slider 可以當計數器」——錯。Slider 傳達 position(在哪裡),計數(多少)用 NumberInput ±step(見「何時不用」)
|
|
238
238
|
- 「兩個選項可以用 Range mode」——錯。Range 是連續值區間(value = [start, end]),二元 / 布林選擇用 Switch / SegmentedControl
|
|
239
|
-
- 「focus 要加 ring」——本元件 documented 例外:focus 用 border
|
|
239
|
+
- 「focus 要加 ring」——本元件 documented 例外:focus 用 border 升 hover 階(`primary-hover`,淺一階 lift;同 hover 視覺),不加 ring / halo(見「視覺規格」表,對齊上方「為什麼 hover / active 用陰影不用色變」)
|
|
240
240
|
|
|
241
241
|
---
|
|
242
242
|
|
|
@@ -107,7 +107,9 @@ const Slider = React.forwardRef<
|
|
|
107
107
|
Range 是「填充視覺」,Thumb border 是「thumb 的輪廓線」——視覺上 thumb
|
|
108
108
|
的 border 剛好是 range 的延續(thumb 坐落在 range 的端點上,border 跟
|
|
109
109
|
range 在色彩上融為一體,看起來像「range 包住 thumb」而不是「thumb 浮在
|
|
110
|
-
range 上」)。兩個 token
|
|
110
|
+
range 上」)。兩個 token 綁在一起 —— **同色綁定 scope = rest 與 disabled 兩態**;
|
|
111
|
+
互動態(hover/active/focus)只動 thumb border 色階,range 填色恆 primary
|
|
112
|
+
(詳下方 Thumb 註解 2026-07-06 retract)。
|
|
111
113
|
*/}
|
|
112
114
|
<SliderPrimitive.Range
|
|
113
115
|
className={cn(
|
|
@@ -39,7 +39,7 @@ export const Overview: Story = {
|
|
|
39
39
|
<tr><Td>completed</Td><Td><span className="inline-flex items-center gap-1.5"><Swatch value="--info" size="sm" /><span>filled info + white check icon</span></span></Td><Td><TokenCell token="--fg-secondary" display="fg-secondary" /></Td><Td><TokenCell token="--info" display="bg-info" /></Td></tr>
|
|
40
40
|
<tr><Td>current(= value)</Td><Td><span className="inline-flex items-center gap-1.5"><Swatch value="--info" size="sm" /><span>filled info + white number + ring</span></span></Td><Td><TokenCell token="--foreground" display="foreground" /></Td><Td><TokenCell token="--border" display="bg-border" /></Td></tr>
|
|
41
41
|
<tr><Td>upcoming</Td><Td><span className="inline-flex items-center gap-1.5"><Swatch value="--muted" size="sm" /><span>filled muted + fg-disabled number</span></span></Td><Td><TokenCell token="--fg-secondary" display="fg-secondary" /></Td><Td><TokenCell token="--border" display="bg-border" /></Td></tr>
|
|
42
|
-
<tr><Td>error</Td><Td><span className="inline-flex items-center gap-1.5"><Swatch value="--error" size="sm" /><span>bg-error + white icon</span></span></Td><Td><TokenCell token="--error-text" display="error-text" /></Td><Td
|
|
42
|
+
<tr><Td>error</Td><Td><span className="inline-flex items-center gap-1.5"><Swatch value="--error" size="sm" /><span>bg-error + white icon</span></span></Td><Td><TokenCell token="--error-text" display="error-text" /></Td><Td><TokenCell token="--border" display="bg-border" /></Td></tr>
|
|
43
43
|
</tbody>
|
|
44
44
|
</table>
|
|
45
45
|
</div>
|
|
@@ -185,7 +185,7 @@ export const ColorMatrix: Story = {
|
|
|
185
185
|
<Td mono>completed</Td>
|
|
186
186
|
<Td><TokenCell token="--info" /></Td>
|
|
187
187
|
<Td>—(同 bg)</Td>
|
|
188
|
-
<Td><TokenCell token="
|
|
188
|
+
<Td><TokenCell token="--on-emphasis" display="白色 Check icon" /></Td>
|
|
189
189
|
<Td><TokenCell token="--fg-secondary" /></Td>
|
|
190
190
|
<Td><TokenCell token="--info" display="bg-info" /></Td>
|
|
191
191
|
</tr>
|
|
@@ -209,9 +209,9 @@ export const ColorMatrix: Story = {
|
|
|
209
209
|
<Td mono>error</Td>
|
|
210
210
|
<Td><TokenCell token="--error" /></Td>
|
|
211
211
|
<Td>—(同 bg)</Td>
|
|
212
|
-
<Td><TokenCell token="
|
|
212
|
+
<Td><TokenCell token="--on-emphasis" display="白色 X icon" /></Td>
|
|
213
213
|
<Td><TokenCell token="--error-text" /></Td>
|
|
214
|
-
<Td
|
|
214
|
+
<Td><TokenCell token="--border" display="bg-border" /></Td>
|
|
215
215
|
</tr>
|
|
216
216
|
</tbody>
|
|
217
217
|
</table>
|
|
@@ -263,7 +263,7 @@ export const LinearBackClickDoesNotMutate: Story = {
|
|
|
263
263
|
return (
|
|
264
264
|
<Section
|
|
265
265
|
title="點 completed step 只改 focus(value),不會自動取消完成狀態"
|
|
266
|
-
subtitle="Steps
|
|
266
|
+
subtitle="Steps 的進度狀態由 parent own(value 為 controlled / uncontrolled defaultValue 雙模),從不偷偷 mutate parent 的 completedValues。若應用層需要「使用者改錯了就 block 後續」,應由應用層自己從 completedValues 移除,Steps 內部絕不 auto-remove。"
|
|
267
267
|
>
|
|
268
268
|
<div className="flex flex-col gap-3 w-[360px]">
|
|
269
269
|
<p className="text-caption text-fg-secondary">
|
|
@@ -284,7 +284,7 @@ disabled > error > focused > default
|
|
|
284
284
|
|
|
285
285
|
### 為什麼 error label 要跟 indicator 同色
|
|
286
286
|
|
|
287
|
-
Steps 的 step 本身是「狀態載體」,跟 Field 的「label 只是欄位名,error 靠 help text 表達」不同。Steps 的 label 在視覺上屬於 indicator 的延伸資訊,兩者應該一起講故事:紅 ✕ indicator + 紅 label
|
|
287
|
+
Steps 的 step 本身是「狀態載體」,跟 Field 的「label 只是欄位名,error 靠 help text 表達」不同。Steps 的 label 在視覺上屬於 indicator 的延伸資訊,兩者應該一起講故事:紅 ✕ indicator + 紅 label 形成一致的 error visual language,讓使用者一眼看出這步出了什麼錯(description 不變色,見下段)。
|
|
288
288
|
|
|
289
289
|
這跟 `CLAUDE.md` 的「Label 永遠 foreground」原則不衝突——那是 Field 家族的規則(edit / readonly / disabled 三態的欄位容器)。Steps 是**進度指示器**不是**輸入容器**,label 色彩跟著 step state 走是正確做法。
|
|
290
290
|
|
|
@@ -38,14 +38,14 @@ export const Overview: Story = {
|
|
|
38
38
|
<thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
|
|
39
39
|
<tbody>
|
|
40
40
|
{[
|
|
41
|
-
['mode', "'edit' | 'display' | 'readonly' | 'disabled'", "'edit'", 'Field mode(默認 inherit Field context 或 edit);display 渲純展示
|
|
41
|
+
['mode', "'edit' | 'display' | 'readonly' | 'disabled'", "'edit'", 'Field mode(默認 inherit Field context 或 edit);display 渲純展示 勾/叉 icon,語意由 context 提供'],
|
|
42
42
|
['size', "'sm' | 'md' | 'lg'", "'md'", '對齊 field size tier(sm 跟 md 視覺相同)'],
|
|
43
43
|
['checked / defaultChecked', 'boolean', '—', 'ON/OFF 狀態(受控 / 非受控)'],
|
|
44
44
|
['onCheckedChange', '(checked: boolean) => void', '—', '切換 callback'],
|
|
45
45
|
['label', 'ReactNode', '—', 'inline label(Field context 內會被忽略)'],
|
|
46
46
|
['description', 'ReactNode', '—', 'inline description(與 label 搭配)'],
|
|
47
47
|
['disabled', 'boolean', 'false', '停用(opacity-disabled 保留顏色,見 spec)'],
|
|
48
|
-
['readOnly', 'boolean', 'false', 'standalone:鎖定互動視覺正常;Field 內:灰框 +
|
|
48
|
+
['readOnly', 'boolean', 'false', 'standalone:鎖定互動視覺正常;Field 內:灰框 + 勾/叉 icon(2026-06-12 拍板)'],
|
|
49
49
|
].map(([p, t, d, desc]) => (
|
|
50
50
|
<tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
|
|
51
51
|
))}
|
|
@@ -78,7 +78,7 @@ export const Inspector: InspectorStory = {
|
|
|
78
78
|
mode: {
|
|
79
79
|
control: 'radio',
|
|
80
80
|
options: ['edit', 'display', 'readonly', 'disabled'],
|
|
81
|
-
description: 'Field mode;display 渲純展示
|
|
81
|
+
description: 'Field mode;display 渲純展示 勾/叉 icon(語意由 context 提供)',
|
|
82
82
|
},
|
|
83
83
|
size: {
|
|
84
84
|
control: 'radio',
|
|
@@ -87,7 +87,7 @@ export const Inspector: InspectorStory = {
|
|
|
87
87
|
},
|
|
88
88
|
defaultChecked: { control: 'boolean', description: '預設 ON / OFF' },
|
|
89
89
|
disabled: { control: 'boolean', description: '停用(opacity-disabled 保留顏色)' },
|
|
90
|
-
readOnly: { control: 'boolean', description: '唯讀(standalone 視覺正常鎖互動;Field 內灰框 +
|
|
90
|
+
readOnly: { control: 'boolean', description: '唯讀(standalone 視覺正常鎖互動;Field 內灰框 + 勾/叉 icon)' },
|
|
91
91
|
label: { control: 'text', description: 'inline label(留空 → 只渲染 switch 本體)' },
|
|
92
92
|
description: { control: 'text', description: 'inline description(需搭配 label)' },
|
|
93
93
|
},
|
|
@@ -135,7 +135,7 @@ export const StateBehavior: Story = {
|
|
|
135
135
|
<div className="flex flex-col gap-8">
|
|
136
136
|
<div>
|
|
137
137
|
<H3>視覺狀態對照</H3>
|
|
138
|
-
<Desc>disabled 用 opacity-disabled 保留顏色(Switch 特例,見下「Disabled 策略」)。readonly:standalone 視覺正常鎖互動;Field 內灰框 +
|
|
138
|
+
<Desc>disabled 用 opacity-disabled 保留顏色(Switch 特例,見下「Disabled 策略」)。readonly:standalone 視覺正常鎖互動;Field 內灰框 + 勾/叉 icon。</Desc>
|
|
139
139
|
<div className="overflow-x-auto mb-4">
|
|
140
140
|
<table className="text-caption border-collapse">
|
|
141
141
|
<thead><tr><Th>State</Th><Th>Track</Th><Th>Thumb</Th><Th>Check icon</Th></tr></thead>
|
|
@@ -178,8 +178,8 @@ export const StateBehavior: Story = {
|
|
|
178
178
|
|
|
179
179
|
<div>
|
|
180
180
|
<H3>Disabled 策略:opacity 而非灰階 swap</H3>
|
|
181
|
-
<Desc>Switch 的 on/off
|
|
182
|
-
<p className="text-footnote text-fg-muted">對照 Checkbox / Slider 用灰階弱化(它們的形狀或位置本身就承載開 / 關狀態,不靠顏色),所以灰掉也看得出狀態;Switch
|
|
181
|
+
<Desc>Switch 的 on/off 視覺差異**最強載體是顏色**(track bg-primary vs bg-border)——thumb 位移與 check icon 只是弱輔助線索。若用灰階 swap(把 primary 換成 border),disabled 的 ON 和 OFF 只剩灰階低對比下的位置與小 icon 差異,難以一眼分辨當前狀態。必須保留顏色。</Desc>
|
|
182
|
+
<p className="text-footnote text-fg-muted">對照 Checkbox / Slider 用灰階弱化(它們的形狀或位置本身就承載開 / 關狀態,不靠顏色),所以灰掉也看得出狀態;Switch 的主載體是顏色,只能降透明度保留顏色。</p>
|
|
183
183
|
</div>
|
|
184
184
|
</div>
|
|
185
185
|
),
|
|
@@ -116,7 +116,7 @@ export const UsageGuidance: Story = {
|
|
|
116
116
|
|
|
117
117
|
<Rule
|
|
118
118
|
title="使用場景對照"
|
|
119
|
-
note="Readonly(standalone settings list):值重要、視覺不能弱化。表單 readonly = Field 內灰框 +
|
|
119
|
+
note="Readonly(standalone settings list):值重要、視覺不能弱化。表單 readonly = Field 內灰框 + 勾/叉 icon(2026-06-12 拍板);DataTable cell 非編輯態 = mode display。Disabled:外部條件造成暫時不可用(方案限制、權限不足)——傳達「現在用不到」"
|
|
120
120
|
>
|
|
121
121
|
<Label>兩者都不可切換、不在 tab order 內(standalone),機制不同:readonly 用 `pointer-events-none`(視覺正常);disabled 走 native `disabled` + `cursor-not-allowed`(降透明度)。Field 內 readonly 灰框則可聚焦(tabIndex=0)</Label>
|
|
122
122
|
</Rule>
|
|
@@ -132,7 +132,7 @@ export const DisabledOpacityRule: Story = {
|
|
|
132
132
|
<div>
|
|
133
133
|
<Rule
|
|
134
134
|
title="Switch disabled 用 opacity,不用灰階 swap"
|
|
135
|
-
note="Switch 的 on/off
|
|
135
|
+
note="Switch 的 on/off 最強視覺載體是顏色(track bg-primary vs bg-border);thumb 位移與 checked 小 check icon 是輔助線索。若灰階 swap(primary → border),disabled 的 ON/OFF 只剩灰階低對比下的位置與小 icon 差異,難以一眼分辨當前狀態"
|
|
136
136
|
>
|
|
137
137
|
<div className="grid grid-cols-2 gap-4">
|
|
138
138
|
<div className="border border-dashed border-divider rounded-md p-3">
|
|
@@ -164,9 +164,9 @@ export const DisabledOpacityRule: Story = {
|
|
|
164
164
|
|
|
165
165
|
<Rule
|
|
166
166
|
title="❌ 若 Switch 改用灰階 swap"
|
|
167
|
-
note="disabled ON 和 disabled OFF
|
|
167
|
+
note="disabled ON 和 disabled OFF 都會退成「灰 track + 灰 thumb」——殘餘線索只剩 thumb 位置與 thumb 內小 check icon,在灰階低對比下辨識度大幅下降,使用者難以一眼判斷被停用的開關當前是開還是關"
|
|
168
168
|
>
|
|
169
|
-
<Label warn>設計上禁止——Switch
|
|
169
|
+
<Label warn>設計上禁止——Switch 的 on/off 最強視覺載體是顏色(thumb 位置 / check icon 只是輔助線索),disabled 必須保留顏色</Label>
|
|
170
170
|
</Rule>
|
|
171
171
|
</div>
|
|
172
172
|
),
|
|
@@ -104,22 +104,22 @@ sm 和 md 視覺相同(純粹命名 mapping,讓消費者可直接傳同一
|
|
|
104
104
|
| ON | `bg-primary` | 白色 + 2px primary border | primary check |
|
|
105
105
|
| Disabled | 套 `opacity-disabled`(整體透明度降級) | 同 ON/OFF | 同 ON/OFF |
|
|
106
106
|
| Readonly(standalone)| 視覺同一般態 | 但 `pointer-events-none` + click guard + `aria-readonly` | — |
|
|
107
|
-
| Readonly(Field 內,2026-06-12 user 拍板)| 不渲染 toggle — 改渲染 `fieldWrapperStyles` readonly 灰框(= Input readonly 同源)+
|
|
107
|
+
| Readonly(Field 內,2026-06-12 user 拍板)| 不渲染 toggle — 改渲染 `fieldWrapperStyles` readonly 灰框(= Input readonly 同源)+ 勾/叉 icon(display 同款值語言) | role="switch" + aria-checked + aria-readonly + 可 focus | — |
|
|
108
108
|
|
|
109
109
|
### Disabled 用 `opacity`
|
|
110
110
|
|
|
111
111
|
**不用灰階 swap**——這是 Switch 的**特例**,跟 Checkbox / Button / Slider 的灰階策略不同。
|
|
112
112
|
|
|
113
|
-
**理由**:Switch 的 on/off
|
|
113
|
+
**理由**:Switch 的 on/off 視覺差異**最強載體是顏色**(track `bg-primary` vs `bg-border`)——thumb 位置(translate-x)與 thumb 內 check icon 雖有差異,但屬弱輔助線索。若用灰階 swap(把 primary 換成 border),disabled 的 ON 跟 OFF 只剩灰階下低對比的位置/小 icon 差異,辨識度大幅下降,使用者難以一眼分辨當前狀態。
|
|
114
114
|
|
|
115
115
|
**對照**:
|
|
116
116
|
- Checkbox disabled 可以灰階 swap——checkmark 形狀承載 state,顏色只是裝飾
|
|
117
117
|
- Slider disabled 可以灰階 swap——thumb 位置和 range 長度承載 state
|
|
118
|
-
- Switch disabled
|
|
118
|
+
- Switch disabled **必須保留顏色**——主載體是顏色,灰階後殘餘線索太弱,state 近乎失傳
|
|
119
119
|
|
|
120
120
|
詳細對照見 `../Slider/slider.spec.md`「Disabled 策略」節。
|
|
121
121
|
|
|
122
|
-
### Readonly vs Disabled(standalone;Field 內 readonly = 灰框 +
|
|
122
|
+
### Readonly vs Disabled(standalone;Field 內 readonly = 灰框 + 勾/叉 icon,見上方狀態表)
|
|
123
123
|
|
|
124
124
|
| | Readonly(standalone) | Disabled |
|
|
125
125
|
|---|---|---|
|
|
@@ -129,14 +129,14 @@ sm 和 md 視覺相同(純粹命名 mapping,讓消費者可直接傳同一
|
|
|
129
129
|
| Tab 焦點 | 不在 tab order | 不在 tab order |
|
|
130
130
|
| 用途 | settings list 鎖定呈現 | 外部條件造成不可操作 |
|
|
131
131
|
|
|
132
|
-
表單 readonly 呈現 = Field 內灰框 +
|
|
132
|
+
表單 readonly 呈現 = Field 內灰框 + 勾/叉 icon(2026-06-12 拍板);DataTable cell 非編輯態 = `mode="display"`(勾/叉 icon),皆非本表 standalone readonly。
|
|
133
133
|
|
|
134
134
|
### `mode` prop(Field mode,正交於 size)
|
|
135
135
|
|
|
136
136
|
`mode?: 'edit' | 'display' | 'readonly' | 'disabled'`(默認 inherit Field context 或 `'edit'`),對齊 `field-types.ts` FieldMode:
|
|
137
137
|
- `edit`(預設)— 可切換的 Switch。
|
|
138
|
-
- `display` — **純展示**:渲染
|
|
139
|
-
- `readonly` — **Field 內** = 灰框 +
|
|
138
|
+
- `display` — **純展示**:渲染 勾/叉 icon(非互動 Switch;true=Check / false=X,中性 foreground 色,SSOT = `../SelectionControl/boolean-value.tsx`),語意由 context(如 DataTable boolean cell 的行/列 header)提供,對齊 Carbon read-only / Input·Select·Textarea display mode 一致。<!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
139
|
+
- `readonly` — **Field 內** = 灰框 + 勾/叉 icon(消費 `fieldWrapperStyles` readonly,與 Input readonly 同一視覺語言;世界級:Salesforce output ✓ glyph / SAP 靜態文字 — readonly 下 boolean 是資料 value 非控件);**standalone** = 正常色鎖互動(settings list 場景)。
|
|
140
140
|
- `disabled` — 同上表「Readonly vs Disabled」(opacity 弱化);`mode='disabled'` 直傳與 `disabled` prop 等效(effectiveDisabled,2026-06-12)。
|
|
141
141
|
|
|
142
142
|
---
|
|
@@ -194,7 +194,7 @@ Switch 可透過 `label` / `description` props 內部直接渲染緊鄰文字:
|
|
|
194
194
|
|
|
195
195
|
- ❌ 用 Switch 做 form 內的同意 / 勾選——「我同意條款」是書面成立行為,用 Checkbox
|
|
196
196
|
- ❌ 把 Switch 當三態使用(例:「on / off / auto」)——用 RadioGroup / SegmentedControl
|
|
197
|
-
- ❌ 對 disabled 狀態用灰階 swap 而非 opacity——會讓 on/off
|
|
197
|
+
- ❌ 對 disabled 狀態用灰階 swap 而非 opacity——會讓 on/off 視覺近乎無法區分(見「Disabled 用 opacity」段)
|
|
198
198
|
- ❌ Switch 的 on/off 顯示「正在處理中」進度——用 Button + loading state
|
|
199
199
|
- ❌ 直接改動 track 顏色承載額外語意(例如 error 時改紅)——Switch 是單純布林,錯誤訊息放外部 help text
|
|
200
200
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @story-trait-rationale: hasSizes 由 anatomy.stories.tsx SizeMatrix / 狀態(States)story 的 md/lg 對照 owns size showcase;Default scenario 由 四模式(Modes) / 狀態(States) / 搭配標籤(WithLabel)等真實業務情境 story 覆蓋,不另開抽象 Default/AllSizes。
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
3
|
import { Switch } from './switch'
|
|
4
|
-
import { SelectionItem } from '@/design-system/components/SelectionControl/selection-item'
|
|
5
4
|
|
|
6
5
|
const meta: Meta<typeof Switch> = {
|
|
7
6
|
title: 'Design System/Components/Switch/展示',
|
|
@@ -23,7 +22,7 @@ export const Modes: Story = {
|
|
|
23
22
|
<div>
|
|
24
23
|
<h3 className="text-body font-bold text-foreground mb-2">display</h3>
|
|
25
24
|
<Switch mode="display" checked />
|
|
26
|
-
<p className="text-caption text-fg-muted mt-1">純視覺
|
|
25
|
+
<p className="text-caption text-fg-muted mt-1">純視覺 勾/叉 icon;語意由 context(如 DataTable 表頭 + 行標籤)提供,display 不暴露獨立 aria-label。需螢幕報讀器可讀請用 edit / readonly。</p>
|
|
27
26
|
</div>
|
|
28
27
|
<div>
|
|
29
28
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
@@ -70,7 +69,10 @@ export const States: Story = {
|
|
|
70
69
|
),
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
/* ──
|
|
72
|
+
/* ── 搭配標籤 ── */
|
|
73
|
+
// 2026-07-14 dim-68 修:原直用 internal <SelectionItem control={...}>(selection-item.spec.md
|
|
74
|
+
// 明定僅 Checkbox / RadioGroup 消費路徑;Switch 不在其中)→ 改公開 `<Switch label description>`
|
|
75
|
+
// (switch.spec.md「label / description 整合」canonical:label 左 / switch 右,自動 wire htmlFor)。
|
|
74
76
|
export const WithLabel: Story = {
|
|
75
77
|
name: '搭配標籤',
|
|
76
78
|
render: () => (
|
|
@@ -78,27 +80,10 @@ export const WithLabel: Story = {
|
|
|
78
80
|
{(['sm', 'md', 'lg'] as const).map(size => (
|
|
79
81
|
<div key={size}>
|
|
80
82
|
<p className="text-caption text-fg-muted mb-1">size="{size}"</p>
|
|
81
|
-
<div className="grid">
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
label="啟用通知"
|
|
86
|
-
description="接收電子郵件和推播通知"
|
|
87
|
-
htmlFor={`sw-${size}-a`}
|
|
88
|
-
/>
|
|
89
|
-
<SelectionItem
|
|
90
|
-
size={size}
|
|
91
|
-
control={<Switch id={`sw-${size}-b`} size={size} />}
|
|
92
|
-
label="自動更新"
|
|
93
|
-
htmlFor={`sw-${size}-b`}
|
|
94
|
-
/>
|
|
95
|
-
<SelectionItem
|
|
96
|
-
size={size}
|
|
97
|
-
control={<Switch id={`sw-${size}-c`} size={size} disabled />}
|
|
98
|
-
label="維護模式(管理員限定)"
|
|
99
|
-
htmlFor={`sw-${size}-c`}
|
|
100
|
-
disabled
|
|
101
|
-
/>
|
|
83
|
+
<div className="grid gap-2">
|
|
84
|
+
<Switch size={size} defaultChecked label="啟用通知" description="接收電子郵件和推播通知" />
|
|
85
|
+
<Switch size={size} label="自動更新" />
|
|
86
|
+
<Switch size={size} disabled label="維護模式(管理員限定)" />
|
|
102
87
|
</div>
|
|
103
88
|
</div>
|
|
104
89
|
))}
|
|
@@ -7,6 +7,7 @@ import { cn } from '@/lib/utils'
|
|
|
7
7
|
import type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'
|
|
8
8
|
import { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from '@/design-system/components/Field/field-context'
|
|
9
9
|
import { fieldWrapperStyles } from '@/design-system/components/Field/field-wrapper'
|
|
10
|
+
import { BooleanValueIcon } from '@/design-system/components/SelectionControl/boolean-value'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Switch — 開關控件
|
|
@@ -24,7 +25,7 @@ import { fieldWrapperStyles } from '@/design-system/components/Field/field-wrapp
|
|
|
24
25
|
* ON: track primary, thumb 白色 + 2px primary border + primary check icon
|
|
25
26
|
* disabled: opacity-disabled(整體透明度)
|
|
26
27
|
* readOnly(standalone): 視覺同一般態,但 pointer-events-none + aria-readonly
|
|
27
|
-
* readOnly(Field 內): 渲染 readonly 灰框 +
|
|
28
|
+
* readOnly(Field 內): 渲染 readonly 灰框 + 勾/叉 icon(2026-06-12 拍板,= Input readonly 同視覺語言)
|
|
28
29
|
*
|
|
29
30
|
* ── label / description / readOnly ──
|
|
30
31
|
* Switch 可以透過 `label` 和 `description` props 在元件內直接渲染緊鄰的文字,
|
|
@@ -45,7 +46,7 @@ import { fieldWrapperStyles } from '@/design-system/components/Field/field-wrapp
|
|
|
45
46
|
* readOnly 模式:
|
|
46
47
|
* <Switch readOnly checked={true} label="..." />
|
|
47
48
|
* standalone:視覺維持 ON/OFF 正確狀態,但無法互動、不在 tab order 內、寫入 aria-readonly。
|
|
48
|
-
* Field 內:渲染 readonly 灰框 +
|
|
49
|
+
* Field 內:渲染 readonly 灰框 + 勾/叉 icon(不渲染 toggle;見 forwardRef 內 readonly 分支)。
|
|
49
50
|
* 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。
|
|
50
51
|
*/
|
|
51
52
|
|
|
@@ -110,18 +111,18 @@ export interface SwitchProps
|
|
|
110
111
|
*/
|
|
111
112
|
description?: React.ReactNode
|
|
112
113
|
/**
|
|
113
|
-
* readonly 模式:standalone = 鎖定互動但維持 ON/OFF 視覺;Field 內 = 灰框 +
|
|
114
|
+
* readonly 模式:standalone = 鎖定互動但維持 ON/OFF 視覺;Field 內 = 灰框 + 勾/叉 icon。
|
|
114
115
|
* 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。
|
|
115
|
-
* DataTable cell 非編輯態用 mode="display"(
|
|
116
|
+
* DataTable cell 非編輯態用 mode="display"(勾/叉 icon),非 readOnly。
|
|
116
117
|
*/
|
|
117
118
|
readOnly?: boolean
|
|
118
119
|
/**
|
|
119
120
|
* Field mode(2026-05-05 Phase B3 align):
|
|
120
121
|
* edit — 一般可互動 Switch(預設)
|
|
121
|
-
* display — **純展示**:渲染
|
|
122
|
+
* display — **純展示**:渲染 勾/叉 icon(無互動 primitive、無 input chrome);
|
|
122
123
|
* 對齊 Carbon read-only / DataTable boolean cell。
|
|
123
124
|
* `display` 完全無 toggle 形體;`readonly` 視場景(field-types.ts)。
|
|
124
|
-
* readonly — standalone 同 readOnly prop(保留視覺鎖互動);Field 內 = 灰框 +
|
|
125
|
+
* readonly — standalone 同 readOnly prop(保留視覺鎖互動);Field 內 = 灰框 + 勾/叉 icon
|
|
125
126
|
* disabled — 同 disabled prop
|
|
126
127
|
*/
|
|
127
128
|
mode?: FieldMode
|
|
@@ -200,17 +201,20 @@ const Switch = React.forwardRef<
|
|
|
200
201
|
} = props
|
|
201
202
|
|
|
202
203
|
// ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────
|
|
203
|
-
// 純展示模式:無互動 toggle、渲染
|
|
204
|
+
// 純展示模式:無互動 toggle、渲染 Check / X icon。與 Checkbox display 對齊(同 boolean primitive,
|
|
205
|
+
// 共用 SelectionControl/boolean-value.tsx SSOT — 勾/叉 icon + 中性 foreground 色)。
|
|
204
206
|
if (resolvedMode === 'display') {
|
|
205
207
|
const isChecked = checkedProp === true
|
|
206
|
-
return
|
|
207
|
-
|
|
208
|
-
|
|
208
|
+
return (
|
|
209
|
+
<span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className="inline-flex">
|
|
210
|
+
<BooleanValueIcon checked={isChecked} size={resolvedBoxSize} />
|
|
211
|
+
</span>
|
|
212
|
+
)
|
|
209
213
|
}
|
|
210
214
|
|
|
211
|
-
// ── mode='readonly' in Field(2026-06-12
|
|
215
|
+
// ── mode='readonly' in Field(2026-06-12 拍板「灰框 + 勾/叉」,與 Checkbox 同款;2026-07-09 glyph → Check/X icon)──
|
|
212
216
|
// Field 內 readonly boolean = fieldWrapperStyles readonly 灰框(= Input readonly 同源)
|
|
213
|
-
// +
|
|
217
|
+
// + 勾/叉 icon 值語言;standalone readOnly(settings list)維持原樣鎖互動。詳 checkbox.tsx 同段註解。
|
|
214
218
|
if (effectiveReadOnly && insideField) {
|
|
215
219
|
const isChecked = (checkedProp ?? defaultCheckedProp) === true
|
|
216
220
|
const boxSize = resolvedBoxSize
|
|
@@ -231,7 +235,7 @@ const Switch = React.forwardRef<
|
|
|
231
235
|
className,
|
|
232
236
|
)}
|
|
233
237
|
>
|
|
234
|
-
|
|
238
|
+
<BooleanValueIcon checked={isChecked} size={boxSize} />
|
|
235
239
|
</div>
|
|
236
240
|
)
|
|
237
241
|
}
|