@qijenchen/design-system 0.1.0-beta.10 → 0.1.0-beta.13
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 +201 -0
- package/README.md +7 -15
- package/cli-init.mjs +90 -0
- package/ds-canonical/commands/README.md +26 -0
- package/ds-canonical/commands/gov-status.md +79 -0
- package/ds-canonical/hooks/README.md +145 -0
- package/ds-canonical/hooks/_log-fire.sh +44 -0
- package/ds-canonical/hooks/block_prototype_imports.py +111 -0
- package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
- package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
- package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
- package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
- package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
- package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
- package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
- package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
- package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
- package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
- package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
- package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
- package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
- package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
- package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
- package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
- package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
- package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
- package/ds-canonical/hooks/check_story_invariants.sh +612 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
- package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
- package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
- package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
- package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
- package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
- package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
- package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
- package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
- package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
- package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
- package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
- package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
- package/ds-canonical/hooks/log_governance_fires.sh +50 -0
- package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
- package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
- package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
- package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
- package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
- package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
- package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
- package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
- package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
- package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
- package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
- package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
- package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
- package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
- package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
- package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
- package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
- package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
- package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
- package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
- package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
- package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
- package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
- package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
- package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
- package/ds-canonical/hooks/stop_self_audit.sh +450 -0
- package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
- package/ds-canonical/hooks/tests/run-all.sh +76 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
- package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
- package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
- package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
- package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
- package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
- package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
- package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
- package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
- package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
- package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
- package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
- package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
- package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
- package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
- package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
- package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
- package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
- package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
- package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
- package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
- package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
- package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
- package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
- package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
- package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
- package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
- package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
- package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
- package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
- package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
- package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
- package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
- package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
- package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
- package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
- package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
- package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
- package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
- package/ds-canonical/references/README.md +43 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
- package/ds-canonical/references/build-ui-canonicals.md +69 -0
- package/ds-canonical/references/cva-patterns.md +41 -0
- package/ds-canonical/references/drag-canonical.md +331 -0
- package/ds-canonical/references/item-anatomy-recipe.md +225 -0
- package/ds-canonical/references/naming-conventions.md +56 -0
- package/ds-canonical/references/principle-dim-map.json +515 -0
- package/ds-canonical/references/props-naming.md +45 -0
- package/ds-canonical/references/spec-rules.md +58 -0
- package/ds-canonical/references/ssot-consultation.md +63 -0
- package/ds-canonical/references/ssot-index.md +40 -0
- package/ds-canonical/references/story-baseline-registry.json +79 -0
- package/ds-canonical/references/structural-token-retention.md +42 -0
- package/ds-canonical/references/tailwind-gotchas.md +87 -0
- package/ds-canonical/references/ui-dev-rules.md +60 -0
- package/ds-canonical/rules/README.md +34 -0
- package/ds-canonical/rules/meta-patterns.md +87 -0
- package/ds-canonical/rules/self-verify.md +53 -0
- package/ds-canonical/rules/spec-rules.md +25 -0
- package/ds-canonical/rules/story-rules.md +56 -0
- package/ds-canonical/rules/ui-development.md +87 -0
- package/ds-canonical/skills/README.md +88 -0
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
- package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
- package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
- package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
- package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
- package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
- package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
- package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
- package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
- package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
- package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
- package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
- package/ds-canonical/skills/governance-health/SKILL.md +146 -0
- package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
- package/ds-canonical/skills/new-component/SKILL.md +170 -0
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
- package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
- package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
- package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
- package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
- package/ds-canonical/skills/propose-options/SKILL.md +177 -0
- package/ds-canonical/skills/prototype/SKILL.md +244 -0
- package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
- package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
- package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
- package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
- package/ds-canonical/skills/story-writing/SKILL.md +122 -0
- package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
- package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
- package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
- package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
- package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
- package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
- package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
- package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/package.json +9 -5
- package/src/components/Accordion/accordion.spec.md +114 -0
- package/src/components/Alert/alert.spec.md +197 -0
- package/src/components/AppShell/app-shell.spec.md +331 -0
- package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
- package/src/components/Avatar/avatar.spec.md +329 -0
- package/src/components/Badge/badge.spec.md +380 -0
- package/src/components/Breadcrumb/breadcrumb.spec.md +257 -0
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
- package/src/components/Button/button.spec.md +460 -0
- package/src/components/Calendar/calendar.spec.md +242 -0
- package/src/components/Carousel/carousel.spec.md +253 -0
- package/src/components/Chart/chart.spec.md +155 -0
- package/src/components/Checkbox/checkbox.spec.md +344 -0
- package/src/components/Chip/chip.spec.md +237 -0
- package/src/components/CircularProgress/circular-progress.spec.md +268 -0
- package/src/components/Coachmark/coachmark.spec.md +230 -0
- package/src/components/Combobox/combobox.spec.md +180 -0
- package/src/components/Command/command.spec.md +171 -0
- package/src/components/DataTable/data-table.spec.md +525 -0
- package/src/components/DateGrid/date-grid.spec.md +215 -0
- package/src/components/DatePicker/date-picker.spec.md +334 -0
- package/src/components/DescriptionList/description-list.spec.md +214 -0
- package/src/components/Dialog/dialog.spec.md +202 -0
- package/src/components/DropdownMenu/dropdown-menu.spec.md +250 -0
- package/src/components/Empty/empty.spec.md +214 -0
- package/src/components/Field/field-controls.spec.md +338 -0
- package/src/components/Field/field.spec.md +438 -0
- package/src/components/Field/form-validation.spec.md +152 -0
- package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
- package/src/components/FileItem/file-item.spec.md +467 -0
- package/src/components/FileUpload/file-upload.spec.md +123 -0
- package/src/components/FileViewer/file-viewer.spec.md +373 -0
- package/src/components/HoverCard/hover-card.spec.md +157 -0
- package/src/components/Input/input.spec.md +193 -0
- package/src/components/LinkInput/link-input.spec.md +130 -0
- package/src/components/Menu/menu-item.spec.md +290 -0
- package/src/components/NameCard/name-card.spec.md +171 -0
- package/src/components/Notice/notice.spec.md +149 -0
- package/src/components/NumberInput/number-input.spec.md +126 -0
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
- package/src/components/PeoplePicker/people-picker.spec.md +263 -0
- package/src/components/Popover/popover.spec.md +198 -0
- package/src/components/ProgressBar/progress-bar.spec.md +232 -0
- package/src/components/RadioGroup/radio-group.spec.md +141 -0
- package/src/components/Rating/rating.spec.md +208 -0
- package/src/components/ScrollArea/scroll-area.spec.md +145 -0
- package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
- package/src/components/Select/select.spec.md +299 -0
- package/src/components/SelectMenu/select-menu.spec.md +220 -0
- package/src/components/SelectionControl/selection-item.spec.md +128 -0
- package/src/components/Separator/separator.spec.md +109 -0
- package/src/components/Sheet/sheet.spec.md +148 -0
- package/src/components/Sidebar/sidebar.spec.md +713 -0
- package/src/components/Skeleton/skeleton.spec.md +104 -0
- package/src/components/Slider/slider.spec.md +353 -0
- package/src/components/Steps/steps.spec.md +465 -0
- package/src/components/Switch/switch.spec.md +215 -0
- package/src/components/Tabs/tabs.spec.md +314 -0
- package/src/components/Tag/tag.spec.md +282 -0
- package/src/components/Textarea/textarea.spec.md +151 -0
- package/src/components/TimePicker/time-picker.spec.md +279 -0
- package/src/components/Toast/toast.spec.md +177 -0
- package/src/components/Tooltip/tooltip.spec.md +139 -0
- package/src/components/TreeView/tree-view.spec.md +374 -0
- package/src/patterns/action-bar/action-bar.spec.md +458 -0
- package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +315 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
- package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +428 -0
- package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
- package/src/tokens/color/color.spec.md +804 -0
- package/src/tokens/density/density.spec.md +127 -0
- package/src/tokens/elevation/elevation.spec.md +81 -0
- package/src/tokens/layoutSpace/layoutSpace.spec.md +314 -0
- package/src/tokens/motion/motion.spec.md +97 -0
- package/src/tokens/opacity/opacity.spec.md +78 -0
- package/src/tokens/orphan-tokens.spec.md +117 -0
- package/src/tokens/radius/radius.spec.md +123 -0
- package/src/tokens/typography/typography.spec.md +202 -0
- package/src/tokens/uiSize/uiSize.spec.md +438 -0
- package/src/styles/preset.css +0 -31
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — verified 0 world-class DS claim in body; blanket retract removed. -->
|
|
2
|
+
|
|
3
|
+
# Density 設計原則
|
|
4
|
+
|
|
5
|
+
Density 由**兩個獨立維度**構成,並配合一個 convenience attribute 同時控制兩者:
|
|
6
|
+
|
|
7
|
+
| 維度 | 管的是 | attribute | 範例 |
|
|
8
|
+
|------|--------|-----------|------|
|
|
9
|
+
| **UI Size** | 元件**高度 / 內距**(Button / Input / SelectionItem / field-height / table-row) | `data-ui-size` | `md`(28px field)/ `lg`(32px field) |
|
|
10
|
+
| **Layout Space** | 版面**間距 / 外框 padding**(section gutter / dialog body padding / form gap) | `data-layout-space` | `md`(tight gap)/ `lg`(loose gap) |
|
|
11
|
+
| **Density**(convenience)| 一鍵同時切兩者 | `data-density` | `md` / `lg` |
|
|
12
|
+
|
|
13
|
+
## 兩維度為何解耦(世界級對照)
|
|
14
|
+
|
|
15
|
+
**Carbon Design System**:spacing scale 獨立於 component size([carbondesignsystem.com/elements/spacing](https://carbondesignsystem.com/elements/spacing/overview/))
|
|
16
|
+
**GitHub Primer**:8px base unit scale 獨立於 control size([styleguide.github.com/primer](https://styleguide.github.com/primer/support/spacing/))
|
|
17
|
+
**Atlassian**:spacing tokens 可單獨消費(partial decouple)
|
|
18
|
+
|
|
19
|
+
**反例**(耦合):Material M3 / Polaris density 模式綁 control size + spacing — 無法「寬版面 + 標準 control」的場景。
|
|
20
|
+
|
|
21
|
+
**我們走 decouple 流派**:解決 Dialog / overlay chrome 的痛點 — header 想要寬鬆呼吸(layout=lg),但不要被 button chrome 撐高(ui-size 跟 page 走 md)。
|
|
22
|
+
|
|
23
|
+
## 預設同步(density convenience)
|
|
24
|
+
|
|
25
|
+
日常使用:不管兩個維度,直接 `data-density` 一次切兩者:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<html data-theme="light" data-density="md">
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **md**(預設):資訊密集的桌面 UI / form-heavy 頁面
|
|
32
|
+
- **lg**:觸控裝置 / 需要更大點擊目標的情境
|
|
33
|
+
|
|
34
|
+
`data-density` 內部等同同時設 `data-ui-size` + `data-layout-space` 相同 tier。CSS selectors 同時監聽 `[data-density="lg"], [data-ui-size="lg"]` 等(見 `uiSize.css` + `layoutSpace.css`)。
|
|
35
|
+
|
|
36
|
+
## 解耦用法(canonical 情境)
|
|
37
|
+
|
|
38
|
+
當需要「layout 寬鬆 + control 標準」時,**顯式設兩個 attribute**:
|
|
39
|
+
|
|
40
|
+
### Canonical 情境 1 — 歷史備忘(Dialog 已撤回)
|
|
41
|
+
|
|
42
|
+
**歷史:** Dialog 先前設 `data-layout-space="lg"` 給 header/body 寬鬆呼吸,但跟 `--chrome-header-height` canonical(md=48)衝突(強設 lg 會變 56)。**已於 2026-04-22 v5 撤回**,Dialog 全盤繼承 page density(跟 Sheet 對齊)。
|
|
43
|
+
|
|
44
|
+
**本情境仍有效的使用時機**:若未來有新元件需要「page density = md 但此元件 chrome 要 lg padding」,可用 `data-layout-space="lg"`(不撐高 header 的 rationale 仍成立,前提是 chrome-header-height 對齊不是需求)。
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// 假設未來某元件需要 lg 呼吸 + page-default ui-size
|
|
48
|
+
<SomeContent data-layout-space="lg">
|
|
49
|
+
<Button size="sm" /> {/* 仍是 28px md */}
|
|
50
|
+
</SomeContent>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**實際 v5 canonical(Dialog / Sheet / Popover)**:
|
|
54
|
+
- Dialog / Sheet:繼承 page density(無 override)
|
|
55
|
+
- Popover / DropdownMenu / Tooltip / Sidebar:`data-density="md"` 鎖定(Portal 逃逸 + compact 語意)
|
|
56
|
+
|
|
57
|
+
### Canonical 情境 2 — 單獨切 ui-size
|
|
58
|
+
|
|
59
|
+
Product demo / stakeholder 觀感測試:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
document.documentElement.setAttribute('data-ui-size', 'lg')
|
|
63
|
+
// layout-space 仍 md — 看大 control 在密集 layout 裡是否合用
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Canonical 情境 3 — 局部覆蓋
|
|
67
|
+
|
|
68
|
+
某 region 需要不同密度:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<div data-layout-space="lg">
|
|
72
|
+
{/* 這個 region layout 寬鬆,control 跟外層 page 走 */}
|
|
73
|
+
</div>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 動態切換
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// 一鍵(兩維度同步)
|
|
80
|
+
document.documentElement.setAttribute('data-density', 'lg')
|
|
81
|
+
|
|
82
|
+
// 解耦(獨立控制)
|
|
83
|
+
document.documentElement.setAttribute('data-ui-size', 'lg')
|
|
84
|
+
document.documentElement.setAttribute('data-layout-space', 'md')
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 判斷流程(寫新元件時)
|
|
88
|
+
|
|
89
|
+
1. **元件是否有自己特定 density**?
|
|
90
|
+
- 否(繼承 page) → 不設任何 `data-*-size` attribute,所有 token 由 `html[data-density]` 繼承
|
|
91
|
+
- 是 → 看 Q2
|
|
92
|
+
|
|
93
|
+
2. **需要 layout 跟 control 同步 density 嗎**?
|
|
94
|
+
- 是 → 用 `data-density="X"`(convenience)
|
|
95
|
+
- 否(想解耦) → 明示 `data-layout-space="X"` + / 或 `data-ui-size="Y"`
|
|
96
|
+
|
|
97
|
+
3. **Portal 逃逸 subtree?**(Dialog / Popover / Sheet / DropdownMenu)
|
|
98
|
+
- Portal 到 body 的元件**不繼承 trigger 的 density** → 必自設(對齊 Meta-Pattern M3)
|
|
99
|
+
|
|
100
|
+
## 消費者清單
|
|
101
|
+
|
|
102
|
+
| 元件 | attribute 設置 | 用法理由 |
|
|
103
|
+
|------|---------------|---------|
|
|
104
|
+
| Dialog | 無(繼承 page,v5 校準)| 跟 Sheet 對齊;header 高度 = `--chrome-header-height` 自動對齊(md=48 / lg=56);原 `data-layout-space="lg"` 已於 2026-04-22 撤回(衝突 chrome-header canonical) |
|
|
105
|
+
| Sheet | 無(繼承 page) | Sheet 繼承 page density,不 lock |
|
|
106
|
+
| Popover | `data-density="md"` | Portal 逃逸,且 popover 語意「compact」兩維度同鎖 md |
|
|
107
|
+
| DropdownMenu | `data-density="md"` | 同 Popover |
|
|
108
|
+
| Tooltip | `data-density="md"` | 同 Popover |
|
|
109
|
+
| Sidebar | `data-density="md"` | Sidebar 本身 compact(不管 page 是否 lg)|
|
|
110
|
+
|
|
111
|
+
## Anti-patterns(禁止)
|
|
112
|
+
|
|
113
|
+
- ❌ 元件同時設 `data-density` + `data-ui-size`(重複,以後者為準但混亂)
|
|
114
|
+
- ❌ Overlay Portal 元件不自設 density(Portal 到 body 不繼承 trigger — 見 Meta-Pattern M3)
|
|
115
|
+
- ❌ 為了追求表面一致性硬把 Dialog button 綁 lg ui-size(犧牲 header 高度 / strapline 彈性)
|
|
116
|
+
|
|
117
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
118
|
+
|
|
119
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
120
|
+
|
|
121
|
+
- `dialog.spec.md`
|
|
122
|
+
- `dropdown-menu.spec.md`
|
|
123
|
+
- `popover.spec.md`
|
|
124
|
+
- `sheet.spec.md`
|
|
125
|
+
- `sidebar.spec.md`
|
|
126
|
+
- `tooltip.spec.md`
|
|
127
|
+
- `uiSize.spec.md`
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Elevation 設計原則
|
|
2
|
+
|
|
3
|
+
Elevation 定義陰影層級,區分內容層(Card)和浮層(Modal/Popover)的視覺深度。
|
|
4
|
+
|
|
5
|
+
兩個層級對應兩種「浮起高度」,用 CSS 變數實現,light / dark mode 自動切換。
|
|
6
|
+
|
|
7
|
+
**不要用 Tailwind 的 `shadow-*`**,改用 CSS 變數:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
<div style={{ boxShadow: 'var(--elevation-100)' }} />
|
|
11
|
+
<div style={{ boxShadow: 'var(--elevation-200)' }} />
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## 層級
|
|
16
|
+
|
|
17
|
+
| Token | 用途 | 對應元件 |
|
|
18
|
+
|-------|------|----------|
|
|
19
|
+
| `--elevation-100` | 頁面內容層,靜止 | Card |
|
|
20
|
+
| `--elevation-100-hover` | 頁面內容層,hover / 拖拽 | 可拖拽 card |
|
|
21
|
+
| `--elevation-200` | 浮層,靜止 | Modal、popover、dropdown、overlay drawer |
|
|
22
|
+
| `--elevation-200-hover` | 浮層,hover | — |
|
|
23
|
+
|
|
24
|
+
elevation-100 < elevation-200,數字越大浮起越高。
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## 與 Surface 的配對規則
|
|
28
|
+
|
|
29
|
+
| Elevation | 必須搭配 | 原因 |
|
|
30
|
+
|-----------|----------|------|
|
|
31
|
+
| `--elevation-100` | `bg-surface` | 頁面內容層,半透明可接受 |
|
|
32
|
+
| `--elevation-200` | `bg-surface-raised` | 浮層必須不透明,否則底層內容透出 |
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// ✅ 正確
|
|
36
|
+
<div className="bg-surface rounded-md" style={{ boxShadow: 'var(--elevation-100)' }} />
|
|
37
|
+
<div className="bg-surface-raised rounded-lg" style={{ boxShadow: 'var(--elevation-200)' }} />
|
|
38
|
+
|
|
39
|
+
// ❌ 錯誤——浮層用了半透明 bg-surface
|
|
40
|
+
<div className="bg-surface rounded-lg" style={{ boxShadow: 'var(--elevation-200)' }} />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## 浮層間距(sideOffset)
|
|
45
|
+
|
|
46
|
+
所有從觸發元件彈出的浮層(Tooltip、Popover、SelectMenu、Dropdown、HoverCard、Coachmark)與觸發元件的間距統一 **8px**(`sideOffset={8}`)。
|
|
47
|
+
|
|
48
|
+
不因浮層類型或位置而異——一致的間距讓使用者建立穩定的空間預期。
|
|
49
|
+
|
|
50
|
+
**SSOT** → `tokens/elevation/overlay-geometry.ts` exports `OVERLAY_SIDE_OFFSET = 8` / `OVERLAY_COLLISION_PADDING = 8`。所有 primitive `default` 必 import 該 const(M17 SSOT 必可傳播);Radix `sideOffset` 接 number 不接 CSS var,因此用 JS const 共用,改值只動一處全部聯動。
|
|
51
|
+
|
|
52
|
+
| 浮層類型 | sideOffset | 說明 |
|
|
53
|
+
|---------|-----------|------|
|
|
54
|
+
| Tooltip | 8px | TooltipContent 預設值 |
|
|
55
|
+
| SelectMenu | 8px | PopoverContent sideOffset |
|
|
56
|
+
| DropdownMenu | 8px | DropdownMenuContent sideOffset |
|
|
57
|
+
| Popover | 8px | 通用浮層 |
|
|
58
|
+
|
|
59
|
+
## 浮層共用樣式
|
|
60
|
+
|
|
61
|
+
所有 elevation-200 浮層共用:
|
|
62
|
+
|
|
63
|
+
| 屬性 | Token | 值 |
|
|
64
|
+
|------|-------|-----|
|
|
65
|
+
| 背景 | `bg-surface-raised` | 不透明,避免底層透出 |
|
|
66
|
+
| 陰影 | `--elevation-200` | 浮層陰影 |
|
|
67
|
+
| 圓角 | `rounded-lg` | 8px |
|
|
68
|
+
| 邊框 | `border border-border` | 1px |
|
|
69
|
+
| sideOffset | 8px | 與觸發元件的間距 |
|
|
70
|
+
|
|
71
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
72
|
+
|
|
73
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
74
|
+
|
|
75
|
+
- `slider.spec.md`
|
|
76
|
+
|
|
77
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
78
|
+
|
|
79
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
80
|
+
|
|
81
|
+
- `motion.spec.md`
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
2
|
+
|
|
3
|
+
# LayoutSpace 設計原則
|
|
4
|
+
|
|
5
|
+
Layout Space 定義頁面與容器的巨觀間距 token,隨 density 自動縮放(透過 `data-density` 或 `data-layout-space`)。
|
|
6
|
+
|
|
7
|
+
## Token 表
|
|
8
|
+
|
|
9
|
+
| Token | md | lg | 語意 |
|
|
10
|
+
|-------|----|----|------|
|
|
11
|
+
| `--layout-space-loose` | 16px | 24px | 主間距:容器水平 padding、parallel 元素 gap、bounded region 呼吸空間 |
|
|
12
|
+
| `--layout-space-tight` | 12px | 16px | 緊湊間距:Header → element、functional 交互的元素之間 |
|
|
13
|
+
| `--layout-space-bottom` | 48px | 48px | 結論留白:內容到 action buttons(commitment 前視覺暫停)|
|
|
14
|
+
|
|
15
|
+
**為什麼 bottom 不隨 density 變**:48px 是「結論前的留白」— content 到 action buttons 的視覺暫停。跟 density 無關(不論 compact 或 comfortable,使用者都需要「commitment 前」的節奏)。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 元件角色:`region` / `element`(scope-relative)
|
|
20
|
+
|
|
21
|
+
**沒有元件級固定分類** — 角色是元件在「該層 layout」裡扮演的,不是元件本質。CSS `display` 跟此分類**無關**(避免撞名,2026-04 從 v1 `block` / `inline` 改為 `region` / `element`)。
|
|
22
|
+
|
|
23
|
+
| 角色 | 定義 |
|
|
24
|
+
|------|------|
|
|
25
|
+
| **region** | 寬高占主要空間(寬度撐滿、高度通常 flex-1 撐剩餘)/ 視覺畫布 / 該層展示主角 |
|
|
26
|
+
| **element** | 局部塊 / 控件感 / 寬高自然 |
|
|
27
|
+
|
|
28
|
+
### region 子分類
|
|
29
|
+
|
|
30
|
+
| 子類 | 條件 | 視覺邏輯 |
|
|
31
|
+
|-----|------|---------|
|
|
32
|
+
| **bounded** | 有視覺邊界:底色 / 邊框 / 明確上下分隔線(Card / Table with borders / Panel with chrome)| 邊界清楚,容器靠 outer padding 給 spacing |
|
|
33
|
+
| **unbounded** | 無視覺邊界:純 vertical collection,**靠 list 自帶 py + item 自帶高度**撐起視覺平衡(Cmd+K menu / Sidebar nav / unstyled list)| 邊界由 list 自帶 py 完成,outer padding = 0 才視覺對稱 |
|
|
34
|
+
|
|
35
|
+
### 判斷 3 題(scope-relative)
|
|
36
|
+
|
|
37
|
+
每進一層 layout container 重新判斷該層的子元件:
|
|
38
|
+
|
|
39
|
+
1. 該層占主要空間嗎?(寬+高占主導 → region;局部 → element)
|
|
40
|
+
2. 視覺重量是「畫布」還是「控件」?
|
|
41
|
+
3. 是該層展示主角,還是一塊區段?
|
|
42
|
+
|
|
43
|
+
任何元件(list / table / code block / image / form section / chart / sidebar)都套同邏輯。例:
|
|
44
|
+
- Page body 直接放 Table → Table = bounded region(該層展示主角 + 有 borders)
|
|
45
|
+
- Cmd+K menu list → list = unbounded region(主角 + 無 chrome,自帶 py)
|
|
46
|
+
- InfoPanel 內 DescriptionList → element(只是一塊,不主導)
|
|
47
|
+
- Field 內 Textarea → 不獨立分類(Field 整體才是該層的 element)
|
|
48
|
+
|
|
49
|
+
### Region 數量 invariant(2026-04-30 codified)
|
|
50
|
+
|
|
51
|
+
**Container body(vertical stack)通常最多 1 個 region — 罕見會多**。理由:
|
|
52
|
+
- region 多為 `flex-1` 撐剩餘 → 兩個並存競爭 flex space
|
|
53
|
+
- Multi-functional-group 慣用 **list group 切分**(`item-anatomy.spec.md` group separator)或多個 element,不另增 region
|
|
54
|
+
- **Unbounded + bounded 並存違 scroll affordance**:unbounded 無邊界 vs 內部 scroll 必須 bounded chrome 讓 user 知道可捲
|
|
55
|
+
|
|
56
|
+
**多 region 慣用 horizontal layout**(left-right panes / grid columns,Sidebar + Main + InfoPanel)。Vertical 多 region 罕見場景 → 走規則 3 親疏判 + consumer compose。
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 親疏 3 級(替代 v1 簡單 block-adjacent)
|
|
61
|
+
|
|
62
|
+
判斷兩元素的 spacing 規則前,先確定它們屬哪一級:
|
|
63
|
+
|
|
64
|
+
| 級別 | 條件 | layout rule? |
|
|
65
|
+
|------|------|------------|
|
|
66
|
+
| **同範疇 / bundled component family** | 元件 spec 寫成 bundle 並定 inter-component spacing(FileUpload+FileList、Pagination 內部、Toolbar+ButtonGroup) | 元件 spec own,layout rule **跳過** |
|
|
67
|
+
| **跨範疇 + 直接 functional 交互 / 依賴** | search → filter list / heading → labeled content / toolbar → table / form section heading → fields | 規則 3 = **tight** |
|
|
68
|
+
| **跨範疇 + parallel / independent** | form fields stack(parallel inputs)/ unrelated sections / 兩個獨立 functional groups | 規則 3 = **loose** |
|
|
69
|
+
|
|
70
|
+
「**Bundled component family**」客觀判斷:**有沒有 spec 文件把這些 components 寫成 bundle 並定義它們之間 spacing**(不是「同種類 component instance 多個」)。
|
|
71
|
+
|
|
72
|
+
「**Functional 交互 / 依賴**」具體:操作後在畫面上有交互(value 驅動 display)/ labeling(命名 / 描述 group identity)/ context dependency。
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 6 條 Layout 規則
|
|
77
|
+
|
|
78
|
+
### 規則 1:水平 padding(3 patterns 並存)
|
|
79
|
+
|
|
80
|
+
| Pattern | padding 寫哪 | 適用場景 |
|
|
81
|
+
|---------|------------|---------|
|
|
82
|
+
| **A. 元件自帶**(`px-loose` on root) | 元件 root | 有視覺邊界(border / bg / shadow / chrome):Sidebar / SurfaceHeader / Toolbar / Card / Panel |
|
|
83
|
+
| **B. 父層管**(consumer 或 wrapper) | 父層 div | 純 layout primitive 無邊界:Table / DescriptionList / DataTable(naked structure)|
|
|
84
|
+
| **C. Item 自帶**(each item `px-loose`,list naked)| 每個 item | List with hover row,hover bg 需 flush 容器邊界:Cmd+K menu / DropdownMenu items / Sidebar nav |
|
|
85
|
+
|
|
86
|
+
任何內容左右 padding 最終 = `loose`(對齊 inline 元件邊緣);**寫哪看元件本質**,不是 either-or。
|
|
87
|
+
|
|
88
|
+
Pattern C 的視覺邏輯見 `overlay-surface.spec.md`「Hover bg 貼邊 chrome」(hover bg 0 gutter 貼邊 + content 由 item-px 推進)。
|
|
89
|
+
|
|
90
|
+
### 規則 2:頂部(Header → 第一個元素)
|
|
91
|
+
|
|
92
|
+
| 第一個元素 | Header → 該元素 |
|
|
93
|
+
|-----------|--------------|
|
|
94
|
+
| **bounded region**(table / card / panel)| `loose` |
|
|
95
|
+
| **unbounded region**(自帶 py 的 list / nav stack)| **0**(讓 list 自帶 py 撐 spacing) |
|
|
96
|
+
| **element**(input / button / alert) | `tight` |
|
|
97
|
+
|
|
98
|
+
### 規則 3:元素間 gap(**只看親疏,role 無關**)
|
|
99
|
+
|
|
100
|
+
| 親疏 | gap |
|
|
101
|
+
|------|-----|
|
|
102
|
+
| **同範疇 / bundled** | 元件 spec own(跳此 rule)|
|
|
103
|
+
| **跨範疇 + functional 交互** | `tight` |
|
|
104
|
+
| **跨範疇 + parallel** | `loose` |
|
|
105
|
+
|
|
106
|
+
**核心**:gap 只看親疏不看 role(原 v1「block-adjacent 一律 tight」過機械,違 Gestalt proximity)。
|
|
107
|
+
|
|
108
|
+
世界級對齊:Material 3 / Polaris / Apple HIG / Atlassian 都按「relationship not type」決定 spacing。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
109
|
+
|
|
110
|
+
### 規則 4:底部 — 拆兩個 distinct 概念
|
|
111
|
+
|
|
112
|
+
**核心**:**「內容 → action button 前留白」跟「元件 → 容器底邊」是兩個不同 spacing 概念**,不可混為一談。
|
|
113
|
+
|
|
114
|
+
| 情境 | gap | 概念 |
|
|
115
|
+
|------|-----|------|
|
|
116
|
+
| **任何最後內容 → action button**(inline / in SurfaceFooter / in chrome footer 內)| `bottom`(48)| **A. Commitment 前留白** — user 跨到決策 moment |
|
|
117
|
+
| **bounded region → 容器底**(後無 action buttons) | `loose` | **B. Spatial 邊界** |
|
|
118
|
+
| **unbounded region → 容器底**(後無 action buttons) | **0**(list 自帶 py 撐)| **B. Spatial 邊界** |
|
|
119
|
+
| **element → 容器底**(後無 action buttons) | `tight` | **B. Spatial 邊界** |
|
|
120
|
+
|
|
121
|
+
**Note**:Dialog body `pb-bottom 48` 是 line 1 的實作(預期後接 SurfaceFooter buttons,universal 套 48,**不是元件特例**)。「**底部 chrome band**」(Alert / BulkActionBar / Status bar / Footer)內含 action → 套 48;不含 → 套 loose(line 2)。
|
|
122
|
+
|
|
123
|
+
### 規則 5:橫排 Input Gap(固定不隨 density)
|
|
124
|
+
|
|
125
|
+
橫排並列的 input fields **固定 gap,不走 layout-space token**:
|
|
126
|
+
|
|
127
|
+
| 關聯性 | Gap | 範例 |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| 緊密相關(同一組值的起迄)| `gap-2`(8) | Sleep start ↔ Sleep end |
|
|
130
|
+
| 非緊密(不同組值並列)| `gap-4`(16) | Sleep 時段 ↔ Work 時段 |
|
|
131
|
+
|
|
132
|
+
**為什麼固定**:這是 field 級 micro-spacing,跟容器級 macro-spacing 是不同維度。Field gap 由**內容語意**決定(緊密 vs 獨立),不由 density 決定。
|
|
133
|
+
|
|
134
|
+
### 規則 6:Chrome 水平左右 padding(規則 1 specialization)
|
|
135
|
+
|
|
136
|
+
**所有 chrome 表面**(SurfaceHeader / SurfaceFooter / SurfaceBody / Sidebar header / FileViewer toolbar+filmstrip+InfoPanel header / app top bar / page header)**水平左右** padding 統一 `px-[var(--layout-space-loose)]`(md=16 / lg=24,density-aware)。
|
|
137
|
+
|
|
138
|
+
**為何 loose 而非 tight**:Chrome 是 surface 視覺邊界 + 內容呼吸區;`tight` 足夠 inline list item,chrome 需更穩定 anchor 讓 title / dismiss / actions 不貼邊。
|
|
139
|
+
|
|
140
|
+
**M8 8 家世界級對照**(default density 共識 16px):Material 3 Top App Bar 16dp / Carbon UI Shell 16px / Polaris Page Header 16px / Atlassian Page Header 16px / Apple HIG macOS Toolbar 16-20pt / Linear / Notion / GitHub Primer / Figma 全 16px。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
141
|
+
|
|
142
|
+
**禁止**:硬寫 `px-4` / 自創值(`px-5`)/ 用 tight 當 chrome inline / 同 surface header/body/footer inline padding 不一致(三層左邊界必對齊)。
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 心智模型(三步推理 + 具體 self-questions)
|
|
147
|
+
|
|
148
|
+
### Step 1 — 判角色(對單一元素)
|
|
149
|
+
|
|
150
|
+
問 3 題:
|
|
151
|
+
1. 在該層 layout 占主導(寬度撐滿 + 高度 flex-1)嗎?
|
|
152
|
+
2. 視覺重量是「畫布」(占據 layout)還是「控件」(局部塊)?
|
|
153
|
+
3. 是該層展示主角(主導內容)嗎?
|
|
154
|
+
|
|
155
|
+
多數 yes → **region**;反之 → **element**。
|
|
156
|
+
|
|
157
|
+
若 region 再問 1 題:有視覺邊界(底色 / 邊框 / 上下分隔線)嗎?
|
|
158
|
+
- 有 → **bounded**(Card / Table with borders / Panel)
|
|
159
|
+
- 無 → **unbounded**(menu list / nav stack,自帶 py 撐)
|
|
160
|
+
|
|
161
|
+
### Step 2 — 判範疇(對兩元素之間)
|
|
162
|
+
|
|
163
|
+
問 2 題:
|
|
164
|
+
1. 兩元素在 spec.md 裡寫成 bundle 並定 spacing 嗎?(eg FileUpload+FileList / Pagination 內部 / button-group + SurfaceFooter)
|
|
165
|
+
- **是 → 同範疇 / bundled** → 跳 layout rule,套元件 spec own
|
|
166
|
+
- 否 → 跨範疇,進下一題
|
|
167
|
+
2. 兩元素有直接 functional 交互 / 依賴(操作驅動 / labeling / context dependency)嗎?
|
|
168
|
+
- **是 → 相關**(search→list / heading→content / toolbar→table)→ tight
|
|
169
|
+
- **否 → 不相關**(parallel / independent)→ loose
|
|
170
|
+
|
|
171
|
+
### Step 3 — 套規則(下節決策表 + walkthrough 範例)
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 套規則決策表(具體查詢)
|
|
176
|
+
|
|
177
|
+
「我要決定什麼?」找對應規則:
|
|
178
|
+
|
|
179
|
+
| 想決定的 | 走哪條規則 | 看哪些變數 | 答案分支 |
|
|
180
|
+
|---------|----------|----------|---------|
|
|
181
|
+
| 容器水平左右 padding | **規則 1** | 元件有無視覺邊界? | 有 → A 元件自帶 `px-loose` / 無 → B 父層管 / list-with-hover-row → C item 自帶 |
|
|
182
|
+
| Header → 第一個元素 gap | **規則 2** | 第一個元素 role | bounded region → `loose` / unbounded region → **0**(list 自帶 py 撐)/ element → `tight` |
|
|
183
|
+
| 兩元素之間 gap | **規則 3** | 親疏 | 同範疇 → 元件 spec own(跳)/ 跨範疇相關 → `tight` / 跨範疇 parallel → `loose` |
|
|
184
|
+
| 最後內容 → 容器底 | **規則 4** | (a) 後接 action button?(b) 元件 role | 後接 action → `bottom`(48,概念 A commitment 前留白)/ 否則看 role:bounded → `loose` / unbounded → **0** / element → `tight`(概念 B spatial 邊界)|
|
|
185
|
+
| 橫排並列 input 之間 gap | **規則 5** | 內容語意緊密度 | 同組值起迄 → `gap-2`(8) / 不同組並列 → `gap-4`(16) |
|
|
186
|
+
| Chrome 表面水平 padding | **規則 6** | (永遠) | `loose` |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 具體推導 walkthrough(6 範例)
|
|
191
|
+
|
|
192
|
+
### 範例 1:Dialog 內 form fields stack(Field A ↔ Field B)
|
|
193
|
+
|
|
194
|
+
- **走規則**:規則 3(兩元素之間 gap)
|
|
195
|
+
- **判親疏**:
|
|
196
|
+
- bundled?(在元件 spec 裡寫成 bundle 嗎?) → **否**(consumer-composed)→ 跨範疇
|
|
197
|
+
- functional 交互?A 不驅動 B,parallel siblings → **不相關**
|
|
198
|
+
- **答**:`loose`(16/24)— 對齊 Material / Polaris / Apple HIG / Atlassian 共識 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
199
|
+
|
|
200
|
+
### 範例 2:Cmd+K menu 中 search input ↔ result list
|
|
201
|
+
|
|
202
|
+
- **走規則**:規則 3
|
|
203
|
+
- **判親疏**:
|
|
204
|
+
- bundled?Input + list 不在同 spec bundle → 跨範疇
|
|
205
|
+
- functional 交互?search value 驅動 list filter → **相關**
|
|
206
|
+
- **答**:`tight`(12/16)
|
|
207
|
+
|
|
208
|
+
### 範例 3:Header chrome → InfoPanel 內第一個 Field(說明)
|
|
209
|
+
|
|
210
|
+
- **走規則**:規則 2(Header → 第一個元素)
|
|
211
|
+
- **判 role**:Field = element(局部塊 / 控件感)
|
|
212
|
+
- **答**:`tight`(12/16)
|
|
213
|
+
|
|
214
|
+
### 範例 4:Cmd+K menu list 最後 row → menu 容器底
|
|
215
|
+
|
|
216
|
+
- **走規則**:規則 4
|
|
217
|
+
- **判**:後接 action button?**否** → 看 role:menu list = unbounded region(主導 + 自帶 py 撐)
|
|
218
|
+
- **答**:**0**(概念 B spatial 邊界,list 自帶 py 撐)
|
|
219
|
+
|
|
220
|
+
### 範例 5:Dialog body 最後 field → body 底
|
|
221
|
+
|
|
222
|
+
- **走規則**:規則 4
|
|
223
|
+
- **判**:後接 action button(在 SurfaceFooter 內)?**是** → 套 `bottom 48`
|
|
224
|
+
- **答**:48(概念 A commitment 前留白)。`dialog.tsx:203` body 預設 `pb-bottom` 是此規則的實作(預期 body 後接 SurfaceFooter buttons),非 Dialog 例外
|
|
225
|
+
|
|
226
|
+
### 範例 6:SurfaceFooter 內 [Cancel] ↔ [Save] gap
|
|
227
|
+
|
|
228
|
+
- **走範疇判**(在規則 3 之前):
|
|
229
|
+
- bundled?**是**(`button-group.spec` + `overlay-surface.spec` 都自帶 button arrangement canonical = `gap-2`/8px)
|
|
230
|
+
- → 同範疇 / bundled 第一級,**layoutSpace 一般規則跳過**
|
|
231
|
+
- **答**:`gap-2`(8)— 由 `button-group.tsx:51` / `overlay-surface.tsx:92`(SurfaceFooter)自帶 canonical own
|
|
232
|
+
|
|
233
|
+
**注意**:規則 5「橫排並列」**只**適用 input fields(line 102 明文),不套 button group。Button spacing 屬 bundled-family canonical,不走 layoutSpace 一般 rule。
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 典型容器範例
|
|
238
|
+
|
|
239
|
+
### Form 情境(Field stack 在 Dialog 內)
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
┌────────────────────────────────────┐
|
|
243
|
+
│ Title [X] │ ← SurfaceHeader (chrome, py-tight)
|
|
244
|
+
├────────────────────────────────────┤
|
|
245
|
+
│← tight ─────────────────────────→ │ ← Header → element (規則 2)
|
|
246
|
+
│ ← loose → [Name input] ← loose →│
|
|
247
|
+
│← loose gap ─────────────────────→ │ ← 跨範疇 parallel form fields (規則 3 不相關)
|
|
248
|
+
│ ← loose → [Description] ← loose →│
|
|
249
|
+
│← loose ─────────────────────────→ │
|
|
250
|
+
│ ← loose → [Other field] ← loose →│
|
|
251
|
+
│← bottom 48 ────────────────────→ │ ← 最後內容 → action buttons (規則 4 line 1, 概念 A)
|
|
252
|
+
├────────────────────────────────────┤ ← SurfaceFooter border-t
|
|
253
|
+
│ ← loose → [Cancel] [Save] ← loose →│ ← Footer (chrome, py-tight)
|
|
254
|
+
└────────────────────────────────────┘
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Page 情境(全頁 list / dashboard)
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
┌────────────────────────────────────┐
|
|
261
|
+
│ ← loose → [Toolbar items] ← loose →│ ← Toolbar(自帶 py-tight,跨範疇 functional → table 規則 3 tight)
|
|
262
|
+
│╔══════════════════════════════════╗│
|
|
263
|
+
│║← loose → DataTable ← loose →║│ ← bounded region(規則 1 內 px = loose)
|
|
264
|
+
│╚══════════════════════════════════╝│
|
|
265
|
+
│← loose ─────────────────────────→ │ ← bounded region → 底部 chrome band(規則 4)
|
|
266
|
+
│ ← loose → [Alert hint] ← loose →│ ← 底部 chrome band
|
|
267
|
+
│ ← loose → [BulkActionBar] ← loose →│
|
|
268
|
+
└────────────────────────────────────┘
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 模式切換
|
|
274
|
+
|
|
275
|
+
```html
|
|
276
|
+
<html data-density="md">
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
document.documentElement.setAttribute('data-density', 'lg')
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
單獨控制版面間距而不影響元件尺寸:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
document.documentElement.setAttribute('data-layout-space', 'lg')
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Notes
|
|
292
|
+
|
|
293
|
+
- **不抽 universal LayoutBody / FormLayout primitive**:world-class(Material / Polaris / Atlassian / Carbon / Mantine)都「每元件 own variant + 共享 token」;規則 1-6 universal,角色 scope-relative 易誤封裝。獨特 chrome 已在 `overlay-surface.spec.md` + `action-bar.spec.md`
|
|
294
|
+
- **List-as-region in overlay body**(2026-05-01 canonical):當 Dialog / Sheet / Popover body 內容 = unbounded list-as-region(menu / Cmd+K / nav)時,consumer 用 className override 撤掉 chrome padding(`<DialogBody className="!px-0 !pt-0 !pb-0">`)+ 自管 list outer wrapper(`<div className="py-2">`)+ item 自帶 `px-loose rounded-md`。**不做成 body variant**(`flush?: boolean`)— Material/Atlassian/Mantine/shadcn 都 consumer 自管,Polaris flush API scope 極窄;variant 不解決底層脆弱(加 1 row search/banner 就破功),反把 1 surface decision 拆兩 API。詳 `overlay-surface.spec.md`「List-as-region in overlay body」+ `dialog.tsx:165` JSDoc
|
|
295
|
+
- **v1 → v6**(2026-04-30):block-adjacent 機械 → 親疏判 + bundled-family 分權 + region 二分(bounded/unbounded)+ 多 region 限制。詳 git + memory `feedback_layout_v6_canonical.md`
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
300
|
+
|
|
301
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
302
|
+
|
|
303
|
+
- `description-list.spec.md`
|
|
304
|
+
- `dialog.spec.md`
|
|
305
|
+
- `empty.spec.md`
|
|
306
|
+
- `file-viewer.spec.md`
|
|
307
|
+
- `overlay-surface.spec.md`
|
|
308
|
+
- `uiSize.spec.md`
|
|
309
|
+
|
|
310
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
311
|
+
|
|
312
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
313
|
+
|
|
314
|
+
- `app-shell.spec.md`
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: motion
|
|
3
|
+
family: token
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes: {}
|
|
6
|
+
traits: []
|
|
7
|
+
benchmark:
|
|
8
|
+
- Material Design 3 motion tokens: m3.material.io/styles/motion/easing-and-duration
|
|
9
|
+
- Carbon Design System duration tokens: carbondesignsystem.com/guidelines/motion/overview
|
|
10
|
+
- Atlassian @atlaskit/tokens motion: atlassian.design/tokens/all-tokens#motion
|
|
11
|
+
- Radix Tooltip delayDuration: radix-ui.com/primitives/docs/components/tooltip
|
|
12
|
+
- MUI Tooltip enterDelay: mui.com/material-ui/api/tooltip
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
16
|
+
|
|
17
|
+
# Motion tokens — hover delay 設計原則
|
|
18
|
+
|
|
19
|
+
> **Foundational SSOT rationale**(2026-05-18 ship per user 拍板 #3A):跨 5+ overlay 消費者
|
|
20
|
+
> (Tooltip / HoverCard / NameCard / Avatar / OverflowIndicator)的 hover 開啟 / 關閉延遲統一。
|
|
21
|
+
|
|
22
|
+
## 定位
|
|
23
|
+
|
|
24
|
+
Hover delay token 是「hover 觸發 → overlay 顯示」之間的等待時間。**目的不是動畫長度,是「user 真的想看」過濾器** — 短暫滑過不該觸發 expensive overlay(NameCard fetch 資料 / Tooltip 視覺擾動)。
|
|
25
|
+
|
|
26
|
+
## 三層 tier 系統
|
|
27
|
+
|
|
28
|
+
| Token | 值 | 用於 | 為何 |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| `--hover-delay-plain` | `500ms` | Tooltip 純文字提示 | 被動 hint,需 user「真停留」才觸發,避免滑過列表時 N 次視覺擾動。對齊 Material 3 plain tooltip 500ms / Apple HIG ~500ms / shadcn-Radix default 500ms 主流共識 |
|
|
31
|
+
| `--hover-delay-rich` | `700ms` | HoverCard / NameCard 內容預覽 | 含 avatar / fields / actions 的 rich content(可能含 fetch)。User 必須「真的想看」才停留 700ms,避免列表掃視時誤觸發 N 個 fetch waterfall |
|
|
32
|
+
| `--hover-delay-close` | `200ms` | 所有 overlay 關閉 | Mouse leave 後給 200ms 緩衝(user 可能誤滑出再回來)。對齊 UX 共識「close delay ≤ open delay」+ 既有 Avatar `closeDelay={200}` 值 |
|
|
33
|
+
|
|
34
|
+
## 為何不用單一值 / 為何不沿用過去 200ms
|
|
35
|
+
|
|
36
|
+
- **過去 200/300ms 偏快**(2026-05-18 ship,2026-05-20 user 抓「太快很容易干擾人」撤回):200ms plain 滑過列表 N 次觸發 Tooltip 視覺擾動;300ms rich 在含 fetch 的 HoverCard 場景列表掃視會打 N 次 server request waterfall。
|
|
37
|
+
- **MUI/Ant 100ms 是 fast-tier 例外**:適合 form input help text 等「我就是要快」的 dense 場景,不適合通用 chrome tooltip。
|
|
38
|
+
- **單一值** 失去 plain / rich 語意區分:NameCard 含 fetch + image + actions 應比 Tooltip(純文字)delay 長,單一值會讓 NameCard 滑過列表時整列誤觸發 fetch waterfall。
|
|
39
|
+
- **過短**(< 100ms):每滑必觸發 → 視覺擾動 + 不必要 server request。
|
|
40
|
+
- **過長**(> 1s):user 已不期待 overlay,等出來變干擾。
|
|
41
|
+
|
|
42
|
+
## 何時用 / 何時不用
|
|
43
|
+
|
|
44
|
+
| 場景 | 用哪 token | 為何 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Icon-only Button → 顯示文字提示 | `--hover-delay-plain` | 純文字輔助 |
|
|
47
|
+
| Avatar / Username → 顯示完整人物卡 | `--hover-delay-rich` | 含 fetch + multi-section content |
|
|
48
|
+
| OverflowIndicator → 顯示隱藏列表 | `--hover-delay-plain` | 純列表展開,無 fetch |
|
|
49
|
+
| Tag / Chip → 顯示說明 | `--hover-delay-plain` | 純文字 |
|
|
50
|
+
| 任何 overlay 關閉延遲 | `--hover-delay-close` | universal |
|
|
51
|
+
| Click-triggered Popover / Dialog | — | N/A,click 不適用 hover delay |
|
|
52
|
+
| Tooltip 鍵盤 focus 觸發 | — | N/A,直接顯示(對齊 WAI-ARIA APG) |
|
|
53
|
+
|
|
54
|
+
## 命名 rationale(per `# 命名與語言一致性` 3 test)
|
|
55
|
+
|
|
56
|
+
1. **既有 DS 詞彙**:`plain` / `rich` 對齊 FileItem `compact / rich` mode tier idiom(world-class richness gradient)
|
|
57
|
+
2. **世界級 idiom**:Material 3 documentation 公開使用「plain tooltip」+「rich tooltip」術語(verified URL above) <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
58
|
+
3. **跨元件無語意衝突**:`plain` 不撞 cva variant(無元件用 `variant="plain"`);`rich` 跟 FileItem mode 同義(content density gradient)
|
|
59
|
+
|
|
60
|
+
### Anti-pattern 避免命名
|
|
61
|
+
|
|
62
|
+
- ❌ `--hover-delay-tooltip` / `--hover-delay-hovercard` — 元件名綁定 → 新元件(Popover variant)用哪個?
|
|
63
|
+
- ❌ `--delay-200` / `--delay-300` — 用值不用語意 → 改值要 rename
|
|
64
|
+
- ❌ `--motion-hover-fast` / `--motion-hover-slow` — fast/slow 在 hover 語境語意模糊(對 user 來說「fast」應該是 instant?)
|
|
65
|
+
- ❌ `--hover-time` / `--mouseover-pause` — 自創縮寫,跨人不可讀
|
|
66
|
+
|
|
67
|
+
## 消費者
|
|
68
|
+
|
|
69
|
+
- `components/Avatar/avatar.tsx:299` — HoverCard openDelay / closeDelay(原硬寫 300/200,migrate 到 token)
|
|
70
|
+
- `components/HoverCard/hover-card.tsx` — Radix Provider 預設 delayDuration override 為 `--hover-delay-rich`
|
|
71
|
+
- `components/Tooltip/tooltip.tsx` — Radix Provider 預設 delayDuration override 為 `--hover-delay-plain`
|
|
72
|
+
- `components/NameCard/name-card.tsx`(consumer of HoverCard)— 繼承 `--hover-delay-rich`
|
|
73
|
+
- `components/OverflowIndicator/overflow-indicator.tsx`(consumer)— 用 `--hover-delay-plain`
|
|
74
|
+
- 任何 future overlay hover consumer 必 import 此 token(per M17 SSOT 必可傳播)
|
|
75
|
+
|
|
76
|
+
## 世界級對照
|
|
77
|
+
|
|
78
|
+
| Framework | plain hint delay | rich preview delay |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Material 3(plain vs rich tooltip 分流)| ~500ms | ~500ms+ |
|
|
81
|
+
| Apple HIG / macOS native | ~500ms | — |
|
|
82
|
+
| Radix Tooltip | 700ms(設保守避 mobile / touch 誤觸)| N/A(consumer 自定) |
|
|
83
|
+
| shadcn(defer Radix) | 500ms(provider override)| N/A |
|
|
84
|
+
| Polaris | 400ms | — |
|
|
85
|
+
| Atlassian Tooltip | 300ms | — |
|
|
86
|
+
| MUI / Ant Tooltip | 100ms(dense form input fast-tier) | — |
|
|
87
|
+
| **DS canonical(本 spec)** | **500ms** | **700ms** |
|
|
88
|
+
|
|
89
|
+
500ms 對齊 Material 3 / Apple HIG / shadcn 主流共識(三家集中在 500ms),避 MUI/Ant 100ms(form input fast-tier 不適通用 chrome)+ Radix 700(過保守)兩極端。Rich 700ms 比 plain 多 200ms 反映 fetch / multi-section content「真的想看」門檻。
|
|
90
|
+
|
|
91
|
+
## 相關
|
|
92
|
+
|
|
93
|
+
- `../elevation/elevation.spec.md` — overlay 視覺層(z-index)
|
|
94
|
+
- `../../patterns/overlay-surface/overlay-surface.spec.md` — overlay 結構 SSOT
|
|
95
|
+
- `../../components/Tooltip/tooltip.spec.md`(consumer)
|
|
96
|
+
- `../../components/HoverCard/hover-card.spec.md`(consumer)
|
|
97
|
+
- `../../components/Avatar/avatar.spec.md`(consumer)
|