@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.
Files changed (307) hide show
  1. package/CLAUDE.md +201 -0
  2. package/README.md +7 -15
  3. package/cli-init.mjs +90 -0
  4. package/ds-canonical/commands/README.md +26 -0
  5. package/ds-canonical/commands/gov-status.md +79 -0
  6. package/ds-canonical/hooks/README.md +145 -0
  7. package/ds-canonical/hooks/_log-fire.sh +44 -0
  8. package/ds-canonical/hooks/block_prototype_imports.py +111 -0
  9. package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
  10. package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
  11. package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
  12. package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
  13. package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
  14. package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
  15. package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
  16. package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
  17. package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
  18. package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
  19. package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
  20. package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
  21. package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
  22. package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
  23. package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
  24. package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
  25. package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
  26. package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
  27. package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
  28. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
  29. package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
  30. package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
  31. package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
  32. package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
  33. package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
  34. package/ds-canonical/hooks/check_story_invariants.sh +612 -0
  35. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
  36. package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
  37. package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
  38. package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
  39. package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
  40. package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
  41. package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
  42. package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
  43. package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
  44. package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
  45. package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
  46. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
  47. package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
  48. package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
  49. package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
  50. package/ds-canonical/hooks/log_governance_fires.sh +50 -0
  51. package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
  52. package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
  53. package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
  54. package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
  55. package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
  56. package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
  57. package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
  58. package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
  59. package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
  60. package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
  61. package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
  62. package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
  63. package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
  64. package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
  65. package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
  66. package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
  67. package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
  68. package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
  69. package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
  70. package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
  71. package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
  72. package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
  73. package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
  74. package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
  75. package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
  76. package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
  77. package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
  78. package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
  79. package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
  80. package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
  81. package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
  82. package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
  83. package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
  84. package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
  85. package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
  86. package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
  87. package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
  88. package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
  89. package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
  90. package/ds-canonical/hooks/stop_self_audit.sh +450 -0
  91. package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
  92. package/ds-canonical/hooks/tests/run-all.sh +76 -0
  93. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
  94. package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
  95. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
  96. package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
  97. package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
  98. package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
  99. package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
  100. package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
  101. package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
  102. package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
  103. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
  104. package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
  105. package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
  106. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
  107. package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
  108. package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
  109. package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
  110. package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
  111. package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
  112. package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
  113. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
  114. package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
  115. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
  116. package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
  117. package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
  118. package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
  119. package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
  120. package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
  121. package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
  122. package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
  123. package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
  124. package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
  125. package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
  126. package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
  127. package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
  128. package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
  129. package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
  130. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
  131. package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
  132. package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
  133. package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
  134. package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
  135. package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
  136. package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
  137. package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
  138. package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
  139. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
  140. package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
  141. package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
  142. package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
  143. package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
  144. package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
  145. package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
  146. package/ds-canonical/references/README.md +43 -0
  147. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
  148. package/ds-canonical/references/build-ui-canonicals.md +69 -0
  149. package/ds-canonical/references/cva-patterns.md +41 -0
  150. package/ds-canonical/references/drag-canonical.md +331 -0
  151. package/ds-canonical/references/item-anatomy-recipe.md +225 -0
  152. package/ds-canonical/references/naming-conventions.md +56 -0
  153. package/ds-canonical/references/principle-dim-map.json +515 -0
  154. package/ds-canonical/references/props-naming.md +45 -0
  155. package/ds-canonical/references/spec-rules.md +58 -0
  156. package/ds-canonical/references/ssot-consultation.md +63 -0
  157. package/ds-canonical/references/ssot-index.md +40 -0
  158. package/ds-canonical/references/story-baseline-registry.json +79 -0
  159. package/ds-canonical/references/structural-token-retention.md +42 -0
  160. package/ds-canonical/references/tailwind-gotchas.md +87 -0
  161. package/ds-canonical/references/ui-dev-rules.md +60 -0
  162. package/ds-canonical/rules/README.md +34 -0
  163. package/ds-canonical/rules/meta-patterns.md +87 -0
  164. package/ds-canonical/rules/self-verify.md +53 -0
  165. package/ds-canonical/rules/spec-rules.md +25 -0
  166. package/ds-canonical/rules/story-rules.md +56 -0
  167. package/ds-canonical/rules/ui-development.md +87 -0
  168. package/ds-canonical/skills/README.md +88 -0
  169. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
  170. package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
  171. package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
  172. package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
  173. package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
  174. package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
  175. package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
  176. package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
  177. package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
  178. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
  179. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
  180. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
  181. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
  182. package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
  183. package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
  184. package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
  185. package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  186. package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
  187. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
  188. package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
  189. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
  190. package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
  191. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
  192. package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
  193. package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
  194. package/ds-canonical/skills/governance-health/SKILL.md +146 -0
  195. package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
  196. package/ds-canonical/skills/new-component/SKILL.md +170 -0
  197. package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
  198. package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
  199. package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
  200. package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
  201. package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
  202. package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
  203. package/ds-canonical/skills/propose-options/SKILL.md +177 -0
  204. package/ds-canonical/skills/prototype/SKILL.md +244 -0
  205. package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
  206. package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
  207. package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
  208. package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
  209. package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
  210. package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
  211. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
  212. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
  213. package/ds-canonical/skills/story-writing/SKILL.md +122 -0
  214. package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
  215. package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
  216. package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
  217. package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
  218. package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
  219. package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
  220. package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
  221. package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
  222. package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
  223. package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  224. package/package.json +9 -5
  225. package/src/components/Accordion/accordion.spec.md +114 -0
  226. package/src/components/Alert/alert.spec.md +197 -0
  227. package/src/components/AppShell/app-shell.spec.md +331 -0
  228. package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
  229. package/src/components/Avatar/avatar.spec.md +329 -0
  230. package/src/components/Badge/badge.spec.md +380 -0
  231. package/src/components/Breadcrumb/breadcrumb.spec.md +257 -0
  232. package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
  233. package/src/components/Button/button.spec.md +460 -0
  234. package/src/components/Calendar/calendar.spec.md +242 -0
  235. package/src/components/Carousel/carousel.spec.md +253 -0
  236. package/src/components/Chart/chart.spec.md +155 -0
  237. package/src/components/Checkbox/checkbox.spec.md +344 -0
  238. package/src/components/Chip/chip.spec.md +237 -0
  239. package/src/components/CircularProgress/circular-progress.spec.md +268 -0
  240. package/src/components/Coachmark/coachmark.spec.md +230 -0
  241. package/src/components/Combobox/combobox.spec.md +180 -0
  242. package/src/components/Command/command.spec.md +171 -0
  243. package/src/components/DataTable/data-table.spec.md +525 -0
  244. package/src/components/DateGrid/date-grid.spec.md +215 -0
  245. package/src/components/DatePicker/date-picker.spec.md +334 -0
  246. package/src/components/DescriptionList/description-list.spec.md +214 -0
  247. package/src/components/Dialog/dialog.spec.md +202 -0
  248. package/src/components/DropdownMenu/dropdown-menu.spec.md +250 -0
  249. package/src/components/Empty/empty.spec.md +214 -0
  250. package/src/components/Field/field-controls.spec.md +338 -0
  251. package/src/components/Field/field.spec.md +438 -0
  252. package/src/components/Field/form-validation.spec.md +152 -0
  253. package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
  254. package/src/components/FileItem/file-item.spec.md +467 -0
  255. package/src/components/FileUpload/file-upload.spec.md +123 -0
  256. package/src/components/FileViewer/file-viewer.spec.md +373 -0
  257. package/src/components/HoverCard/hover-card.spec.md +157 -0
  258. package/src/components/Input/input.spec.md +193 -0
  259. package/src/components/LinkInput/link-input.spec.md +130 -0
  260. package/src/components/Menu/menu-item.spec.md +290 -0
  261. package/src/components/NameCard/name-card.spec.md +171 -0
  262. package/src/components/Notice/notice.spec.md +149 -0
  263. package/src/components/NumberInput/number-input.spec.md +126 -0
  264. package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
  265. package/src/components/PeoplePicker/people-picker.spec.md +263 -0
  266. package/src/components/Popover/popover.spec.md +198 -0
  267. package/src/components/ProgressBar/progress-bar.spec.md +232 -0
  268. package/src/components/RadioGroup/radio-group.spec.md +141 -0
  269. package/src/components/Rating/rating.spec.md +208 -0
  270. package/src/components/ScrollArea/scroll-area.spec.md +145 -0
  271. package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
  272. package/src/components/Select/select.spec.md +299 -0
  273. package/src/components/SelectMenu/select-menu.spec.md +220 -0
  274. package/src/components/SelectionControl/selection-item.spec.md +128 -0
  275. package/src/components/Separator/separator.spec.md +109 -0
  276. package/src/components/Sheet/sheet.spec.md +148 -0
  277. package/src/components/Sidebar/sidebar.spec.md +713 -0
  278. package/src/components/Skeleton/skeleton.spec.md +104 -0
  279. package/src/components/Slider/slider.spec.md +353 -0
  280. package/src/components/Steps/steps.spec.md +465 -0
  281. package/src/components/Switch/switch.spec.md +215 -0
  282. package/src/components/Tabs/tabs.spec.md +314 -0
  283. package/src/components/Tag/tag.spec.md +282 -0
  284. package/src/components/Textarea/textarea.spec.md +151 -0
  285. package/src/components/TimePicker/time-picker.spec.md +279 -0
  286. package/src/components/Toast/toast.spec.md +177 -0
  287. package/src/components/Tooltip/tooltip.spec.md +139 -0
  288. package/src/components/TreeView/tree-view.spec.md +374 -0
  289. package/src/patterns/action-bar/action-bar.spec.md +458 -0
  290. package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
  291. package/src/patterns/element-anatomy/inline-action.spec.md +315 -0
  292. package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
  293. package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
  294. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
  295. package/src/patterns/overlay-surface/overlay-surface.spec.md +428 -0
  296. package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
  297. package/src/tokens/color/color.spec.md +804 -0
  298. package/src/tokens/density/density.spec.md +127 -0
  299. package/src/tokens/elevation/elevation.spec.md +81 -0
  300. package/src/tokens/layoutSpace/layoutSpace.spec.md +314 -0
  301. package/src/tokens/motion/motion.spec.md +97 -0
  302. package/src/tokens/opacity/opacity.spec.md +78 -0
  303. package/src/tokens/orphan-tokens.spec.md +117 -0
  304. package/src/tokens/radius/radius.spec.md +123 -0
  305. package/src/tokens/typography/typography.spec.md +202 -0
  306. package/src/tokens/uiSize/uiSize.spec.md +438 -0
  307. package/src/styles/preset.css +0 -31
