@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,279 @@
1
+ ---
2
+ component: TimePicker
3
+ family: 4
4
+ variants: {}
5
+ sizes: {}
6
+ traits:
7
+ - hasInteractiveStates
8
+ - isInputLike
9
+ benchmark:
10
+ - Ant Design TimePicker: github.com/ant-design/ant-design/tree/master/components/time-picker
11
+ - MUI X Date Pickers (Time): github.com/mui/mui-x/tree/master/packages/x-date-pickers
12
+ ---
13
+
14
+ <!-- @benchmark-cited: D5 retrofit 2026-05-18 — all claims have inline URL or per-claim @benchmark-unverified retract. M22 inline cites added 2026-05-03 v11. -->
15
+
16
+ # TimePicker 設計原則
17
+
18
+ ## 定位
19
+
20
+ TimePicker 是**單一時間**(時/分/秒)輸入與顯示元件,對齊 Ant Design `<TimePicker>` API 風格(source: [github.com/react-component/picker/src/PickerInput/SinglePicker.tsx](https://github.com/react-component/picker/blob/master/src/PickerInput/SinglePicker.tsx)),但視覺與互動走本 DS 設計語言。
21
+
22
+ **Layout Family**:**Family 4(Field control layout)**,視覺對齊 Family 1(Menu item)。見 `patterns/element-anatomy/element-anatomy.spec.md`「Field Composition(不在 family 但相關)」段。
23
+
24
+ **實作基礎**:
25
+ - **Trigger**:`<button>` + `fieldWrapperStyles`(視覺 = Input wrapper,但 role 是 button 開 popover)
26
+ - **Popup**:`<Popover>`(消費 `patterns/overlay-surface/` 的 surface chrome)
27
+ - **Panel 主體**:**自建** 2-3 欄 column picker(時 / 分 / 秒),**不引入第三方 time library**——自建讓 DS own 視覺與交互(對齊 Ant Design 的 Panel 結構 — [react-component/picker TimePanel](https://github.com/react-component/picker/tree/master/src/PickerPanel/TimePanel) + 本 DS token)
28
+ - **世界級對照**:Ant Design TimePicker([source](https://github.com/react-component/picker/tree/master/src/PickerPanel/TimePanel))/ Material DateTimePicker([mui-x DigitalClock](https://github.com/mui/mui-x/blob/master/packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx))/ iOS native time picker `@benchmark-unverified`(closed-source)——共同行為:column scroll selector、minuteStep 支援、Now / OK footer、clearable
29
+
30
+ ---
31
+
32
+ ## Controlled-only rationale(Dim 26)
33
+
34
+ 本元件刻意採 **controlled-only** 模式:`value` + `onChange` 必傳,不支援 `defaultValue` uncontrolled fallback。
35
+
36
+ **為什麼**:
37
+ - 內部狀態複雜(search filter / range / menu open state)跟 `value` 雙向 sync 會產生 race condition
38
+ - Consumer 幾乎一定有外部 state(form library / app state),強制 controlled 消除 ambiguity
39
+ - 世界級對照:Ant Design DatePicker([source](https://github.com/react-component/picker/blob/master/src/PickerInput/SinglePicker.tsx)) / Material MUI Select([source](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Select/Select.js))皆支援 dual-mode;我們選 controlled-only 對齊狀態一致性優先
40
+
41
+ **若未來要改 dual-mode**:需引入 `useControllableState` helper + 測試 controlled↔uncontrolled switch 場景,屬 major API 擴充,非本 session scope。
42
+
43
+ ---
44
+
45
+ ## 何時用
46
+
47
+ | 情境 | 範例 |
48
+ |------|------|
49
+ | 會議排程時間 | Calendar event 的 start / end time(常 minuteStep=15) |
50
+ | 航班 / 公車時刻 | 起飛時間、發車時間(HH:mm) |
51
+ | 營業時間 / 工作時間 | 店家開放時間、員工排班上下班 |
52
+ | 提醒 / 鬧鐘時間 | Reminder time picker(秒無意義,showSeconds=false) |
53
+
54
+ ## 何時不用
55
+
56
+ | 場景 | 改用 | 原因 |
57
+ |------|------|------|
58
+ | 同時需要日期 + 時間 | **DatePicker with time** 或 `<DatePicker> + <TimePicker>` 並列 | TimePicker 本身不帶日期;需配 DatePicker 組合 |
59
+ | 時間範圍(from-to) | **兩個 `<TimePicker>`** 並列 + 之間 `<ArrowRight>` | TimePicker **MVP 不支援 range**,用組合達成(對齊 Ant `TimePicker.RangePicker` 的 composition 思路 — [source](https://github.com/react-component/picker/blob/master/src/PickerInput/RangePicker.tsx)) |
60
+ | 純文字時間輸入(秒有意義的科學測量) | `<Input>` + mask / regex validation | TimePicker 的 column UX 不適合大量精確輸入 |
61
+ | 倒數計時 / 相對時間 | 自行渲染 `MM:SS` 倒數 | TimePicker 是 wall-clock time,不是 duration |
62
+
63
+ ---
64
+
65
+ ## API
66
+
67
+ ```tsx
68
+ <TimePicker
69
+ value={time} // ISO "HH:mm" or "HH:mm:ss" | null
70
+ onChange={setTime}
71
+ size="sm" | "md" | "lg" // 對齊 field-height family,default md
72
+ mode="edit" | "readonly" | "disabled"
73
+ disabled={boolean}
74
+ error={boolean}
75
+ clearable={boolean}
76
+ placeholder="請選擇時間"
77
+ showSeconds={boolean} // 預設 false(兩欄:時/分)
78
+ minuteStep={1 | 5 | 10 | 15 | 30} // 會議常用 15
79
+ secondStep={1 | 5 | 10 | 15 | 30} // showSeconds=true 時生效
80
+ disabledTime={(parts) => ({ // 動態禁用某些時/分/秒
81
+ disabledHours: [...],
82
+ disabledMinutes: [...],
83
+ disabledSeconds: [...],
84
+ })}
85
+ endIcon={Clock} // 預設 Clock,傳 null 關閉(2026-05-05 v9:點擊觸發浮層 indicator 一律 suffix,對齊 DatePicker / Material endAdornment)
86
+ locale="en-US"
87
+ formatOptions={{ hour: '2-digit', minute: '2-digit', hour12: false }}
88
+ />
89
+ ```
90
+
91
+ ### Value 格式
92
+
93
+ **Value 是 ISO time string**(`"HH:mm"` 或 `"HH:mm:ss"`),local-time 語義(不帶時區 / 不帶日期)—— 對齊 DatePicker 家族的「value = ISO string」策略,consumer 不需持有 Date object。
94
+
95
+ ### 顯示格式化
96
+
97
+ **Display 走 `Intl.DateTimeFormat`**(跨 locale 統一、12h/24h 支援)。`formatOptions` 透傳進去。
98
+
99
+ ---
100
+
101
+ ## 尺寸
102
+
103
+ | size | field-height(md density) | Icon | 字體 |
104
+ |------|--------------------------|------|------|
105
+ | sm | 28px(`h-field-sm`)| 16px | text-body |
106
+ | md | 32px(`h-field-md`,**預設**)| 16px | text-body |
107
+ | lg | 36px(`h-field-lg`)| 20px | text-body-lg |
108
+
109
+ **field-height family 成員**,default = md(與 Button / Input / DatePicker 共享),完整 density-aware 值(lg density: sm=32 / md=36 / lg=40)見 `tokens/uiSize/uiSize.spec.md`。
110
+
111
+ ---
112
+
113
+ ## Panel 視覺規則
114
+
115
+ Panel 展開後的 column picker 結構:
116
+
117
+ ```
118
+ ┌─────────────────────────────────┐
119
+ │ 時 分 [秒] │ ← header(有 label 時顯示)
120
+ ├─────┬─────┬──────────────────┤
121
+ │ 09 │ 00 │ │
122
+ │ 10 │ 15 │ 每欄 scrollable │ ← body
123
+ │▓11▓│▓30▓│ 選中項藍底白字 │
124
+ │ 12 │ 45 │ │
125
+ │ 13 │ │ │
126
+ ├─────┴─────┴──────────────────┤
127
+ │ [Now] [OK] │ ← footer(選填)
128
+ └───────────────────────────────┘
129
+ ```
130
+
131
+ ### 欄內 item 狀態(對齊 SelectMenu canonical,**非 DatePicker**)
132
+
133
+ | State | 視覺 | Token |
134
+ |-------|------|-------|
135
+ | 正常 | 置中文字 | `text-foreground` |
136
+ | hover | 灰底 | `hover:bg-neutral-hover` |
137
+ | **selected** | **灰底**(非藍底) | `bg-neutral-selected text-foreground rounded-md` |
138
+ | disabled(`disabledTime`) | 灰字 | `text-fg-disabled cursor-not-allowed` |
139
+
140
+ **為什麼 selected 走 neutral 非 primary**(2026-04-21 canonical):TimePicker panel 是「**列表選中**」語意 — user 在時 / 分 / 秒選項間切換,跟 `SelectMenu` / `MenuItem` 同流派(單選 list → `bg-neutral-selected`)。**DatePicker date cell selected 用 `bg-primary`** 是因為那是「**最終選定日期**」的強 affordance(確定性)。兩者不同語意,不互調。
141
+
142
+ 對齊 SelectMenu / MenuItem 的好處:consumer 看 TimePicker 面板知道這是「選一個項目」,跟 Select 下拉選單認知一致(Ant Design TimePicker panel 同樣採 neutral selected — [picker style source](https://github.com/ant-design/ant-design/blob/master/components/date-picker/style/panel.ts) `@benchmark-unverified` exact line)。
143
+
144
+ ### Spacing + 結構(2026-04-21 canonical,2026-04-21 window width 修正)
145
+
146
+ - Panel 內 padding = `--layout-space-tight`(12px @ md density)
147
+ - **三欄(時 / 分 / 秒)各欄 `w-12`(48px)固定,非 flex-1 均分**(對齊 Ant / Google 世界級慣例 `@benchmark-unverified` visual measurement)。**分隔「:」移除**(AR8 canonical — Ant TimePicker / Google Calendar 同樣不加 `:`,靠 column 間距自明 `@benchmark-unverified` visual)
148
+ - Scrollable list 用 **`<ScrollArea>`**(對齊 DS 跨 OS 一致 overlay 捲軸 canonical);不 raw `overflow-y-auto`
149
+ - **Scroll-into-view**:mount = `behavior:'auto'`(避閃爍),後續 `value` 變更 = `behavior:'smooth'`(對齊 iOS / Material / Ant timepicker idiom)。SSOT 在 `time-columns.tsx` `TimeColumn` useEffect
150
+ - 每 item **`h-field-sm`(28px @ md / 32px @ lg)對齊 DatePicker date cell**(跨 picker 視覺一致)
151
+ - List 高 `h-[216px]`(容納約 7 個 item 置中)
152
+
153
+ ### Panel 寬度 content-driven(AR42 修正,2026-04-21)
154
+
155
+ **每欄 w-12(48px)固定,Panel 寬度隨 showSeconds 動態變化**:
156
+
157
+ | 模式 | 欄數 | Panel 寬(含 padding + gap) |
158
+ |------|------|---------------------------|
159
+ | HH:mm(預設)| 2 欄 | `2 × 48 + gap-1 × 1 + px × 2` ≈ 48×2 + 4 + 24 = **124px** |
160
+ | HH:mm:ss(showSeconds=true)| 3 欄 | `3 × 48 + gap-1 × 2 + px × 2` ≈ 48×3 + 8 + 24 = **176px** |
161
+
162
+ **世界級對照**:
163
+ - Ant Design TimePicker:每欄 ~56px,3 欄 ~170px(Panel 含 footer)`@benchmark-unverified` visual measurement(visual sampling,not source-citable as exact pixel)
164
+ - Google Calendar Quick-Time:~150-170px
165
+ - Material 3 TimePicker dial:~180px(含 AM/PM)`@benchmark-unverified` visual measurement
166
+ - 本 DS:每欄 48px,2 欄 ~124px / 3 欄 ~176px,**符合世界級緊湊節奏**
167
+
168
+ **為什麼每欄 48px 不 56 / 64**:
169
+ - 48px = `h-field-sm × 1.7`,兩位數字 `tabular-nums`(約 16-18px 寬)+ 左右呼吸 ~15px。不貼邊也不浪費
170
+ - 56-64px 寬度逼近 Select menu 語境;picker column 超過此寬度會模糊 picker vs menu 的視覺界線
171
+ - Ant 56 / 本 DS 48 差異在:Ant 的 item 有圓角 button 佔寬,本 DS 走 `rounded-md` `text-center`,視覺 48px 不擠 `@benchmark-unverified` visual measurement
172
+
173
+ **showSeconds 切換時 panel 寬度會跟著變**(刻意):
174
+ - 對齊 Ant 慣例(content-driven)
175
+ - showSeconds=false 的 panel 本就應該更窄,兩欄 + 大量留白會顯得 panel 空洞
176
+ - Popover position 受 side / align / collisionPadding 控制,寬度變化只移動 panel 位置不影響 anchor 關係
177
+
178
+ ---
179
+
180
+ ## 鍵盤
181
+
182
+ | 按鍵 | 行為 |
183
+ |------|------|
184
+ | 點 trigger | 開 Panel |
185
+ | Esc | 關 Panel(不確認) |
186
+ | Tab | 焦點在 column 間移動 |
187
+ | ↑ / ↓ | 欄內上下選 |
188
+ | Enter | 確認當前 highlight |
189
+ | 直接鍵入數字(optional) | 跳到對應值 |
190
+
191
+ ---
192
+
193
+ ## 狀態行為
194
+
195
+ ### Mode / Error / Disabled / Readonly
196
+ 詳見 `../Field/field-controls.spec.md`(共用規則)。
197
+
198
+ ### Empty 值
199
+ `value={null}` / `value=""` / `value=undefined` 都視為空,trigger 顯示 `placeholder`。Display 模式空值顯示 `—`(對齊 `EMPTY_DISPLAY`)。
200
+
201
+ ### 驗證時機
202
+ - Panel 關閉(OK 或 outside click)時 commit value 給 `onChange`
203
+ - `disabledTime` 在 Panel 開啟時套用(selected hour 改變會重算 disabledMinutes)
204
+ - 若 consumer 需要 form-level 必填驗證 → 外層 `<Field>` + `<FieldError>` 承擔(不是 TimePicker 本體責任)
205
+
206
+ ### Loading
207
+ N/A — TimePicker 是純同步輸入,無 async 狀態。
208
+
209
+ ---
210
+
211
+ ## A11y 預設
212
+
213
+ - trigger 需 `aria-label`(若沒外部 `<label>`)
214
+ - Panel 開啟時 trigger `aria-expanded="true"`
215
+ - 每欄 `role="listbox"`,item `role="option" aria-selected`
216
+ - Screen reader 讀出「時間選擇器,當前 9 時 30 分」
217
+
218
+ ---
219
+
220
+ ## Dismiss / Clear 規則(對齊 CLAUDE.md canonical)
221
+
222
+ - **關閉 Panel** → `onOpenChange(false)`(Popover 內建)/ outside click / Esc —— 這是 **overlay close**,不是 `onClear`
223
+ - **清空值** → `clearable={true}` 在 trigger 的 endAction slot 顯示 `X` 透過 `ItemInlineActionButton`(canonical),點擊 `onChange("")`
224
+ - **禁止**:用帶文字 label 的 Button(「清除」)作 clear
225
+
226
+ ---
227
+
228
+ ## 為何無 Range(MVP)
229
+
230
+ user 若需「from-to」時間範圍,用**兩個 `<TimePicker>` 並列 + 中間 `<ArrowRight>`**(對齊 Ant `TimePicker.RangePicker` 的 composition 思路)。內建 Range 暫不 MVP 實作,因為:
231
+
232
+ 1. 大部分「時間範圍」情境是**營業時間 / 會議時段**,consumer 端用兩個 TimePicker 組合語意更清晰
233
+ 2. 未來若出現大量 Range 需求(如 shift 排班表),再抽 `<TimePicker.Range>` sub-composition,對齊 DatePicker.Range 的 API pattern
234
+
235
+ ---
236
+
237
+ ## ColorMatrix 說明(兩層 SSOT 整合展示)
238
+
239
+ TimePicker 視覺分兩層,各自繼承不同 SSOT:
240
+ - **Trigger 層**:走 Field Controls family 色彩(由 `../Field/field-controls.spec.md` 擁有,共用 Input / Select)
241
+ - **Panel column item 層**:走 SelectMenu / MenuItem canonical `bg-neutral-selected`(由 `patterns/element-anatomy/item-anatomy.spec.md` 擁有,非 `bg-primary`——見本 spec「欄內 item 狀態」表)
242
+
243
+ `ColorMatrix` story 整合展示兩層 token 對照,但不重複定義(各 token 來源明示指向上游 SSOT)。
244
+
245
+ ## 為何無 StateBehavior
246
+
247
+ trigger 的互動狀態(focus / invalid / disabled / readonly)完全繼承 `../Field/field-controls.spec.md` SSOT「Mode 狀態」;panel 內 column item 的 hover / selected / disabled 走 `patterns/element-anatomy/item-anatomy.spec.md`「選擇 / 狀態視覺規則」。TimePicker 層級無自有 state 行為,panel 開 / 關由 Popover primitive 處理。重寫 StateBehavior = 與兩個 SSOT 同時漂移。
248
+
249
+ 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix`(兩層整合展示) + `SizeMatrix` + 元件特有 `ModeMatrix` / `PrecisionMatrix`。Field-level state 見 Input `StateBehavior` + field-controls.spec.md;panel item-level state 見 SelectMenu / MenuItem 的對應 story。
250
+
251
+ ---
252
+
253
+ ## 禁止事項
254
+
255
+ - ❌ 不要在 TimePicker 內部直接顯示日期——那是 DatePicker 的語義
256
+ - ❌ 不要把 value 改存 Date object——對齊家族 ISO string 策略
257
+ - ❌ minuteStep 不要設 7 / 11 / 13 等非整除值——會出現 00 / 07 / 14 / 21 / 28 / 35... 不符時間習慣
258
+ - ❌ 不要自刻 `<input type="time">`——瀏覽器原生 UI 跨 OS 不一致,違反 DS「跨 OS 視覺一致」原則
259
+ - ❌ Clear button 用帶文字 label 的 Button(違反 dismiss canonical,見 `patterns/element-anatomy/item-anatomy.spec.md`「Dismiss 按鈕 canonical」)
260
+
261
+ ---
262
+
263
+ ## 邊界案例
264
+
265
+ - **Disabled**:Field SSOT own;trigger 自動 disabled(`text-fg-disabled` + 不開 picker),Display mode + disabled 維持時間格式但 token 切 disabled。
266
+ - **Loading**:TimePicker 為 sync UI(time math 在 client),無 loading state。極端 case(後端 disabled-times list)應由 consumer 先 disable trigger 直到 fetch 完成。
267
+ - **Empty(no value)**:`value=null` 為合法 initial state,trigger 顯 placeholder(預設「選擇時間」);`null` + Display mode 顯 `—`(em dash + `text-fg-muted`)對齊 Input display empty 慣例。
268
+ - **Empty(disabled all times)**:極端場景(`disabledHours` / `disabledMinutes` 覆蓋全範圍),panel column 全 disabled,鍵盤焦點停留無導覽目標。
269
+ - **Dark mode / density**:走 Field + Popover SSOT 自動 adapt;panel column item 由 MenuItem SSOT 控 density。
270
+
271
+ ---
272
+
273
+ ## 相關
274
+
275
+ - `../DatePicker/date-picker.spec.md` — 日期選擇,TimePicker 姊妹元件,API 風格對齊
276
+ - `../Input/input.spec.md` — Field control 基礎
277
+ - `../Field/field-controls.spec.md` — Mode / size / error 共用規則
278
+ - `../Field/form-validation.spec.md` — 驗證時機
279
+ - `../../patterns/element-anatomy/item-anatomy.spec.md`「Dismiss 按鈕 canonical」 — clear button 規則
@@ -0,0 +1,177 @@
1
+ ---
2
+ component: Toast
3
+ family: 2
4
+ traits:
5
+ - hasVariants
6
+ variants:
7
+ neutral:
8
+ when: "非狀態通知;一般 announcement / tip(『已複製到剪貼簿』『偏好已儲存』)"
9
+ world-class: ["Polaris Toast default", "Sonner default", "Linear toast neutral"]
10
+ info:
11
+ when: "資訊性提示(『新版本可用』『同步完成』);非錯誤、非成功"
12
+ world-class: ["Material Snackbar info", "Ant notification info"]
13
+ success:
14
+ when: "成功確認(『訂單已寄送』『付款完成』『5 筆資料已匯入』)"
15
+ world-class: ["Polaris Toast success", "Linear toast success", "Stripe payment success"]
16
+ warning:
17
+ when: "可恢復警告(『有未儲存變更』『連線不穩』『token 將過期』)"
18
+ world-class: ["Ant notification warning", "Carbon Notification warning"]
19
+ error:
20
+ when: "錯誤(『匯入失敗』『權限不足』『網路斷線』);action prop 可加重試"
21
+ world-class: ["Polaris Toast error", "Material Snackbar error", "Linear toast error"]
22
+ sizes: {}
23
+ benchmark:
24
+ - Radix Toast primitive: github.com/radix-ui/primitives/tree/main/packages/react/toast
25
+ - Polaris Toast: github.com/Shopify/polaris/tree/main/polaris-react/src/components/Toast
26
+ - MUI Snackbar: github.com/mui/material-ui/tree/master/packages/mui-material/src/Snackbar
27
+ - Carbon Notification: github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/Notification
28
+ - Ant Design notification: github.com/ant-design/ant-design/tree/master/components/notification
29
+ ---
30
+
31
+ # Toast 設計原則
32
+
33
+ ## 定位
34
+
35
+ Toast 是**短暫的浮動通知,自動消失**。用於操作結果回饋(成功 / 失敗 / 警告)。不阻斷使用者操作。
36
+
37
+ **實作基礎**:基於 sonner(浮動管理)+ 消費 Notice primitive(layout + icon + theme 策略,與 Alert 共用)。
38
+
39
+ **Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。Toast 透過 Notice 繼承 Family 2 結構。
40
+
41
+ ---
42
+
43
+ ## 何時用
44
+
45
+ - **操作結果短暫回饋**:儲存成功、訊息已送出、已複製到剪貼簿、刪除失敗
46
+ - **背景非同步動作完成**:檔案上傳完成、資料同步完成、通知已寄出
47
+ - **需要「復原」按鈕的操作**:刪除後 4 秒內可 Undo(sonner action 模式)
48
+ - **非關鍵資訊**:訊息即使使用者沒看到也不影響流程
49
+
50
+ ## 何時不用
51
+
52
+ | 場景 | 改用 | 原因 |
53
+ |------|------|------|
54
+ | 關鍵錯誤或警告(使用者必須看到)| `Alert` + `Dialog` | Toast 會自動消失,關鍵訊息必須 persistent |
55
+ | 欄位級驗證錯誤 | Field error message | Toast 是頁面級,欄位錯誤靠在欄位下方 |
56
+ | 需要使用者確認的訊息(「是否繼續?」)| `Dialog` | Toast 非阻斷且自動消失,無法承載確認流程 |
57
+ | 持久性系統狀態(方案過期、帳戶未驗證)| `Alert` | Toast 短暫,狀態需要 persistent |
58
+
59
+ ---
60
+
61
+ ## 與 Alert 的分界
62
+
63
+ **Alert 是 canonical owner**——完整多維度比較詳見 `../Alert/alert.spec.md`「與 Toast / Notice 的分界」。
64
+
65
+ 簡述:**Toast** = 短暫浮動自動消失(操作回饋);**Alert** = 持續顯示需 acknowledge(系統狀態)。判斷法「訊息重要到需要 acknowledge 嗎」在 Alert spec。
66
+
67
+ ---
68
+
69
+ ## 禁止事項
70
+
71
+ - ❌ **不用 Toast 做 critical confirmation**:Toast 會自動消失,使用者可能沒看到就消失——關鍵訊息改用 Alert 或 Dialog
72
+ - ❌ **不用 Toast 取代 error validation**:欄位錯誤訊息要貼近發生位置(FieldError),Toast 定位遠離錯誤欄位,使用者難對應到錯誤來源
73
+ - ❌ **不同時彈 > 3 個 Toast**:同時多則 Toast 視覺雜訊重且無法閱讀,sonner 會自動 queue;應用層若批量觸發 toast,整理成單一 Toast with list 或改用 Alert
74
+ - ❌ **不把需要 user action 的內容放 Toast**:action 按鈕僅限「復原 / Undo」這類非必要後手——強制 CTA(付款、確認刪除)用 Dialog
75
+
76
+ ---
77
+
78
+ ## A11y 預設
79
+
80
+ - **預設**(success / info / neutral):`role="status"` + `aria-live="polite"`——screen reader 在空閒時讀出,不中斷使用者
81
+ - **error / warning 升級**:`role="alert"` + `aria-live="assertive"`——立即中斷朗讀通知使用者
82
+ - **由 sonner 自動管理**:本 DS 不覆寫 sonner 的 a11y 行為,consumer 無需額外處理
83
+ - **關閉按鈕**:若 consumer 自訂 action,務必提供 `aria-label`(sonner 內建 dismiss 已處理)
84
+
85
+ ---
86
+
87
+ ## Container 架構
88
+
89
+ 三層結構(所有 variant 統一):
90
+
91
+ 1. **Shadow wrapper**:`rounded-lg`(8px)+ `elevation-200`(浮層陰影)。永遠在頁面 theme 解析。
92
+ 2. **Bg layer**:`bg-{color}`。有色相 variant 在頁面 theme 解析。
93
+ 3. **Theme layer**:`data-theme` + `text-foreground`。content token 在此 re-resolve。
94
+
95
+ ### 為什麼分三層
96
+
97
+ 陰影 token(`--elevation-200`)在 dark mode = 45% black,light mode = 4% black。如果陰影跟 `data-theme="dark"` 在同一層,light 頁面上的 dark toast 會有過重的 dark 陰影。分開讓陰影永遠用頁面 theme 的輕陰影。
98
+
99
+ ## Variant × Theme 策略
100
+
101
+ | Variant | Bg | data-theme | 視覺 |
102
+ |---|---|---|---|
103
+ | neutral | `bg-surface-raised`(同層翻轉) | `{inverse}` | light 頁→暗底, dark 頁→亮底 |
104
+ | success | `bg-surface-raised`(同層翻轉) | `{inverse}` | 同上 + 綠色 icon |
105
+ | info | `bg-info`(outer) | `"dark"`(inner) | 藍底白字 |
106
+ | warning | `bg-warning`(outer) | `"light"`(inner) | 黃底深字 |
107
+ | error | `bg-error`(outer) | `"dark"`(inner) | 橘底白字 |
108
+
109
+ neutral/success 的 bg + data-theme 在同一層,因為 `bg-surface-raised` 需要跟 data-theme 一起翻轉。
110
+
111
+ ## API
112
+
113
+ ```tsx
114
+ toast({
115
+ variant: 'success',
116
+ title: '操作成功',
117
+ description: '變更已儲存至伺服器',
118
+ action: { label: '復原', onClick: handleUndo },
119
+ duration: 4000,
120
+ })
121
+ ```
122
+
123
+ - `title`(必填):主要訊息
124
+ - `description`(選填):補充說明,自然換行
125
+ - `action`(選填):tertiary xs 按鈕
126
+ - `duration`(選填):自動關閉時間,預設 4000ms
127
+
128
+ ## 寬度(元件級常數)
129
+
130
+ Toast 固定 **360px 寬**(見 `.tsx` 的 `w-[360px]`)——跨通知視覺一致,避免長短不一造成視覺跳動;同時限制單一通知橫向占據空間,不遮蔽過多頁面內容。
131
+
132
+ 對照世界級:Material Snackbar 固定 344px、Sonner default toast 固定寬度——**單一元件的 canonical 寬度屬於該元件自己的 design spec,不抽為跨元件 token**。Token 系統只管共享值(如 `--field-height-*`、`--layout-space-*`);單一元件獨有的結構常數留在 component code + 本 spec。
133
+
134
+ ## 為何無 Inspector / SizeMatrix
135
+
136
+ - **無 Inspector**:Toast 透過 `toast()` **函式觸發**,不是 JSX 元件,沒有可 inspect 的 prop 面板——應有的互動玩法是「按鈕按下 → toast 浮現」,已由 `Overview` 中的 Action buttons 覆蓋。ToastOptions 的 schema 完整列於 `Overview` 表格。
137
+ - **無 SizeMatrix**:Toast 固定寬度 **360px**(見本 spec「寬度(元件級常數)」段),單一 canonical width 跨 variant 不變——參考 Material Snackbar 344px / Sonner default。無 sm/md/lg size prop,也不隨 density 變(浮層是獨立視覺語境)。
138
+
139
+ 對應 anatomy story:保留 `Overview` + 元件特有 `ContainerArchitecture`(三層結構解 shadow 陰影 bug) + `ColorMatrix`(Variant × Theme 策略) + `StateBehavior`(dismiss / stacking / pause / swipe)。
140
+
141
+ ---
142
+
143
+ ## shadcn passthrough 例外說明
144
+
145
+ Toast 的 public API 是 `toast()` 函式(imperative 觸發)+ `<Toaster />` Provider(app-level,置於 main.tsx 一次)。**兩者皆非「forwardRef + ...props + asChild」canonical shadcn 元件 pattern**:
146
+
147
+ - `toast(...)` 是 imperative API(sonner 負責 queue / stack / animation / auto-dismiss),consumer 不需持有 DOM ref
148
+ - `<Toaster />` 是 Provider(sonner 內部管理 portal container),consumer 在 app root 放一次,無 consumer-facing DOM operation
149
+
150
+ **sonner 已實作五件套內部**(Toaster Root 有 forwardRef / viewport DOM spread / 適當 a11y role=status/alert)。我們不再 wrap 一層,保持與 sonner 直接對應,避免 API 膨脹。
151
+
152
+ 若 consumer 需要程式化控制(`toast.dismiss(id)` / `toast.promise(...)`),使用 sonner 原生 API,Toast 元件層不重新暴露。
153
+
154
+ ---
155
+
156
+ ## 邊界案例
157
+
158
+ - **Disabled(action button)**:Toast 本身為 ephemeral notification 無 disabled state(自動消失,不需禁用);若 `toast()` 傳入 `action` button(sonner ToastOptions),該 button 在 async 動作中 consumer 可 disable,視覺繼承 Button SSOT(`text-fg-disabled` + `cursor-not-allowed`)。
159
+ - **Loading**:Sonner 提供 `toast.promise(promise, { loading, success, error })` API — loading 階段渲 spinner + `loadingText`,promise 成功 / 失敗自動切 success / error variant;本元件不需 wrap。
160
+ - **Empty**:`toast()` 必傳 title(API contract);無 title-empty 場景。
161
+ - **Icon-only**:`neutral` variant 不渲 status icon,layout 收斂為 `[title + description?] [action?] [dismiss X?]`。
162
+ - **Dark mode / density**:走 Notice / Sonner 內部策略(見「Theme 策略」段),固定寬度 360px 跨 density 不變。
163
+
164
+ ---
165
+
166
+ ## 相關
167
+
168
+ - `../Notice/notice.spec.md` — Toast 消費的 layout primitive(與 Alert 共用)
169
+ - `../Alert/alert.spec.md` — 持久性通知(同一套視覺策略)
170
+ - `../Dialog/dialog.spec.md` — 需要阻斷或確認的通知改用 Dialog
171
+ - [sonner](https://sonner.emilkowal.ski/) — 浮動管理 library
172
+
173
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
174
+
175
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
176
+
177
+ - `sheet.spec.md`
@@ -0,0 +1,139 @@
1
+ ---
2
+ component: Tooltip
3
+ family: composite
4
+ variants: {}
5
+ sizes: {}
6
+ traits:
7
+ - isOverlay
8
+ benchmark:
9
+ - Radix Tooltip primitive: github.com/radix-ui/primitives/tree/main/packages/react/tooltip
10
+ - Ant Design Tooltip: github.com/ant-design/ant-design/tree/master/components/tooltip
11
+ - MUI Tooltip: github.com/mui/material-ui/tree/master/packages/mui-material/src/Tooltip
12
+ - Polaris Tooltip: github.com/Shopify/polaris/tree/main/polaris-react/src/components/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
+ # Tooltip 設計原則
18
+
19
+ ## 定位
20
+
21
+ Tooltip 是 hover 或 focus 時出現的短文字提示,用於補充畫面上未能清楚傳達的資訊。
22
+ 基於 Radix Tooltip(shadcn 包裝)+ 橋接 DS token。
23
+
24
+ **Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
25
+
26
+ ## 何時用
27
+
28
+ Tooltip 的判斷標準是:**畫面上的資訊是否已經足夠讓使用者理解?**
29
+
30
+ - **畫面不夠清楚 → 用 tooltip 補充。** 例如:icon-only 按鈕沒有文字 label,使用者需要 tooltip 才能確認這個 icon 代表什麼操作
31
+ - **畫面已經清楚 → 不需要 tooltip。** 例如:按鈕已有完整的文字 label(「儲存」「刪除」),tooltip 重複同樣的文字沒有價值
32
+ - **截斷文字 → 用 tooltip 顯示完整內容。** 但只有當文字實際被截斷時才顯示——tooltip 是補救機制,不是裝飾
33
+
34
+ ## 出現時機
35
+
36
+ 全產品統一一組時間參數,不因 tooltip 類型或位置而異——不一致的延遲會讓使用者無法建立穩定的操作預期。
37
+
38
+ **Warm-up pattern(暖機模式):**
39
+
40
+ 1. 使用者首次 hover 某個觸發器 → 等待初始延遲,確認是刻意停留而非滑鼠路過(NNGroup 研究:低於此閾值會導致隨意移動滑鼠時螢幕不停閃爍)
41
+ 2. Tooltip 出現後,使用者移到下一個觸發器 → 在掃描窗口期內,tooltip 即時切換,不再等待(toolbar 逐一掃描場景)
42
+ 3. 使用者離開所有觸發器超過掃描窗口期 → 系統冷卻,下次 hover 重新等待初始延遲
43
+
44
+ 這是一個行為的兩個階段,不是兩種不同的延遲。全域一個 `TooltipProvider` 統一控制,所有 tooltip(包括 Button icon-only 自動產生的)共享同一組參數。
45
+
46
+ ## 何時不用
47
+
48
+ | 場景 | 改用 | 原因 |
49
+ |------|------|------|
50
+ | 內容需要互動(按鈕 / 連結 / 輸入框)| `HoverCard` | Tooltip 不可點擊,HoverCard 才支援互動元素 |
51
+ | 需要長篇說明(多段文字 / 圖片)| `HoverCard` / 側邊 help panel | Tooltip 是一句話補充 |
52
+ | 欄位驗證錯誤 | inline error message | Tooltip 需要 hover 才能看到,錯誤必須 persistent |
53
+ | 必要資訊的唯一載體 | 直接顯示在畫面上 | Tooltip 觸控裝置無法觸發,關鍵資訊不能只靠 hover |
54
+ | 按鈕已有完整文字 label | 不要加 tooltip | 重複同樣的文字沒有價值 |
55
+
56
+ ## 與 Button icon-only 的關係
57
+
58
+ Button 的 `iconOnly` 模式已內建自動 tooltip(以 `aria-label` 驅動),開發者不需要額外包 `<Tooltip>`。只有在非 Button 元素需要 tooltip 時,才手動使用 Tooltip 元件。
59
+
60
+ ## 內容完整性
61
+
62
+ Tooltip 是資訊的終點——tooltip 內不能再觸發 tooltip。內容必須完整呈現,不截斷、不省略。
63
+
64
+ - Tag 在 tooltip 內不設 max-width,文字完整顯示
65
+ - 多個 tag 自然換行(flex-wrap),tooltip 高度隨內容撐開
66
+ - 不在 tooltip 內使用需要 hover 才能看到的元素
67
+
68
+ ## 子元素色彩
69
+
70
+ Tooltip 底色是深色,子元素永遠套用 dark theme token(透過 `data-theme="dark"` wrapper)。元件放進 tooltip 自動適配深色背景,不需要特殊樣式。
71
+
72
+ ## Align 對齊
73
+
74
+ **Tooltip 走「輕量浮層」例外**(見 `../Popover/popover.spec.md`「SSOT 適用範圍」)—— hover 觸發、純文字展示、寬度極窄(max 280px),Radix 預設 `center` 貼合指標即可。不強制對齊 structured overlay 的 trigger-position canonical。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
75
+
76
+ ## Edge collision(避免貼 viewport 邊)
77
+
78
+ **`collisionPadding` default = 8**(與 HoverCard 一致),Radix `avoidCollisions` 預設 true 會自動翻邊,但 padding 0 會讓 tooltip **貼齊 viewport 邊緣**(視覺上擠)。default 8 讓 tooltip 跟 viewport 邊保留最少 8px 呼吸距離。consumer 需自訂傳 prop 即可覆寫。
79
+
80
+ 世界級對照:Material Tooltip `margin: 14px` default / Polaris Tooltip 8-12px — 本 DS 選 8 對齊 HoverCard。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
81
+
82
+ ## 最大寬度(元件級常數)
83
+
84
+ Tooltip 最大寬度 **280px**(見 `.tsx` 的 `max-w-[280px]`)——超過換行。避免單條 tooltip 占據過大空間遮蔽內容,同時保證文字可完整呈現(見「內容完整性」節,tooltip 是資訊終點,不截斷)。
85
+
86
+ 對照世界級:Material tooltip 約 250–300px、Apple HIG tooltip 限制在可讀寬度——**單一元件的 canonical 寬度屬於該元件自己的 design spec,不抽為跨元件 token**。Token 系統只管共享值(如 `--field-height-*`、`--layout-space-*`);單一元件獨有的結構常數留在 component code + 本 spec。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
87
+
88
+ ## 禁止事項
89
+
90
+ - ❌ 不要在已有完整 label 的按鈕上加 tooltip 重複同樣的文字
91
+ - ❌ 不要在 tooltip 裡放互動元素——改用 HoverCard
92
+ - ❌ 不要把 tooltip 當作必要資訊的唯一載體——tooltip 需要 hover 才能看到,觸控裝置無法觸發
93
+ - ❌ 不要為個別 tooltip 設定不同的延遲時間——全產品統一一組參數
94
+ - ❌ 不要在 tooltip 內截斷資訊——tooltip 是資訊終點,內容必須完整
95
+
96
+ ---
97
+
98
+ ## 為何無 ColorMatrix / SizeMatrix / StateBehavior
99
+
100
+ Tooltip 是**單一職責 hover 提示 primitive**(一句話補充),刻意無變體:
101
+
102
+ - **無 ColorMatrix**:Tooltip 固定一種視覺(dark surface + white text,跟頁面主題反轉),無 variant / severity / hue。若需要有色 hint,那是 Popover / HoverCard 的職責。Dark mode 自動由 inverse theme 處理。故無 color matrix。
103
+ - **無 SizeMatrix**:Tooltip 無 size prop,尺寸由內容 + max-width 常數決定(本 spec「最大寬度」段)。不提供 sm/md/lg tier——短文字 hint 不需要尺寸變體。
104
+ - **無 StateBehavior**:Tooltip 是 passive 出現 / 消失(hover / focus 觸發,見「出現時機」段),無 hover / selected / active / disabled 這類互動元件 state。開 / 關行為由 Radix primitive 處理,寫在 `Overview` 的 usage 說明已足夠。
105
+
106
+ 對應 anatomy story:保留 `Overview` + `Inspector`(delay / placement 互動試玩) + 元件特有 `PlacementReference`(12 種 side × align 對照)。
107
+
108
+ ---
109
+
110
+ ## 相關
111
+
112
+ - `../HoverCard/hover-card.spec.md` — hover 觸發的可互動浮層(**Tooltip vs HoverCard 的分界 SSOT 在 HoverCard spec**「與 Tooltip 的分界」段落)
113
+ - `../Button/button.spec.md` — `iconOnly` 模式自動產生 tooltip(由 aria-label 驅動)
114
+
115
+ ## A11y 預設
116
+
117
+ **ARIA / Pattern**:繼承 Radix `tooltip` primitive a11y 預設(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/tooltip#accessibility)。
118
+
119
+ **Keyboard 行為**:
120
+
121
+ - Tab — focus trigger 時顯示
122
+ - Esc — 關閉
123
+
124
+ **Focus**:Radix primitive 自管 focus trap / restoration / visible ring(`outline: 2px solid var(--ring)` per design-system focus-visible canonical)。
125
+
126
+ **驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
127
+
128
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
129
+
130
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
131
+
132
+ - `coachmark.spec.md`
133
+ - `name-card.spec.md`
134
+
135
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
136
+
137
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
138
+
139
+ - `motion.spec.md`