@@ -0,0 +1,380 @@
1
+ ---
2
+ component: Badge
3
+ family: 3
4
+ variants:
5
+ critical:
6
+ when: "最高優先級通知 — 錯誤計數 / 緊急徽章(Gmail 未讀 / iOS notification red dot)"
7
+ world-class: ["Polaris Badge tone=critical", "Material Badge error", "Ant Badge status=error / count"]
8
+ high:
9
+ when: "高優先級通知 — 主要計數(Slack 訊息計數 / GitHub PR review badge)"
10
+ world-class: ["Polaris Badge tone=info", "Material Badge primary", "Atlassian Lozenge inProgress"]
11
+ medium:
12
+ when: "中優先級提示 — 次級計數(Linear issue count / Notion sidebar indicator)"
13
+ world-class: ["Polaris Badge tone=info subtle", "Ant Badge status=processing"]
14
+ low:
15
+ when: "低強度指示 — 使用者切 tab 才看(Slack sidebar 靜默標記 / VS Code tab modified dot)"
16
+ world-class: ["Polaris Badge tone=new", "GitHub subtle count"]
17
+ sizes: {}
18
+ traits:
19
+ - hasVariants
20
+ - isMatrixHeavy
21
+ benchmark:
22
+ - Ant Design Badge: github.com/ant-design/ant-design/tree/master/components/badge
23
+ - MUI Badge: github.com/mui/material-ui/tree/master/packages/mui-material/src/Badge
24
+ - Polaris Badge: github.com/Shopify/polaris/tree/main/polaris-react/src/components/Badge
25
+ ---
26
+
27
+ <!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
28
+
29
+ # Badge 設計原則
30
+
31
+ ## 定位
32
+
33
+ Badge 是通知計數指示器,用於未讀數量、待辦計數、狀態紅點。不是分類標籤(那是 Tag)。
34
+
35
+ **Layout Family**:非上述 family — self-contained primitive(獨立視覺,無 slot 結構)。
36
+
37
+ **實作基礎**:純視覺 atom——styled span,無 external primitive base。
38
+
39
+ ---
40
+
41
+ ## 何時用
42
+
43
+ - **通知計數**:收件匣未讀數(3)、待辦事項數(12)、notification center 新訊息數
44
+ - **狀態紅點**(dot 模式):新功能提示、「有新內容」不需具體數字
45
+ - **版本 / 角色標記**:「Beta」、「Pro」、「Admin」(當視覺重量需要比 Tag 更輕時)
46
+ - **疊加在互動元件右上角**:Button iconOnly + Badge 通知 icon(鈴鐺 + 3)
47
+
48
+ ## 何時不用
49
+
50
+ | 場景 | 改用 | 原因 |
51
+ |------|------|------|
52
+ | 分類標籤(產品類別、角色分類)| `Tag` | Tag 較大、可含 icon/dismiss,適合承載語意;Badge 是計數指示器 |
53
+ | 狀態描述(In stock / Out of stock)| `Tag` + 色彩 | 狀態語意用 Tag 的 variant 系統(green/yellow/red)更明確 |
54
+ | 過濾 / 選擇(filter chip)| `Chip` | Badge 不可互動,Chip 是 filter 選取 |
55
+ | Loading 指示 | `CircularProgress` | Badge 是數字或 dot,loading 用旋轉動畫 |
56
+
57
+ ---
58
+
59
+ ## 層級(Variant)
60
+
61
+ 四個層級代表**通知內容的緊急程度**——從 low(被動資訊)到 critical(立即處理)。
62
+
63
+ **核心原則:Default LOW, escalate only with reason.**
64
+
65
+ Badge 的 level **反映內容的緊急程度,不是 container 的視覺權重**——從 low 起跳,只有當通知內容本身值得更多注意力時才升級。這樣 critical 的紅色從「罕見」獲得信號價值,過度使用會讓使用者麻木、無法分辨真正的急迫。
66
+
67
+ | Variant | 視覺 | 使用者錯過會怎樣 |
68
+ |---------|------|------------------|
69
+ | `low`(起點)★ cva default | 灰底灰字(neutral-3 + neutral-7) | **無影響**——只是「目前有這麼多」的資訊,不讀也沒關係 |
70
+ | `medium` | 淺藍底藍字(bg-info-subtle) | **輕微不便**——少了資訊但不影響主要流程 |
71
+ | `high` | 藍底白字(bg-info) | **有感影響**——工作會堆積、待辦會過期,但不是立即傷害 |
72
+ | `critical` | 紅底白字(bg-notification) | **直接傷害**——錯過訊息會造成資料遺失 / 錯過機會 / 帳戶問題 |
73
+
74
+ ### 選 level 的流程
75
+
76
+ **從 low 起跳,四步驟逐步升級**。每一步都要有**明確理由**才升級;沒理由就留在 low。
77
+
78
+ 1. **從 low 開始問**:這是「被動計數」嗎?(Inbox 總數、已完成數、tab item 內容總數)→ 是 → **用 low**
79
+ 2. **升到 medium**:是「供參考、可延後看的資訊」嗎?(評論數、更新數)→ 是 → **升 medium**
80
+ 3. **升到 high**:是「有感影響的待辦」嗎?(未完成 task、已套用 filter 數)→ 是 → **升 high**
81
+ 4. **升到 critical**:是「立即需要處理的急迫」嗎?(錯誤計數、付款失敗、未讀私訊)→ 是 → **升 critical**
82
+
83
+ ### 具體場景對照(從 low 起跳順序)
84
+
85
+ | 場景 | Level | 為什麼 |
86
+ |------|-------|--------|
87
+ | Tab item 的內容總數(「文件 (12)」) | `low` | 使用者切 tab 才看,不需搶注意力 |
88
+ | Archive / Trash 數量 | `low` | 被動資訊,使用者只在需要時才看 |
89
+ | Inbox 總數(不是「未讀」) | `low` | 參考數字,無 call-to-action |
90
+ | 已完成 task 總數 | `low` | 成就指標,不期待使用者關注 |
91
+ | 可用更新數量(套件、訂閱) | `medium` | 有參考價值,延遲看不影響 |
92
+ | 評論 / 回覆計數 | `medium` | 社交互動,可延後處理 |
93
+ | 新功能提示(NEW / Beta)| `high` | 重要但可延後,非必要立即處理 |
94
+ | 待辦事項計數 | `high` | 工作會堆積,有感影響 |
95
+ | Active toggle 顯示計數(如 Filter [3]、Bold pressed 的套用數)| `high`(或 `medium`)| Active 狀態補充資訊,不是急迫訊號 |
96
+ | 通知中心 bell icon 的數字 | `high` 或 `critical` | 視內部通知性質,全是急迫才 critical |
97
+ | Email / Slack 未讀訊息 | `critical` | 錯過會錯過溝通,紅色觸發 action |
98
+ | 錯誤計數(表單 / CI) | `critical` | 必須立即處理才能繼續 |
99
+ | 帳戶警告(付款失敗、到期) | `critical` | 有金錢 / 服務中斷風險 |
100
+
101
+ ### 色彩硬規則(不可違反)
102
+
103
+ - **❌ Critical 不是紅色就是錯誤**——critical 永遠 `bg-notification`(紅)。改色等於改信號語意,稀釋紅色在產品內的「急迫」意義
104
+ - **❌ High 不能用紅色**——會跟 critical 搶信號。藍色是「重要但不急」的全球共識
105
+ - **❌ 不能為了「視覺統一」把所有 badge 降 level**——使用者需要看到 level 差異才能分配注意力,全部 low 等於沒 badge
106
+ - **❌ 不能為了「強調」把 low 升 level**——升 level 改變的是「這件事多重要」的承諾,不是消費者的偏好
107
+
108
+ ### 級別使用頻率的自我檢查
109
+
110
+ 一個畫面上**最多 1-2 個 `critical` badge**。更多代表:
111
+ 1. 使用者真的有多個急迫狀況(罕見)→ 合理
112
+ 2. 把不急迫的事標成 critical(常見錯誤)→ 降級
113
+
114
+ ### 層級與容器的關係:雙重約束
115
+
116
+ Badge level 同時受**兩個約束**,取較高者:
117
+
118
+ - **Semantic level(業務需求)**:內容真正的 urgency,按「選 level 的流程」從 low 起跳
119
+ - **Contrast floor(可見度下限)**:container 的 bg 決定 badge **至少** 要是哪個 level 才看得清
120
+
121
+ **最終 level = max(semantic, contrast floor)**
122
+
123
+ 兩個約束各自可以獨立推高 level:
124
+ - 業務需求更急 → 升 semantic → 拉高最終 level
125
+ - Container bg 更深 → 提高 contrast floor → 拉高最終 level
126
+
127
+ Contrast floor **是下限不是上限**——不限制 semantic 繼續往上。業務需求永遠可以再升。
128
+
129
+ ### 三種常見情況
130
+
131
+ | 情況 | Semantic | Contrast floor | 最終 | 說明 |
132
+ |------|---------|----------------|------|------|
133
+ | **Case 1:semantic ≥ floor** | `high` | `low`(text button)| `high` | 用 semantic,contrast 不是問題 |
134
+ | **Case 2:semantic < floor** | `low`(passive count)| `high`(primary button)| `high` | 被迫 bump 到 floor——**設計錯配訊號** |
135
+ | **Case 3:後來業務升級** | 原 `high` → 新 `critical` | `high` | `critical` | semantic 升,最終跟著升,不受 floor 封頂 |
136
+
137
+ ### 各容器的 contrast floor 對照
138
+
139
+ | 容器 | Contrast floor | 多數 semantic 可直接用 |
140
+ |------|----------------|---------------------|
141
+ | text / tab item / icon button(透明 / 極淺) | `low` | ✓ 99% 場景 |
142
+ | secondary / tertiary(淺底帶邊框) | `low` | ✓ |
143
+ | checked(pressed state,通常淺灰或 subtle 底) | `low` / `medium` | ✓ 多數直接用;bg 較深時 floor 提高 |
144
+ | primary / secondary+danger(飽和深底) | `high` | low/medium 被迫 bump;high/critical 直接用 |
145
+
146
+ **Critical 的紅白對比在任何底色上都清楚**——不存在「critical 看不清」的場景。
147
+
148
+ ### Case 2 是設計錯配訊號
149
+
150
+ 若 semantic = low(passive count)+ contrast floor = high/critical(primary button),被迫跨 2+ 階 bump,代表 **badge 放錯地方**:
151
+
152
+ 1. **問:這個 badge 真的屬於這裡嗎?** primary button 強調 action,passive 計數在此語意矛盾
153
+ 2. **用 dot 模式取代 count**:純圓點傳達「有東西」但不干擾主 action
154
+ 3. **把 badge 移到外部**:按鈕旁邊 label 顯示計數,而非疊在按鈕上
155
+ 4. **乾脆不放 badge**:passive 資訊在強 CTA 上本來就次要
156
+
157
+ **Case 1 和 Case 3 永遠合法**——semantic 本身高,不受 floor 影響。只有 Case 2(被迫跨階 bump)才是警訊。
158
+
159
+ ---
160
+
161
+ ## 字體例外:`text-[10px]`(documented sub-footnote)
162
+
163
+ Badge count 模式的數字使用 `text-[10px]`,低於 typography 系統最小的 `--font-footnote`(12px)。這是 **Badge 獨有的合法例外**:
164
+
165
+ - **為什麼不加新 typography token**: 10px 是「count indicator 專用尺寸」,全系統**只有 Badge / OverflowIndicator 兩處**使用;創一個 `--font-micro` token 只為這兩個消費者會過度 generalization
166
+ - **為什麼合法**: Badge count 是輔助 indicator(次要訊號),12px 字寬在 16×16 的圓形 Badge 內缺乏 padding 呼吸(字徑/圓徑比例過密)。對照世界級:Material Badge 10sp、Polaris Badge 字級小於 body、GitHub Counter 10-11px 都小於 body footnote <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
167
+ - **其他元件不得比照**: 若新元件覺得需要 `text-[10px]`,先問「真的不是 footnote 12px 可以解決嗎」,99% 情境 footnote 夠用;真有需求跟 Badge / OverflowIndicator 歸同一 micro-indicator family 討論
168
+
169
+ ---
170
+
171
+ ## 模式:Count vs Dot
172
+
173
+ 兩種模式傳達不同強度的訊號——**精確數字** vs **存在性指示**。
174
+
175
+ ### Count — 精確數字
176
+
177
+ **何時用**:數字本身有意義(3 vs 30 vs 300 觸發不同 urgency),使用者需要「還剩多少」的資訊。
178
+ - 未讀訊息數、錯誤數、待辦事項數、購物車品項數
179
+ - 使用者會根據數字大小決定行動優先序
180
+
181
+ **實作**:固定高度小於 Field 元件(保持輔助層級);個位數時為正圓,多位數時變膠囊——由 count 長度自動決定形狀。具體 token / class 見 `.tsx` cva。
182
+
183
+ ### Dot — 存在性指示
184
+
185
+ **何時用**:「有東西」本身就是訊號,具體數量不重要或無意義。
186
+ - 新功能提示、「有新內容」、在線狀態、unsaved changes 標示
187
+ - 避免「99+」的視覺噪音時(知道有即可、不需要精確數字)
188
+
189
+ **實作**:小尺寸純色圓點,無文字。具體 size 見 `.tsx` cva。
190
+
191
+ ### 判斷流程
192
+
193
+ 問:「**使用者想知道『有沒有』還是『多少』?**」
194
+ - 知道有就夠 → `dot`
195
+ - 需要數量判斷 urgency → `count`
196
+
197
+ **如果 count 永遠顯示 max+(例如 99+)**:代表資訊超出計數承載力——改用 dot 或提高 max threshold,別讓使用者永遠看到「99+」失去數字價值。
198
+
199
+ ---
200
+
201
+ ## Max 上限的選擇
202
+
203
+ | Max | 適合場景 | 原因 |
204
+ |-----|---------|------|
205
+ | `max={9}` | 錯誤 / 嚴重告警 / 關鍵 task | 超過 9 代表資料異常或需重新設計流程 |
206
+ | `max={99}`(常見預設) | 一般通知、訊息 | 多數 app 的常態分布 |
207
+ | `max={999}` | 社群 / 高頻通知(Twitter / Instagram) | 活躍使用者正常可累積 3 位數 |
208
+ | 無 `max` | 資料需真實反映(報表計數) | UI 寬度需設計側處理 |
209
+
210
+ **Max threshold 應匹配資料常態分布**:
211
+ - 若 99+ 是常態 → threshold 失去區別力,升到 999
212
+ - 若從沒超過 20 → max=99 就夠,太大反而浪費 UI 空間
213
+ - 永遠卡 max+ = 使用者無法判斷「多急迫」,等於沒有 count
214
+
215
+ ---
216
+
217
+ ## 放置模式(Placement)
218
+
219
+ Badge 有三種常見放置,各有不同視覺語意。**企業軟體 80% 情境是 Inline**(列表 / tab / section title 的計數),Overlay 反而是少數;**先從 Inline 開始考慮,只在容器是「單一視覺重心」時才升 Overlay**。
220
+
221
+ ### 判斷流程(企業 > 消費級)
222
+
223
+ ```
224
+ Q1. 容器有 label 嗎?(tab item / menu item / section title / list row)
225
+ → YES → Inline(Slack sidebar channel「# general · 3」/ Linear tab「Todo 12」)
226
+ → NO → Q2
227
+
228
+ Q2. 容器是「單一視覺重心」嗎?(iconOnly button / 純 icon / avatar)
229
+ → YES → Overlay(iOS App icon / bell icon + 3 / Avatar + presence)
230
+ → NO → Q3
231
+
232
+ Q3. Badge 自己獨立呈現狀態嗎?(無宿主元件)
233
+ → YES → Standalone(「● 離線 Alex」狀態 row)
234
+ ```
235
+
236
+ **為什麼 Inline 在企業更常見**:
237
+ - B2B 介面充滿「label + 計數」場景:tab(Todo 12 / Done 5)/ sidebar section(Projects 8 / Archive)/ menu item(Settings · 2 待處理)
238
+ - Overlay 需要額外 `aria-label` 整合(「通知 (3 則)」),inline 直接讀「文件 12」—— 語意更直接
239
+ - 企業 UI 的 container 多帶 label,天生適合 inline;消費級(iOS home / WhatsApp chat)大量 icon-only chrome 才大量用 overlay
240
+
241
+ ### 1. Overlay(疊加在元件角落)
242
+
243
+ ```tsx
244
+ // ✅ Canonical:Button 的 overlayBadge prop — badge 內部貼 icon 右上角
245
+ <Button variant="tertiary" size="sm" iconOnly startIcon={Bell}
246
+ aria-label="通知 (3 則)"
247
+ overlayBadge={<Badge count={3} variant="high" />} />
248
+
249
+ // ✅ Avatar 走自己的 badgeCount / status prop(見 avatar.spec.md)
250
+ <Avatar alt="Ada" size={40} status="online" badgeCount={3} />
251
+
252
+ // ❌ Anti-pattern:手刻 relative + absolute 定位 button chrome 角落
253
+ <div className="relative inline-flex">
254
+ <Button iconOnly startIcon={Bell} />
255
+ <Badge count={3} className="absolute -top-1 -right-1" /> // ← 離 icon 太遠
256
+ </div>
257
+ ```
258
+
259
+ - **語意**:元件主內容(icon / avatar)+ 補充通知
260
+ - **實作**:badge **絕對定位相對於 icon / avatar 視覺重心**,不相對於 interactive chrome。Button `overlayBadge` prop 內部用 `<span className="relative inline-flex">` 包 icon、badge 中心對齊 icon top-right corner(Material BadgedBox canonical)。**不再允許** consumer 手刻 `<div relative><Button/><Badge absolute/></div>`——padding 差距會讓 badge 飄到 chrome 角 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
261
+ - **世界級對照**:Material BadgedBox / iOS App Icon / Ant Design Badge — 全部 wrap 視覺重心(icon / avatar),不 wrap interactive chrome(button padding) <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
262
+ - **aria**:parent 元件的 `aria-label` 包含 badge 資訊(見「無障礙」)
263
+
264
+ ### Overlay 適用元件 canonical(2026-04-20)
265
+
266
+ **Overlay 只疊在「單一視覺重心」元件上**:
267
+ - ✅ **iconOnly Button**(按鈕本身 = icon,badge 疊 icon 角落語義清楚)
268
+ - ✅ **Avatar**(圓 / 方 avatar 本身 = 單一視覺)
269
+ - ✅ **純 Icon**(inline Bell / MessageSquare 等)
270
+
271
+ **禁止疊在**:
272
+ - ❌ **text + icon Button**:按鈕寬度遠大於 icon,badge 跑到按鈕右邊緣,離 icon 太遠,視覺上 dot / count 跟 icon 語義無法配對。使用者不會把 "飄在按鈕邊緣的小點" 和齒輪 icon 的 "有新功能" 連結起來。改用:(a) 按鈕改 iconOnly、(b) 移除 overlay 改 inline badge 在 text 後。
273
+ - ❌ **Primary / 主 CTA button**:contrast floor 會逼 badge 升階到 critical,扭曲 passive count 的語意(見「Contrast floor」rule)。Archive 這種歸檔動作本來就不該是 primary;正確做法是按鈕降級 tertiary + badge 回歸 low。
274
+
275
+ 世界級對照:iOS / Material / macOS / Slack 的 badge dot 永遠貼在 **App icon 或單一 icon** 上,從不疊在「icon + text」的 inline button 右上角。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
276
+
277
+ ### 2. Inline(跟 label 並列)
278
+
279
+ Tab / Menu item / Section title 旁邊顯示計數。
280
+
281
+ ```tsx
282
+ <div className="flex items-center gap-2">
283
+ <span>文件</span>
284
+ <Badge count={12} variant="low" />
285
+ </div>
286
+ ```
287
+
288
+ - **語意**:label + 計數,一體展示
289
+ - **實作**:不用 absolute,`gap` 控制間距
290
+ - **常見錯誤**:把 inline 場景的 badge 做成 overlay,label 和 badge 視覺斷開
291
+
292
+ ### 3. Standalone(獨立狀態指示)
293
+
294
+ 作為狀態 dot 獨立存在,無宿主元件。
295
+
296
+ ```tsx
297
+ <div className="flex items-center gap-2">
298
+ <Badge dot variant="critical" aria-label="離線" />
299
+ <span>離線</span>
300
+ </div>
301
+ ```
302
+
303
+ - **語意**:狀態指示 + 描述文字並列
304
+ - **通常 dot 模式**(純視覺訊號)
305
+
306
+ ---
307
+
308
+ ## 無障礙
309
+
310
+ Badge 必須讓 screen reader 使用者獲得**同等資訊**——不能只靠視覺(顏色 / 位置)傳達意義。
311
+
312
+ ### aria-label 模式
313
+
314
+ **Count 模式**:badge 的數字會被讀出,但需要 context 才有意義。在 parent 元件加 aria-label 整合主內容 + 計數:
315
+
316
+ ```tsx
317
+ <button aria-label="通知 (3 則未讀)">
318
+ <Bell />
319
+ <Badge count={3} variant="critical" />
320
+ </button>
321
+ ```
322
+
323
+ **Dot 模式**:無文字 → screen reader 完全看不到 → **必須**給 `aria-label`:
324
+
325
+ ```tsx
326
+ <Badge dot variant="critical" aria-label="有新訊息" />
327
+ ```
328
+
329
+ ### 色彩不獨立承載意義(color-blind)
330
+
331
+ Badge 的 level 靠顏色區分(紅 / 藍 / 灰)——color-blind 使用者可能無法分辨 critical vs high。
332
+
333
+ **必須**搭配:
334
+ - **Count 數字或 aria-label 傳達具體內容**(「3 則緊急錯誤」而非單純「紅色 badge 3」)
335
+ - **容器上的其他視覺指示**(icon / 文字標籤)共同傳達意義
336
+
337
+ 單靠 badge 顏色承載語意(「紅色代表緊急」)會讓 color-blind 使用者錯過關鍵資訊。
338
+
339
+ ---
340
+
341
+ ## 禁止事項
342
+
343
+ - ❌ 不用 Badge 做分類標籤——那是 Tag
344
+ - ❌ dot 模式不帶 `aria-label`——無文字的 dot 對 screen reader 完全不存在
345
+ - ❌ 單靠顏色傳達 urgency——必須搭配 aria-label / count / 其他視覺指示
346
+ - ❌ 一個元件疊加**多個同類 badge**(signal crowding)——規則看**元件本身的 overlay slot 設計**:
347
+
348
+ **判斷法(決定性)**:**看元件本身提供幾個 overlay slot prop**
349
+ - 元件只暴露 **1 個 overlay slot**(例:`<Button overlayBadge={...}>`)→ **只能有 1 個 badge**,consumer 無法合法疊多個(DS 擋下手刻 `absolute` 疊加)
350
+ - 元件暴露 **多個具名 slot**(例:`<Avatar status={...} badgeCount={...}>` — status 在右下、count 在右上,兩個獨立 prop)→ **可合法疊加,最多到 slot 數量**
351
+
352
+ **Avatar 可以疊兩個 badge**(status + count),因為 DS canonical 設計了兩個不同角、不同語義的 slot(presence 狀態 / 未讀數量)——這是 iMessage / Slack / LINE 標配。
353
+
354
+ **Button iconOnly 只能疊一個 badge**(透過 `overlayBadge` prop),DS 不提供第二個 slot——任何「右上 count + 右下 dot」之類的手刻疊加都是 signal crowding 反例,使用者無法判斷哪個訊號重要。想同時表達兩種訊號 → 合併成一個 badge(count + 色彩分級)或重新思考資訊架構
355
+ - ❌ Overlay badge 的 `absolute` 定位相對於 interactive chrome(button / card padding)——badge 必須相對於**視覺重心**(icon / avatar)定位,否則 dot 會飄在 chrome padding 空間裡,離 icon 太遠失去語義連結。canonical:`<Button iconOnly overlayBadge={...}>`(Button 內部貼 icon 角)、或 consumer 自包時把 `relative` 放 icon wrapper 而非 button
356
+ - ❌ Count 永遠顯示 max+(如永遠 99+)——threshold 失去區別力,改用 dot 或升高 max
357
+ - ❌ 為了「視覺統一」把所有 badge 降 level——使用者需要 level 差異分配注意力
358
+ - ❌ 為了「強調」把 low 升 level——升 level 是「這件事多重要」的承諾,不是偏好問題
359
+ - ❌ 為了 contrast 把 semantic = low 的 badge 跨 2+ 階 bump——設計錯配,重新考慮放置
360
+
361
+ ---
362
+
363
+ ## 為何無 StateBehavior
364
+
365
+ Badge 是**計數 / 狀態視覺指示器**,本身**非互動元件**:
366
+
367
+ - 無 hover / focus / active / selected / disabled 這類 state。
368
+ - Badge 通常依附在互動元件上(Button / Nav Item),那些元件有自己的 state——Badge 隨父層視覺連動,不擁有獨立 state。
369
+ - 計數變化(`count` 更新)屬資料更新不是 UI state 切換。
370
+
371
+ 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix`。
372
+
373
+ ---
374
+
375
+ ## 相關
376
+
377
+ - `../Tag/tag.spec.md` — 分類標籤、狀態標記(Badge vs Tag 的詳細對照在本 spec 定位段落)
378
+ - `../Button/button.spec.md` — iconOnly Button + Badge overlay 通知 icon 的組合模式
379
+ - `../Chip/chip.spec.md` — 可互動 filter(不是 Badge 的用途)
380
+ - `../CircularProgress/circular-progress.spec.md` — Loading 狀態指示(取代 Spinner)
@@ -0,0 +1,257 @@
1
+ ---
2
+ component: Breadcrumb
3
+ family: composite
4
+ variants: {}
5
+ sizes: {}
6
+ traits:
7
+ - hasInteractiveStates
8
+ - isStructural
9
+ benchmark:
10
+ - Ant Design Breadcrumb: github.com/ant-design/ant-design/tree/master/components/breadcrumb
11
+ - MUI Breadcrumbs: github.com/mui/material-ui/tree/master/packages/mui-material/src/Breadcrumbs
12
+ - Polaris Breadcrumbs: github.com/Shopify/polaris/tree/main/polaris-react/src/components/Breadcrumbs
13
+ - Carbon Breadcrumb: github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Breadcrumb
14
+ ---
15
+
16
+ <!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
17
+
18
+ # Breadcrumb 設計原則
19
+
20
+ ## 定位
21
+
22
+ Breadcrumb 顯示「當前頁面在資訊階層中的位置」,同時提供快速回到上層的路徑導覽。
23
+ 基於 shadcn/ui Breadcrumb 結構(純 HTML + Tailwind,無 Radix primitive),橋接設計系統 token。
24
+
25
+ **Breadcrumb 是「你在哪裡」的指示器,不是「你可以去哪裡」的選單**——反映當前路徑,不是全部可能路徑。
26
+
27
+ **Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
28
+
29
+ ---
30
+
31
+ ## 何時用
32
+
33
+ - **頁面深度 ≥ 3 層**的資訊階層導覽(專案 / 子專案 / 任務,組織 / 團隊 / 成員 / 設定)
34
+ - **檔案管理器類 UI**(folder 路徑)
35
+ - **電商多層分類**(Home / Electronics / Phones / iPhone 15)
36
+
37
+ ## 何時不用
38
+
39
+ | 場景 | 改用 | 原因 |
40
+ |------|------|------|
41
+ | 頁面結構只有 1–2 層 | page header + back button | 兩層不值得 Breadcrumb 的視覺投資 |
42
+ | 切換**平行** view(非階層)| `Tabs` | Breadcrumb 表達的是 parent-child 關係 |
43
+ | 主導覽 | `Sidebar` / top nav | Breadcrumb 反映當前位置,不是全局導覽 |
44
+
45
+ ## 近親元件分界
46
+
47
+ | vs | 差異軸 | 何時用 Breadcrumb |
48
+ |---|---|---|
49
+ | **Tabs** | Tabs 平行視圖切換;Breadcrumb 階層位置 indicator | 表達「我在 A → B → C 的 C」 |
50
+ | **Steps** | Steps 是順序流程進度;Breadcrumb 是樹狀階層位置 | 非進度,而是 nested resource path |
51
+ | **Sidebar nav** | Sidebar 是全局導覽 chrome;Breadcrumb 是 content header 內 inline path | 局部位置 anchor,不取代全局 nav |
52
+ | **Link / page header** | Link 是單一導覽動作;Breadcrumb 是 parent-chain 完整路徑 | 路徑 ≥ 3 層需要可逐層回上 |
53
+
54
+ 對齊 Polaris Breadcrumbs / Material Breadcrumb / Atlassian Breadcrumbs 共識:nav inside page header,不取代 sidebar。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
55
+
56
+ ---
57
+
58
+ ## 內部結構
59
+
60
+ ```
61
+ <nav aria-label="Breadcrumb">
62
+ <ol>
63
+ <li> BreadcrumbItem
64
+ <a> BreadcrumbLink ← clickable, 可回到上層
65
+ </li>
66
+ <li>
67
+ <span> BreadcrumbSeparator (ChevronRight, aria-hidden)
68
+ </li>
69
+ ...
70
+ <li>
71
+ <span> BreadcrumbPage ← 當前頁面, 不可點, aria-current="page"
72
+ </li>
73
+ </ol>
74
+ </nav>
75
+ ```
76
+
77
+ ### 元件家族
78
+
79
+ | 元件 | 語意 | HTML |
80
+ |---|---|---|
81
+ | `Breadcrumb` | 整個 nav 容器 | `<nav aria-label="Breadcrumb">` |
82
+ | `BreadcrumbList` | items 清單 | `<ol>` flex row |
83
+ | `BreadcrumbItem` | 單一項目容器 | `<li>` |
84
+ | `BreadcrumbLink` | 可點擊路徑項(非當前)| `<a>` 或 Slot(支援 `asChild` 給 router Link)|
85
+ | `BreadcrumbPage` | 當前頁面(非 clickable)| `<span aria-current="page">` |
86
+ | `BreadcrumbSeparator` | 項目間分隔 | `<li role="presentation">` + `ChevronRight` icon |
87
+ | `BreadcrumbEllipsis` | 省略中間路徑的 `⋯` | `<span aria-hidden>` + `MoreHorizontal` |
88
+
89
+ ---
90
+
91
+ ## 視覺 Token
92
+
93
+ | Slot | Token | 原因 |
94
+ |---|---|---|
95
+ | 基底字體 | `text-body` (14px) | navigation 尺度的標準 |
96
+ | 間距(items 之間) | `gap-2` (8px) | 對齊 item-layout pattern 的 slot gap |
97
+ | **`BreadcrumbLink`(可點擊)預設** | `text-fg-secondary` | neutral-8, 提示「可互動但非焦點」 |
98
+ | **`BreadcrumbLink` hover** | **`text-primary-hover`** | 藍字 + `transition-colors duration-150`,明確回饋「點這個會有動作」 |
99
+ | **`BreadcrumbPage`(當前)** | `text-foreground`(不加粗)| neutral-9 深色區分於 fg-secondary 的 links,但**不加粗**——加粗會讓 breadcrumb 最右端視覺過重,破壞「你從哪來 → 你在這」的流動感 |
100
+ | **`BreadcrumbSeparator`** | `text-fg-muted` + `ChevronRight` size=`BREADCRUMB_ICON_SIZE[size]`(`breadcrumb.tsx:130` SSOT,sm/md=16, lg=20) | 視覺降噪,separator 不搶焦點;對齊 `uiSize.spec.md` Icon Size Tier(2026-05-18 retire 過去 14) |
101
+ | **`BreadcrumbEllipsis`** | `text-fg-muted` + `MoreHorizontal` size=`BREADCRUMB_ICON_SIZE[size]` | 同 separator 層級 |
102
+ | **`BreadcrumbLink` / `BreadcrumbPage` `startIcon`**(2026-05-20 ship)| `<Icon size={BREADCRUMB_ICON_SIZE[size]} aria-hidden />`(sm/md=16, lg=20)| 首項 Home icon 業界慣例(Material / Atlassian)。Consumer 只傳 `LucideIcon`,DS 統一管 size 消費 BREADCRUMB_ICON_SIZE SSOT — 對齊 `uiSize.spec.md` Icon Size Tier,**禁 consumer 傳 size prop**(避免再次 14 / 20 等寫死 drift)|
103
+
104
+ ## 對齊既有設計語言
105
+
106
+ - **色彩三階層**(fg-secondary → foreground / primary-hover → fg-muted)跟 MenuItem / Tabs trigger / SegmentedControl 的三階層結構一致:**次要 → 主要(或 hover 強調) → 弱化**
107
+ - **`primary-hover` 在 Breadcrumb 的用法是「互動時文字變藍」**,跟 Tabs underline / Chip border / SegmentedControl border 用 `primary-hover` 的 canonical 選中規則屬於同一個色彩語言(`primary-hover` = 互動高亮)
108
+ - **分隔 icon 用 `ChevronRight`**(不用 `/` 字元)對齊 Button `endIcon` 的「方向指示」icon 選擇
109
+
110
+ ---
111
+
112
+ ## 互動狀態
113
+
114
+ ### `BreadcrumbLink`
115
+ - **Default**:`text-fg-secondary`
116
+ - **Hover**:`text-primary-hover`(使用者要求的核心互動)
117
+ - **Active/Click**:瀏覽器原生 `:active` 反饋,不特別覆寫
118
+ - **Focus-visible**:`ring-2 ring-ring ring-offset-1`(對齊全系統 focus 規則)
119
+ - **Disabled**:通常 breadcrumb link 不會 disabled(如果需要,consumer 自己處理為 `BreadcrumbPage` 樣式)
120
+
121
+ ### `BreadcrumbPage`
122
+ - 無互動狀態,只是 text。`aria-current="page"` 給螢幕閱讀器
123
+
124
+ ### `BreadcrumbSeparator`
125
+ - 無互動。`aria-hidden`(語意分隔由 `<ol>` / `<li>` 結構承擔)
126
+
127
+ ---
128
+
129
+ ## Single-line + Overflow / 長路徑處理(2026-05-10 升級)
130
+
131
+ **Single-line canonical**:BreadcrumbList 預設 `flex-nowrap`,**不 wrap 到下一行**。對齊 Material UI / GitHub / Notion / Linear / Atlassian 共識(WebFetch verified Material UI source `Breadcrumbs.js renderItemsBeforeAndAfter`)。路徑過長走中段折疊,非 multi-line wrap。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
132
+
133
+ 當路徑層級太深(> 4–5 層)且容器寬度有限,world-class 作法是**中段折疊**:
134
+
135
+ ```
136
+ 首頁 › ⋯ › 成員管理 › 權限設定
137
+ ```
138
+
139
+ **v1 現況**(consumer 手動):
140
+ - 保留第一個 + 最後 1–2 items;中間用 `<BreadcrumbEllipsis>` 折疊
141
+ - `<BreadcrumbEllipsis>` 消費 `ItemInlineActionButton` primitive(per inline-action.spec.md predicate + M1 SSOT 消費),`overlayTrigger=true` 內建 DropdownMenu open 視覺鎖
142
+ - 包 `<DropdownMenuTrigger asChild>` 提供點 ⋯ 展開互動
143
+
144
+ **v2 shipped Phase B**(2026-05-10):declarative `items` prop + `maxItems`(**default 4**,user-tuned;Material UI source 預設 8)+ `itemsBeforeCollapse`(default 1)+ `itemsAfterCollapse`(default 1)auto-collapse mode。對齊 Material UI source `Breadcrumbs.js renderItemsBeforeAndAfter` mechanism(2026-05-10 WebFetch verified)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
145
+
146
+ ```tsx
147
+ <BreadcrumbList
148
+ items={[
149
+ { label: '組織', href: '/org' },
150
+ { label: '產品團隊', href: '/team' },
151
+ { label: '成員管理', href: '/members' },
152
+ { label: '權限', href: '/permissions' },
153
+ { label: '編輯角色' }, // 無 href → 自動 BreadcrumbPage(末位)
154
+ ]}
155
+ // maxItems={4} // default
156
+ // itemsBeforeCollapse={1} // default
157
+ // itemsAfterCollapse={1} // default
158
+ />
159
+ ```
160
+
161
+ **Per-item width canonical(Phase B)— flex-shrink hierarchy**:
162
+
163
+ | Role(`data-bc-role`)| `flex-shrink` | 行為 |
164
+ |---|---|---|
165
+ | `root`(首位)| **3** | 縮最積極(root context 可弱化)|
166
+ | `middle`(中段)| **2** | 次積極 |
167
+ | `current`(末位 / BreadcrumbPage)| **1** | 最後縮(a11y current page anchor)|
168
+ | `ellipsis`(BreadcrumbEllipsis 包裝)| **0** | 永遠完整顯示 ⋯ |
169
+ | `BreadcrumbSeparator` | **0** | 永遠完整(否則 path 視覺斷裂)|
170
+
171
+ **為何 flex-shrink hierarchy 不用 fixed max-width**:
172
+ - 容器寬 / items 少 → 各 item 自然寬度,**不浪費剩餘空間**(回應 user 質疑)
173
+ - 容器窄 / items 多 → 按 priority 縮(root 先 → middle → current 最後)
174
+ - 都縮到 `min-w-0` 後 CSS `truncate` 開啟 + Tooltip 補完整文字
175
+ - Root **也會** truncate(shrink:3 縮最積極)— 不是 `shrink-0`(回應 user 質疑)
176
+
177
+ **Truncate-on-overflow + tooltip canonical**(per `tooltip.principles.stories.tsx:190`):
178
+ - 每 BreadcrumbLink / BreadcrumbPage 內部 wrap `<TruncatedLabel>`(同 `data-table.tsx:339 TruncateCell` + `tag.tsx:138 isTruncated` SSOT pattern)
179
+ - Shared ResizeObserver 偵測 `scrollWidth > clientWidth` → `<Tooltip>` wrap
180
+ - 只在實際 truncate 時才顯 Tooltip(per tooltip canonical)— 沒被截斷不顯
181
+ - **TODO**(Rule-of-3):breadcrumb / data-table / tag 三處同 idiom,future 抽 `patterns/element-anatomy/truncated-text.tsx` 共用 SSOT
182
+
183
+ 世界級對照:
184
+ - **Material UI**:`maxItems=8` declarative auto-collapse(source verified,**no per-item width rule**)
185
+ - Notion / Linear / GitHub / Atlassian per-item width 策略:**unverified**(WebFetch + web search 無法取得 source / docs)。本 DS 設計基於 DS internal SSOT(`TruncateCell` + `Tag truncate` + `Tooltip canonical`)+ first-principles flex-shrink hierarchy 回應 user 兩 challenges(root 也 truncate / 不浪費空間)。
186
+
187
+ 世界級對照:
188
+ - **Material UI**:`maxItems=8` + auto-collapse(declarative)
189
+ - **Polaris**:點 ⋯ DropdownMenu 展開
190
+ - **Atlassian**:中段 ⋯ + dropdown
191
+ - **GitHub / Notion / Linear / Apple Finder**:auto truncate 中段
192
+
193
+ ## Title-breadcrumb-end 同步 canonical(2026-05-10 新增)
194
+
195
+ **Breadcrumb 末位 `<BreadcrumbPage>` 文字 = page title `<h2>` / `<h3>` / `<h4>` 內容**。對齊 GitHub / Notion / Linear / Atlassian / Material UI examples 共識。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
196
+
197
+ 具體 pairing(per BreadcrumbList size):
198
+ - `size="sm"` + 末位 `<BreadcrumbPage>X</BreadcrumbPage>` + `<h4>X</h4>` 同字
199
+ - `size="md"`(default)+ 末位 `<BreadcrumbPage>X</BreadcrumbPage>` + `<h3>X</h3>` 同字
200
+ - `size="lg"` + 末位 `<BreadcrumbPage>X</BreadcrumbPage>` + `<h2>X</h2>` 同字
201
+
202
+ **為何同字重複**:breadcrumb 末位是 a11y 階層 navigation 階梯末端(`aria-current="page"`);title h2/h3/h4 是同字**視覺大字 emphasis**。兩者各司其職:小字 breadcrumb 提供路徑 context,大字 title 提供 page identity。同 SSOT 兩 view。
203
+
204
+ **禁止**:breadcrumb 末位用 `BreadcrumbLink`(parent path)+ title 才顯示 current page = breadcrumb 末位 ≠ title 內容 = 違反 spec.md L142「最後一項必 BreadcrumbPage」+ 違反 world-class consensus。
205
+
206
+ ---
207
+
208
+ ## 禁止事項
209
+
210
+ - ❌ **不用 `/` 字元作分隔**——用 `ChevronRight` icon。`/` 是文字字元,跟文字對齊不穩、顏色綁 text、screen reader 會讀出「斜線」
211
+ - ❌ **最後一項不可是 `BreadcrumbLink`**——最後一項代表當前頁,無處可點。必須用 `BreadcrumbPage`
212
+ - ❌ **Breadcrumb 不做頁面切換動作的「back 按鈕」**——back 的語意是「上一步瀏覽歷史」不是「上一層階層」,兩者不同。Back 用 Button 或瀏覽器原生
213
+ - ❌ **不得在 Breadcrumb 裡嵌入複雜互動元素**(dropdown、search、avatar picker)——breadcrumb 是「位置指示器」,塞功能會變 nav bar
214
+ - ❌ **不得覆寫 `BreadcrumbLink` 的 hover 色彩**——`primary-hover` 是全系統的「互動高亮」canonical,覆寫破壞語言一致性
215
+ - ❌ **不得把 Breadcrumb 拿來當 sidebar 或 top nav 替代**——breadcrumb 只顯示當前路徑,不展示 sibling 選項
216
+ - ❌ **單一層級頁面不要放 Breadcrumb**——「首頁」一個 item 沒導覽價值,造成視覺噪音
217
+
218
+ ---
219
+
220
+ ## 為何無 Inspector
221
+
222
+ Breadcrumb 決策維度是 collapse 策略 × size × 當前頁狀態,已在 `CollapseMatrix` / `SizeMatrix` / `ColorMatrix` / `StateBehavior` / 元件特有 `UsageExamples` 五張結構矩陣 + 真實場景完整覆蓋。互動 Inspector(切換 size / truncate)無法呈現「路徑深度 + 斷點」這類真實場景決策——`UsageExamples` 展示實際業務路徑更直接。
223
+
224
+ ColorMatrix 已建:展示 BreadcrumbLink / Page / Separator / Ellipsis 四種節點的 default / hover / focus 色彩矩陣,採 fg-muted → fg-secondary → foreground 的階層策略(對齊 GitHub / Notion / Linear)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
225
+
226
+ ---
227
+
228
+ ## 相關
229
+
230
+ - `Tabs` — 切換平行 view 的導覽(不同層級的 problem,breadcrumb 是階層內,Tabs 是同層切換)
231
+ - `Button variant="link"` — 一般文字連結按鈕
232
+ - `Sidebar` — 主導覽(breadcrumb 用來補 sidebar 之外的「當前位置」資訊)
233
+
234
+ ## A11y 預設
235
+
236
+ **ARIA / Pattern**:繼承 Radix `slot` primitive a11y 預設(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/slot#accessibility)。
237
+
238
+ **Keyboard 行為**:
239
+
240
+ - Tab — 逐個 link 導覽
241
+ - Enter — navigate
242
+
243
+ **Focus**:Radix primitive 自管 focus trap / restoration / visible ring(`outline: 2px solid var(--ring)` per design-system focus-visible canonical)。
244
+
245
+ **驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
246
+
247
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
248
+
249
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
250
+
251
+ - `steps.spec.md`
252
+
253
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
254
+
255
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
256
+
257
+ - `app-shell.spec.md`