@qijenchen/design-system 0.1.0-beta.10 → 0.1.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +201 -0
- package/README.md +7 -15
- package/cli-init.mjs +90 -0
- package/ds-canonical/commands/README.md +26 -0
- package/ds-canonical/commands/gov-status.md +79 -0
- package/ds-canonical/hooks/README.md +145 -0
- package/ds-canonical/hooks/_log-fire.sh +44 -0
- package/ds-canonical/hooks/block_prototype_imports.py +111 -0
- package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
- package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
- package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
- package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
- package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
- package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
- package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
- package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
- package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
- package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
- package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
- package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
- package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
- package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
- package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
- package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
- package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
- package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
- package/ds-canonical/hooks/check_story_invariants.sh +612 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
- package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
- package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
- package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
- package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
- package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
- package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
- package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
- package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
- package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
- package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
- package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
- package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
- package/ds-canonical/hooks/log_governance_fires.sh +50 -0
- package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
- package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
- package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
- package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
- package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
- package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
- package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
- package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
- package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
- package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
- package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
- package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
- package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
- package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
- package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
- package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
- package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
- package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
- package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
- package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
- package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
- package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
- package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
- package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
- package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
- package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
- package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
- package/ds-canonical/hooks/stop_self_audit.sh +450 -0
- package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
- package/ds-canonical/hooks/tests/run-all.sh +76 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
- package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
- package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
- package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
- package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
- package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
- package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
- package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
- package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
- package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
- package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
- package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
- package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
- package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
- package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
- package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
- package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
- package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
- package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
- package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
- package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
- package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
- package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
- package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
- package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
- package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
- package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
- package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
- package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
- package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
- package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
- package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
- package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
- package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
- package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
- package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
- package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
- package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
- package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
- package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
- package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
- package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
- package/ds-canonical/references/README.md +43 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
- package/ds-canonical/references/build-ui-canonicals.md +69 -0
- package/ds-canonical/references/cva-patterns.md +41 -0
- package/ds-canonical/references/drag-canonical.md +331 -0
- package/ds-canonical/references/item-anatomy-recipe.md +225 -0
- package/ds-canonical/references/naming-conventions.md +56 -0
- package/ds-canonical/references/principle-dim-map.json +515 -0
- package/ds-canonical/references/props-naming.md +45 -0
- package/ds-canonical/references/spec-rules.md +58 -0
- package/ds-canonical/references/ssot-consultation.md +63 -0
- package/ds-canonical/references/ssot-index.md +40 -0
- package/ds-canonical/references/story-baseline-registry.json +79 -0
- package/ds-canonical/references/structural-token-retention.md +42 -0
- package/ds-canonical/references/tailwind-gotchas.md +87 -0
- package/ds-canonical/references/ui-dev-rules.md +60 -0
- package/ds-canonical/rules/README.md +34 -0
- package/ds-canonical/rules/meta-patterns.md +87 -0
- package/ds-canonical/rules/self-verify.md +53 -0
- package/ds-canonical/rules/spec-rules.md +25 -0
- package/ds-canonical/rules/story-rules.md +56 -0
- package/ds-canonical/rules/ui-development.md +87 -0
- package/ds-canonical/skills/README.md +88 -0
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
- package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
- package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
- package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
- package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
- package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
- package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
- package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
- package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
- package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
- package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
- package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
- package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
- package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
- package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
- package/ds-canonical/skills/governance-health/SKILL.md +146 -0
- package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
- package/ds-canonical/skills/new-component/SKILL.md +170 -0
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
- package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
- package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
- package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
- package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
- package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
- package/ds-canonical/skills/propose-options/SKILL.md +177 -0
- package/ds-canonical/skills/prototype/SKILL.md +244 -0
- package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
- package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
- package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
- package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
- package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
- package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
- package/ds-canonical/skills/story-writing/SKILL.md +122 -0
- package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
- package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
- package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
- package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
- package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
- package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
- package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
- package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
- package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
- package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
- package/package.json +9 -5
- package/src/components/Accordion/accordion.spec.md +114 -0
- package/src/components/Alert/alert.spec.md +197 -0
- package/src/components/AppShell/app-shell.spec.md +331 -0
- package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
- package/src/components/Avatar/avatar.spec.md +329 -0
- package/src/components/Badge/badge.spec.md +380 -0
- package/src/components/Breadcrumb/breadcrumb.spec.md +257 -0
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
- package/src/components/Button/button.spec.md +460 -0
- package/src/components/Calendar/calendar.spec.md +242 -0
- package/src/components/Carousel/carousel.spec.md +253 -0
- package/src/components/Chart/chart.spec.md +155 -0
- package/src/components/Checkbox/checkbox.spec.md +344 -0
- package/src/components/Chip/chip.spec.md +237 -0
- package/src/components/CircularProgress/circular-progress.spec.md +268 -0
- package/src/components/Coachmark/coachmark.spec.md +230 -0
- package/src/components/Combobox/combobox.spec.md +180 -0
- package/src/components/Command/command.spec.md +171 -0
- package/src/components/DataTable/data-table.spec.md +525 -0
- package/src/components/DateGrid/date-grid.spec.md +215 -0
- package/src/components/DatePicker/date-picker.spec.md +334 -0
- package/src/components/DescriptionList/description-list.spec.md +214 -0
- package/src/components/Dialog/dialog.spec.md +202 -0
- package/src/components/DropdownMenu/dropdown-menu.spec.md +250 -0
- package/src/components/Empty/empty.spec.md +214 -0
- package/src/components/Field/field-controls.spec.md +338 -0
- package/src/components/Field/field.spec.md +438 -0
- package/src/components/Field/form-validation.spec.md +152 -0
- package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
- package/src/components/FileItem/file-item.spec.md +467 -0
- package/src/components/FileUpload/file-upload.spec.md +123 -0
- package/src/components/FileViewer/file-viewer.spec.md +373 -0
- package/src/components/HoverCard/hover-card.spec.md +157 -0
- package/src/components/Input/input.spec.md +193 -0
- package/src/components/LinkInput/link-input.spec.md +130 -0
- package/src/components/Menu/menu-item.spec.md +290 -0
- package/src/components/NameCard/name-card.spec.md +171 -0
- package/src/components/Notice/notice.spec.md +149 -0
- package/src/components/NumberInput/number-input.spec.md +126 -0
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
- package/src/components/PeoplePicker/people-picker.spec.md +263 -0
- package/src/components/Popover/popover.spec.md +198 -0
- package/src/components/ProgressBar/progress-bar.spec.md +232 -0
- package/src/components/RadioGroup/radio-group.spec.md +141 -0
- package/src/components/Rating/rating.spec.md +208 -0
- package/src/components/ScrollArea/scroll-area.spec.md +145 -0
- package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
- package/src/components/Select/select.spec.md +299 -0
- package/src/components/SelectMenu/select-menu.spec.md +220 -0
- package/src/components/SelectionControl/selection-item.spec.md +128 -0
- package/src/components/Separator/separator.spec.md +109 -0
- package/src/components/Sheet/sheet.spec.md +148 -0
- package/src/components/Sidebar/sidebar.spec.md +713 -0
- package/src/components/Skeleton/skeleton.spec.md +104 -0
- package/src/components/Slider/slider.spec.md +353 -0
- package/src/components/Steps/steps.spec.md +465 -0
- package/src/components/Switch/switch.spec.md +215 -0
- package/src/components/Tabs/tabs.spec.md +314 -0
- package/src/components/Tag/tag.spec.md +282 -0
- package/src/components/Textarea/textarea.spec.md +151 -0
- package/src/components/TimePicker/time-picker.spec.md +279 -0
- package/src/components/Toast/toast.spec.md +177 -0
- package/src/components/Tooltip/tooltip.spec.md +139 -0
- package/src/components/TreeView/tree-view.spec.md +374 -0
- package/src/patterns/action-bar/action-bar.spec.md +458 -0
- package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
- package/src/patterns/element-anatomy/inline-action.spec.md +315 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
- package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +428 -0
- package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
- package/src/tokens/color/color.spec.md +804 -0
- package/src/tokens/density/density.spec.md +127 -0
- package/src/tokens/elevation/elevation.spec.md +81 -0
- package/src/tokens/layoutSpace/layoutSpace.spec.md +314 -0
- package/src/tokens/motion/motion.spec.md +97 -0
- package/src/tokens/opacity/opacity.spec.md +78 -0
- package/src/tokens/orphan-tokens.spec.md +117 -0
- package/src/tokens/radius/radius.spec.md +123 -0
- package/src/tokens/typography/typography.spec.md +202 -0
- package/src/tokens/uiSize/uiSize.spec.md +438 -0
- package/src/styles/preset.css +0 -31
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: CircularProgress
|
|
3
|
+
family: self-contained
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes: {}
|
|
6
|
+
traits:
|
|
7
|
+
- isMatrixHeavy
|
|
8
|
+
benchmark:
|
|
9
|
+
- MUI CircularProgress: github.com/mui/material-ui/tree/master/packages/mui-material/src/CircularProgress
|
|
10
|
+
- Ant Design Progress: github.com/ant-design/ant-design/tree/master/components/progress
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
14
|
+
|
|
15
|
+
# CircularProgress 設計原則
|
|
16
|
+
|
|
17
|
+
**圓形進度指示(determinate + indeterminate 雙模式)**——整個設計系統 circular 形式進度的 SSOT。
|
|
18
|
+
|
|
19
|
+
**Layout Family**:非 family — self-contained primitive(獨立視覺,無 slot 結構)。
|
|
20
|
+
|
|
21
|
+
**實作基礎**:自繪 SVG(雙 circle:track + arc)+ Tailwind `animate-spin`(indeterminate 模式)。無 external primitive base。
|
|
22
|
+
|
|
23
|
+
> 最薄的 circular progress primitive。`value` 有無切換兩態:無 value = indeterminate 旋轉 / 有 value = determinate arc + track。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 定位 + 姊妹元件分界(SSOT)
|
|
28
|
+
|
|
29
|
+
| 元件 | 型態 | 可量化? | 典型使用 |
|
|
30
|
+
|------|------|---------|----------|
|
|
31
|
+
| **`ProgressBar`** | linear **determinate** | ✅ 0–100 | 頁面級 / 表單步驟 / 上傳 bar / card 內大區塊進度 |
|
|
32
|
+
| **`CircularProgress`**(本元件) | circular **兩態** | ✅ 有 value / ❌ 無 value | inline 小空間 / Button loading / Field loading / 單一 icon 位置 / cell 內進度 |
|
|
33
|
+
|
|
34
|
+
**判斷法**:
|
|
35
|
+
- 水平大區塊 / 頁面級 → **ProgressBar**
|
|
36
|
+
- 小空間 / inline icon 位置 → **CircularProgress**(有 value 用 determinate / 無則 indeterminate)
|
|
37
|
+
|
|
38
|
+
### 世界級流派選擇(為何 circular 兩態合一)
|
|
39
|
+
|
|
40
|
+
查 6 家世界級 circular progress 命名策略:
|
|
41
|
+
- **合一派**(一元件 determinate + indeterminate):Material `CircularProgress` / Chakra `CircularProgress`
|
|
42
|
+
- **分離派**(2 元件):Ant(`Spin` + `Progress type=circle`) / Mantine(`Loader` + `RingProgress`)
|
|
43
|
+
- **只有 indeterminate**:Polaris / Atlassian / Carbon
|
|
44
|
+
- **混合**:Apple HIG(ActivityIndicator indeterminate / ProgressView determinate circular+linear 合)
|
|
45
|
+
|
|
46
|
+
**本 DS 採合一派**(Material / Chakra),理由:
|
|
47
|
+
1. **語義一致**:「CircularProgress」天然涵蓋兩態,不像「Spinner with value」語義拉扯
|
|
48
|
+
2. **元件數少**:不拆 Spinner + CircularProgress 兩元件,consumer 只要記一個
|
|
49
|
+
3. **視覺結構共用**:同一 SVG skeleton(`size` + strokeWidth + 雙 circle),`value` 有無只切換 dashoffset 計算 + animate-spin class,無 code 重複
|
|
50
|
+
|
|
51
|
+
(2026-04-20 從「Spinner + CircularProgress 分離」改為本架構;`Spinner` 元件已廢除並遷至本元件。consumer 改 import `CircularProgress`。)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 何時用
|
|
56
|
+
|
|
57
|
+
- **Button / Inline Action 的 loading 狀態**:Button `loading` prop 內部渲染(無 value = indeterminate)
|
|
58
|
+
- **Field loading 狀態**(Input / NumberInput / Combobox / Select):consumer 傳 `loading={true}` → 元件內部 readonly + endAction slot 自動塞 `<CircularProgress>`(見 `field-controls.spec.md`「Loading state」)
|
|
59
|
+
- **Cell / row 局部進度**(cell 上傳中、cell async fetch 中):size 16-20 inline
|
|
60
|
+
- **inline 可量化小進度**(如 file uploader list row 的上傳 % / 倒數計時):有 value
|
|
61
|
+
- **全頁 / empty surface 載入**:`<Empty icon={<CircularProgress size={48}/>}/>` compose(Empty canonical 垂直堆疊,無需另造)
|
|
62
|
+
|
|
63
|
+
## 何時不用
|
|
64
|
+
|
|
65
|
+
| 場景 | 改用 | 原因 |
|
|
66
|
+
|------|------|------|
|
|
67
|
+
| 頁面級 / 表單級大區塊進度 | `ProgressBar`(linear) | CircularProgress 在大尺寸視覺比例不如 linear bar |
|
|
68
|
+
| 骨架載入(list / card 初次 render) | `Skeleton` | Skeleton 保留內容形狀 |
|
|
69
|
+
| 全頁 loading 版面 | `<Empty icon={<CircularProgress/>}/>` | 版面繼承 Empty 垂直堆疊 canonical |
|
|
70
|
+
| 通知計數 / 狀態紅點 | `Badge`(dot 模式) | 語義完全不同 |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## API
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
export interface CircularProgressProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
78
|
+
/** 0-100;undefined → indeterminate(旋轉 partial arc) */
|
|
79
|
+
value?: number
|
|
80
|
+
/** 直徑 px,預設 24,≤ 64 建議 */
|
|
81
|
+
size?: number
|
|
82
|
+
/** 狀態色(與 ProgressBar 一致) */
|
|
83
|
+
status?: 'inProgress' | 'success' | 'error'
|
|
84
|
+
/** 視覺 label(inline,font-size inherit,color text-fg-muted) */
|
|
85
|
+
label?: string
|
|
86
|
+
/** Determinate 模式的 affix(indeterminate 忽略) */
|
|
87
|
+
affix?: 'value' | 'status-icon' | React.ReactNode
|
|
88
|
+
/** A11y label(指定後 shouldAnnounce=true) */
|
|
89
|
+
'aria-label'?: string
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 尺寸策略:自由 `number`,跟 Avatar 同一套
|
|
94
|
+
|
|
95
|
+
不用 `sm | md | lg` enum(跨度 16 → 64 太大)。
|
|
96
|
+
|
|
97
|
+
#### Size inheritance table(consumer 傳入的 canonical 值)
|
|
98
|
+
|
|
99
|
+
| Context | 建議 `size` | 來源 |
|
|
100
|
+
|---------|-------------|------|
|
|
101
|
+
| 獨立使用 | **24**(預設) | 不傳 |
|
|
102
|
+
| Button startIcon loading | `iconSize`(16 / 20) | Button 內部程式化 `<CircularProgress size={iconSize}/>` |
|
|
103
|
+
| Field endAction loading | `ICON_SIZE[size]`(16 / 16 / 20) | Input / Field 內部程式化(`loading` prop) |
|
|
104
|
+
| 取代 Avatar | 與 Avatar size 相同 | Consumer 傳 |
|
|
105
|
+
| Empty overlay 全頁 loading | **48** | Empty 範例與 story convention |
|
|
106
|
+
| 大型 card 中央 | 32–48 | Consumer 判 |
|
|
107
|
+
|
|
108
|
+
**程式化原則**:consumer wrapper(Button / Input `loading`)內部決定 size,consumer 不再傳;獨立場景(Empty / 自組 card)consumer 傳。
|
|
109
|
+
|
|
110
|
+
### 最大尺寸建議(不設硬上限)
|
|
111
|
+
|
|
112
|
+
不設 prop 上限(跟 Avatar 策略一致)。視覺建議 ≤ 64px。超過通常代表場景該改用 Empty 組合或動畫插圖。
|
|
113
|
+
|
|
114
|
+
### Determinate 達 100% 的 canonical:**swap 為完成 state,不留 value=100**
|
|
115
|
+
|
|
116
|
+
達 100% 時 consumer **必須 swap** 為完成狀態呈現,不保留 `<CircularProgress value={100}/>`:
|
|
117
|
+
|
|
118
|
+
| 完成後呈現 | 場景 |
|
|
119
|
+
|-----------|------|
|
|
120
|
+
| ✓ 打勾 icon(`<CircleCheck/>` / `<Check/>`) | cell inline / 上傳列表 row |
|
|
121
|
+
| 直接呈現該呈現的內容 | 資料載入完成 → 渲染實際 list / table / card |
|
|
122
|
+
| 切到 `<Empty>` 或其他 state component | 全頁 overlay → 內容出現;或 empty state |
|
|
123
|
+
| CircularProgress 直接消失 | 非同步操作完成,UI 回到預設態 |
|
|
124
|
+
|
|
125
|
+
**世界級慣例**:Gmail / Dropbox / Google Drive 上傳完成即消失;iOS Activity Indicator 完成隱藏;Figma / Notion async fetch 完成切到實際內容。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
126
|
+
|
|
127
|
+
**為什麼不留 100%**:`CircularProgress` 語義是「進行中」,停在 100% 跟「完成」的語義衝突,使用者看到「滿的 circle」會困惑「還在跑嗎?」。
|
|
128
|
+
|
|
129
|
+
### 不設 `status` prop — 完成 / 失敗由 consumer 端 swap
|
|
130
|
+
|
|
131
|
+
世界級 DS(Material / Chakra / Ant / Polaris)**沒有**「success / error CircularProgress」variant——完成與失敗的語義應由 consumer 在業務邏輯上**替換 CircularProgress 為實際內容**(Check icon + label / 結果 / 錯誤訊息等),不讓 progress 指示器本身做狀態 morph(綠底空心 circle + check icon 並排是 anti-pattern)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
// ✅ canonical — consumer 端 swap
|
|
135
|
+
{uploading
|
|
136
|
+
? <CircularProgress />
|
|
137
|
+
: done
|
|
138
|
+
? <><Check /> 已完成</>
|
|
139
|
+
: error
|
|
140
|
+
? <><AlertCircle /> 失敗,重試</>
|
|
141
|
+
: null}
|
|
142
|
+
|
|
143
|
+
// ❌ anti-pattern — 不存在的 API
|
|
144
|
+
<CircularProgress status="success" /> // 本 DS 無此 prop
|
|
145
|
+
<CircularProgress affix="status-icon" /> // 本 DS 無此選項
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Size canonical(一條規則)
|
|
149
|
+
|
|
150
|
+
**若 CircularProgress 放在 field-height 相關容器內,`size` 對齊該容器的 icon 尺寸;否則預設 `24`。**
|
|
151
|
+
|
|
152
|
+
| 情境 | 建議 size | 為什麼 |
|
|
153
|
+
|------|----------|--------|
|
|
154
|
+
| field-height 相關容器(Button loading / Input loading / DataTable cell / Field control loading 等) | 對齊容器的 iconSize(本 DS 全部是 `sm/md = 16 / lg = 20`) | 與容器內其他 icon 視覺同刻度,避免 row 內 icon 跳高低 |
|
|
155
|
+
| 獨立使用 / 全頁 / Empty overlay / Coachmark media 等無 field-height 約束 | 預設 24(傳統 Material 標準)— 需要更大(例如 Empty 大圖)可 32 / 48 | 無參考尺寸時走 DS 預設,不憑感覺挑 | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
156
|
+
|
|
157
|
+
**實作保證**:
|
|
158
|
+
- Button / Input / Field 等 **元件內部自動傳對的 size**(consumer 不用傳)— 來源:這些元件本來就知道自己的 `iconSize`(`field-controls.spec.md` 中 `sm/md=16, lg=20`)
|
|
159
|
+
- DataTable cell 由 consumer 手寫 render,**consumer 傳 `16`(sm/md table) / `20`(lg table)** — 規則在 `data-table.spec.md` 十一之一
|
|
160
|
+
- 獨立使用 CircularProgress 的元件 **預設走 24** — 已是 `<CircularProgress />` default
|
|
161
|
+
|
|
162
|
+
世界級對照:Material / Ant / Carbon 的 inline loading 全部 16dp;Material 獨立使用標準 = 40dp(desktop)/ 24dp(compact)。本 DS 收斂成「inline 跟 context 走 16 或 20,獨立走 24」兩檔,不暴露更多 size 階。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
163
|
+
|
|
164
|
+
### 顏色策略:固定 `text-primary` + consumer 覆寫
|
|
165
|
+
|
|
166
|
+
固定 `text-primary`(品牌語義色「正在處理」)。不隨狀態變色。
|
|
167
|
+
|
|
168
|
+
| Consumer | className | 實際色彩 |
|
|
169
|
+
|----------|-----------|---------|
|
|
170
|
+
| 獨立 / 全頁 / Empty overlay / Input loading | 無(走預設) | `text-primary` |
|
|
171
|
+
| Button `loading` 各 variant | `className="text-current"` | 繼承 button `text-on-emphasis` / `text-foreground` |
|
|
172
|
+
|
|
173
|
+
Track 色鎖 `var(--secondary)`(= neutral-3,與 ProgressBar track 一致)。
|
|
174
|
+
|
|
175
|
+
### Label 策略:font-size 繼承 + 色鎖 neutral-7
|
|
176
|
+
|
|
177
|
+
- `label` 有值 → render `<span className="text-fg-muted">`,font-size **繼承 parent**(不設 text-size class,CSS inherit 天然處理)
|
|
178
|
+
- 塞在元件內(Button / Field)時不用 label(元件本身已有文字);全頁 / Empty overlay 場景可開
|
|
179
|
+
|
|
180
|
+
### A11y 策略
|
|
181
|
+
|
|
182
|
+
| 模式 | role | aria 屬性 |
|
|
183
|
+
|------|------|----------|
|
|
184
|
+
| Determinate(`value` 有值) | `progressbar` | `aria-valuenow / aria-valuemin=0 / aria-valuemax=100` + optional `aria-label` |
|
|
185
|
+
| Indeterminate + 有 aria-label / label | `status` | `aria-label={label ?? aria-label}` |
|
|
186
|
+
| Indeterminate + 無 label | `aria-hidden=true` | 由父層 `aria-busy` 管理(Button 模式) |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 視覺與幾何鐵律
|
|
191
|
+
|
|
192
|
+
- **正方形不可妥協**:`style={{ width: size, height: size }}` 強制。本體絕不加 margin / padding
|
|
193
|
+
- **SVG 雙 circle**:track(`var(--secondary)`) + arc(`currentColor`),stroke-linecap round,rotate -90deg 從 12 點起始
|
|
194
|
+
- **strokeWidth 動態 scale**:`Math.max(2, Math.round(size / 10))` 維持跨尺寸視覺比例
|
|
195
|
+
- size 24 → stroke 2
|
|
196
|
+
- size 32 → stroke 3
|
|
197
|
+
- size 48 → stroke 5
|
|
198
|
+
- size 64 → stroke 6
|
|
199
|
+
- **Indeterminate arc**:固定 25%(`INDETERMINATE_ARC_RATIO=0.25`),外層 `animate-spin` 旋轉整個 span(Material 流派)
|
|
200
|
+
- **旋轉規則單純**:indeterminate → 轉;determinate → 不轉;沒有 status 條件分支,因為沒有 status。完成時 consumer 把整個 CircularProgress swap 成其他內容(Check icon / 結果 / Empty),不靠元件本身做 spin-stop 動畫
|
|
201
|
+
- **`align-middle` 鎖死**(SVG 對齊 adjacent text x-height 中線):外層 span 本體帶 `align-middle`,避免在 inline-flex 容器內出現基線錯位。consumer 若在文字旁放 CircularProgress,**不需**自己加 `align-middle` 或 `leading-none`
|
|
202
|
+
- **Determinate transition**:`transition-[stroke-dashoffset] duration-300`(value 變化時 smooth animation)
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Do / Don't
|
|
207
|
+
|
|
208
|
+
✅ **Do**
|
|
209
|
+
- 無進度資訊 → 不傳 value(indeterminate,替代舊 Spinner 用法)
|
|
210
|
+
- 有進度資訊 → 傳 `value={N}`(determinate + track)
|
|
211
|
+
- 跟 Button / Field loading 配合 → 走 `loading` prop,不自己 import
|
|
212
|
+
- 全頁 loading → `<Empty icon={<CircularProgress size={48}/>}/>`,不手刻 overlay
|
|
213
|
+
|
|
214
|
+
❌ **Don't**
|
|
215
|
+
- 不要 inline `<Loader2 className="animate-spin" />` — 用 CircularProgress
|
|
216
|
+
- 不要加 `color` / `variant` / `speed` / `thickness` prop — 單一職責
|
|
217
|
+
- 不要在本元件外包 `absolute inset-0 flex items-center justify-center` — 用 Empty compose
|
|
218
|
+
- 不要用 CircularProgress 表達裝飾效果 — 語意鎖「進度」,不轉其他
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 為何僅保留 Overview + 兩 consumer context stories
|
|
223
|
+
|
|
224
|
+
CircularProgress 是**最薄的 circular progress primitive**,刻意避免多維度變體:
|
|
225
|
+
|
|
226
|
+
- **無 Inspector**:variant 只有 value 有無 + status 三狀態(lifecycle),互動切換式 Inspector 可展的決策點少。`UsageInButton` / `UsageInline` 已覆蓋真實 consumer context
|
|
227
|
+
- **ColorMatrix N/A(只繼承 Progress color token)**:本元件 color 完全來自 `text-current`(繼承 host)+ Progress token(track / fill),無 own variant × state 色彩組合可 matrix 對照。status(running/success/error)已在 `UsageInButton` / `UsageInline` 真實 context 演示,獨立 ColorMatrix story 會是冗餘
|
|
228
|
+
- **SizeMatrix 透過 Inspector 即可展示 — 無 separate SizeMatrix story**:size 是自由 number(非 sm/md/lg tier),Inspector 的 size slider 即可展示 16 / 24 / 32 / 48 等常用值的行為差異,比靜態 matrix 更貼近消費情境
|
|
229
|
+
- **無 StateBehavior**:無 hover / focus / active,唯一「狀態」是 value 變化(已在 Determinate story 動態演示)
|
|
230
|
+
|
|
231
|
+
對應 anatomy story:`Overview` + `UsageInButton` + `UsageInline`。缺 canonical 5 多數項的 rationale 即本段。
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 邊界案例
|
|
236
|
+
|
|
237
|
+
- **Disabled(consumer host)**:CircularProgress 本身**不擁有 disabled state**(色彩繼承 host 的 `text-current`)。當消費 host 為 Button loading + disabled 組合時,spinner 顏色自動跟 Button text color 弱化為 `text-fg-disabled`;不需 CircularProgress 端 prop。
|
|
238
|
+
- **Loading(本即元件本質)**:本元件本質是 loading indicator;無需另外的 loading prop。indeterminate(無 `value`)= 旋轉動畫,determinate(有 `value`)= 弧長對應 0–100%。
|
|
239
|
+
- **Empty / 0 progress**:`value=0` 在 determinate mode 渲空 track,符合「尚未開始」語意;若 0 + lifecycle status `success`,自動切 success token(`UsageInline` story 演示)。
|
|
240
|
+
- **Dark mode**:走 Progress token + `text-current` 繼承,自動 adapt。
|
|
241
|
+
- **Size 極端值**:size 為自由 number(非 sm/md/lg tier);size < 12 不建議(stroke width / icon overlap 失調),size > 96 建議改 ProgressBar(linear 在大尺寸更易讀)。
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 相關
|
|
246
|
+
|
|
247
|
+
- **ProgressBar** — `components/ProgressBar/progress-bar.spec.md`(linear determinate 姊妹元件)
|
|
248
|
+
- **Avatar 自由 size 策略** — `components/Avatar/avatar.tsx`(同 pattern 先例)
|
|
249
|
+
- **Empty compose 全頁 loading** — `components/Empty/empty.spec.md`(icon slot 接 ReactElement)
|
|
250
|
+
- **Field loading state** — `components/Field/field-controls.spec.md`「Loading state」
|
|
251
|
+
- **Button loading prop** — `components/Button/button.tsx`(消費,使用 `text-current` 繼承)
|
|
252
|
+
|
|
253
|
+
## 遷移記錄(2026-04-20)
|
|
254
|
+
|
|
255
|
+
`Spinner` 元件已廢除並遷至本元件。Breaking change:
|
|
256
|
+
- `import { Spinner } from '.../Spinner/spinner'` → `import { CircularProgress } from '.../CircularProgress/circular-progress'`
|
|
257
|
+
- `<Spinner size={N}/>` → `<CircularProgress size={N}/>`(indeterminate 行為相同)
|
|
258
|
+
- `<Spinner size={N} aria-label="..."/>` → `<CircularProgress size={N} aria-label="..."/>`
|
|
259
|
+
- 新增能力:`<CircularProgress value={N}/>` 支援 determinate
|
|
260
|
+
|
|
261
|
+
遷移理由:世界級命名對齊 Material / Chakra,支援 determinate 需求(user 2026-04-20 提出),元件數減少(廢除重複的 Spinner 名稱)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
262
|
+
|
|
263
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
264
|
+
|
|
265
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
266
|
+
|
|
267
|
+
- `badge.spec.md`
|
|
268
|
+
- `skeleton.spec.md`
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Coachmark
|
|
3
|
+
family: composite
|
|
4
|
+
traits:
|
|
5
|
+
- isOverlay
|
|
6
|
+
variants: {}
|
|
7
|
+
sizes: {}
|
|
8
|
+
benchmark:
|
|
9
|
+
- Radix Popover primitive: github.com/radix-ui/primitives/tree/main/packages/react/popover
|
|
10
|
+
- Shepherd onboarding: github.com/shipshapecode/shepherd
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
14
|
+
|
|
15
|
+
# Coachmark 設計原則
|
|
16
|
+
|
|
17
|
+
## 定位
|
|
18
|
+
|
|
19
|
+
Coachmark 是**主動推送的功能介紹浮層**——anchor 到特定 UI 元素,帶 media + title + description + footer 按鈕列,用於首次功能介紹 / onboarding 多步導覽 / 新功能提示。
|
|
20
|
+
|
|
21
|
+
**實作基礎**:Popover 的 composition pattern——完全消費 Popover 的定位、動畫、焦點管理、overlay-surface padding 系統,不自寫浮層邏輯。差別:(1) **Header 可選**(`kind="tips" | "new-features" | ReactNode`;single-step 常無 header、multi-step tour 建議帶 header 提示整體脈絡),(2) 有 **Media 區**(可選,頂部 full-width 圖 / 截圖 / illustration),(3) Footer 是 `justify-between`(左 step 計數 / 右 actions)而非 `justify-end`。
|
|
22
|
+
|
|
23
|
+
**Layout Family**:非上述 family — composite / multi-section(Media / Body / Footer 多區塊組合)。
|
|
24
|
+
|
|
25
|
+
**世界級對照**:Apple HIG「Coachmark」(Apple 命名原處)/ Material「Feature Discovery」/ Ant Design `<Tour>` / Shepherd.js / react-joyride / Intercom Product Tours。命名採 Apple HIG 詞彙(最早且最廣泛被理解的術語)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 與 Popover 的關係
|
|
30
|
+
|
|
31
|
+
Coachmark **就是** Popover 的 composition —— 不是競品。改 Popover 視覺(bg / border / shadow / radius / padding)Coachmark 自動跟進,不需雙邊同步。唯一 Coachmark 自己擁有的視覺決策:
|
|
32
|
+
|
|
33
|
+
- **預設比 Popover 寬一階**:容納 media + 多行 description(主動推送內容量 > 篩選面板);具體寬度 class 見 `coachmark.tsx` cva
|
|
34
|
+
- **`p-0 overflow-hidden`**:移除 PopoverContent 預設 padding,讓 Media 邊緣對齊圓角;Body / Footer 自己消費 overlay-surface padding token
|
|
35
|
+
- **Footer `justify-between`**:step 計數(左)+ actions(右),對齊 Ant Tour / Intercom convention <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
36
|
+
|
|
37
|
+
SSOT 規則:**Coachmark 不重寫 Popover 的任何視覺 token**,只加自己結構層的差異。
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 與 Dialog 的分界
|
|
42
|
+
|
|
43
|
+
**核心差別:是否阻斷使用者流程**。
|
|
44
|
+
|
|
45
|
+
- **Coachmark**(non-modal 輔助):使用者可忽略、可 skip、可繼續原本的操作。onboarding 的精神是「幫忙介紹但不強迫」
|
|
46
|
+
- **Dialog**(modal 阻斷):使用者必須處理(確認 / 取消 / 完成表單)才能繼續
|
|
47
|
+
|
|
48
|
+
**判斷法**:「這個資訊不看會怎樣?」不看也能用 → Coachmark;不看就做不下去(破壞性動作、必要資訊輸入、多步表單)→ Dialog。
|
|
49
|
+
|
|
50
|
+
**為什麼 onboarding 絕不用 Dialog**:強制彈窗打斷使用者自主探索的動線,心理上造成「又是 tutorial?跳過」的本能反彈。Coachmark 的 non-modal 特性讓使用者保持主控權,tour 反而更容易被完整看完。
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 何時用
|
|
55
|
+
|
|
56
|
+
| 場景 | 範例 |
|
|
57
|
+
|------|------|
|
|
58
|
+
| 首次功能介紹 | 第一次使用 AI 助理功能時,anchor 到 AI 按鈕介紹「點這裡開始對話」 |
|
|
59
|
+
| Onboarding 多步導覽 | Notion-style 3-step tour:建立 workspace → 邀請成員 → 建立第一個頁面 |
|
|
60
|
+
| 版本更新 / What's new | 新 dashboard view 上線時提示「試試新的圖表模式」 |
|
|
61
|
+
| 新功能發現 | Intercom-style feature discovery,anchor 到功能 icon 並說明價值 |
|
|
62
|
+
|
|
63
|
+
## 何時不用
|
|
64
|
+
|
|
65
|
+
| 場景 | 改用 | 原因 |
|
|
66
|
+
|------|------|------|
|
|
67
|
+
| 錯誤訊息 / 系統通知 | `Notice` / `Alert` / `Toast` | Coachmark 是主動推送「要不要試試」,不是事件回饋 |
|
|
68
|
+
| 靜態 help text(hover 說明) | `Tooltip` | Tooltip 是被動查詢,Coachmark 是主動推送 |
|
|
69
|
+
| 確認破壞性動作 | `Dialog` | Coachmark 可忽略,破壞性動作必須阻斷 |
|
|
70
|
+
| 必要資訊輸入(表單 wizard) | `Dialog` + `Tabs` | 必填欄位不能讓使用者 skip |
|
|
71
|
+
| 一般點擊觸發的浮層面板 | `Popover` | Coachmark 是「系統主動出現」,Popover 是使用者點擊才出現 |
|
|
72
|
+
| Hover 觸發可互動浮層 | `HoverCard` | 觸發模型不同(Coachmark 由外部狀態控制) |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Anatomy
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
┌────────────────────────────────┐
|
|
80
|
+
│ Header(可選) │ ← SurfaceHeader padding;kind="tips"/"new-features"
|
|
81
|
+
│ 使用技巧 / 新功能介紹 │ text-caption uppercase text-fg-secondary
|
|
82
|
+
├────────────────────────────────┤
|
|
83
|
+
│ Media │ ← 可選,頂部 full-width,AspectRatio {16/9} default
|
|
84
|
+
│ (image / illustration / video) │ 邊緣對齊(overflow-hidden)
|
|
85
|
+
├────────────────────────────────┤
|
|
86
|
+
│ Body │ ← SurfaceBody padding(px-loose py-tight)
|
|
87
|
+
│ Title │ text-body-lg font-medium
|
|
88
|
+
│ Description │ text-body text-fg-secondary
|
|
89
|
+
├────────────────────────────────┤
|
|
90
|
+
│ Footer(justify-between) │ ← SurfaceFooter padding(px-loose py-tight)
|
|
91
|
+
│ 2 of 3 [Skip] [Next] │ 左 step / 右 actions
|
|
92
|
+
│ 1 of 3 [Prev] [Next] │ 多步驟中段:無 Skip,加 Prev
|
|
93
|
+
│ [知道了] │ 單步驟:無 step / Prev / Skip,只 CTA
|
|
94
|
+
└────────────────────────────────┘
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Props 結構
|
|
100
|
+
|
|
101
|
+
- `children` — trigger anchor(用 Popover asChild 定位)
|
|
102
|
+
- `kind` — `'tips' | 'new-features' | ReactNode`;有值則渲染 Header(tour-level title)
|
|
103
|
+
- `image` — ReactNode 媒體區;不傳則不渲染
|
|
104
|
+
- `title` / `description` — 文字內容;兩個都不傳則整個 Body 不渲染
|
|
105
|
+
- `step` — `{ current, total }`;有值則 footer 左側顯示 `2 of 3`
|
|
106
|
+
- `onSkip` / `onNext` / `onPrev` — footer 按鈕 callback;無 callback 不渲染該按鈕
|
|
107
|
+
- `isLastStep` — `true` 影響 CTA 文字(見下方「CTA 語義表」)
|
|
108
|
+
- `doneLabel` — 單步驟 CTA 自訂文字(預設 `'知道了'`)
|
|
109
|
+
- `open` / `onOpenChange` — controlled 控制(多步 tour 由 consumer 管理)
|
|
110
|
+
- `side` / `align` / `sideOffset` — 定位,對齊 Popover props(**`align` 跟隨 trigger 位置:左 → start / 中 → center / 右 → end**,見 `popover.spec.md`「Align 對齊 canonical」SSOT)
|
|
111
|
+
|
|
112
|
+
### CTA 語義表(世界級 canonical)
|
|
113
|
+
|
|
114
|
+
| 情境 | `onPrev` | `isLastStep` | CTA 文字 | Skip 顯示? |
|
|
115
|
+
|------|----------|--------------|----------|-----------|
|
|
116
|
+
| **單步驟**(只 1 步) | — | `true` | `doneLabel ?? '知道了'` | 否(單步驟無 skip 意義) |
|
|
117
|
+
| Multi 第一步 | — | `false` | `Next` | **是**(尚未投入進度) |
|
|
118
|
+
| Multi 中間步 | ✓ | `false` | `Next` | 否(有 Prev 時不再 Skip) |
|
|
119
|
+
| Multi 最後步 | ✓ | `true` | `Done` | 否 |
|
|
120
|
+
|
|
121
|
+
**為什麼單步驟 CTA 不叫 "Next"**:Next 語義隱含「還有下一步」,single step 用 Next 使用者會困惑「後面還有嗎?」。Apple HIG / Intercom / Pendo 同樣慣例:single-step tip / onboarding toast 一律用「知道了 / Got it / Start」類完成詞。
|
|
122
|
+
|
|
123
|
+
**為什麼有 Prev 時不顯示 Skip**:使用者按 Next 進到 step 2+ 代表已投入進度,此時同時出現「Prev(回上一步)」和「Skip(放棄全部)」語義衝突。Linear / Shepherd.js / Pendo tour 都在第 2 步後隱藏 Skip;想退出的使用者按 Esc / 關閉圖示即可(Radix 預設 Esc = dismiss)。
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Media 區規則
|
|
128
|
+
|
|
129
|
+
- **尺寸**:固定 `aspect-video`(16:9),確保不同 tour 步驟視覺一致,consumer 不需自己算高度
|
|
130
|
+
- **背景**:預設 `bg-muted`(當內容是 illustration 或透明 PNG 時有底色)
|
|
131
|
+
- **邊緣**:`overflow-hidden` + `rounded-t-lg` 讓媒體切齊浮層圓角
|
|
132
|
+
- **支援內容**:image / video / SVG illustration / animated GIF / Lottie
|
|
133
|
+
- **禁止**:不放互動元件(按鈕 / 輸入框)——media 純視覺說明,互動一律走 footer
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Multi-step Tour 模式
|
|
138
|
+
|
|
139
|
+
**Coachmark 本身不管理 step state**——consumer 自己管理 `currentStep` + 每步 anchor element:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
const [step, setStep] = useState(0)
|
|
143
|
+
const steps = [
|
|
144
|
+
{ anchorRef: workspaceBtnRef, title: '建立 workspace', ... },
|
|
145
|
+
{ anchorRef: inviteBtnRef, title: '邀請成員', ... },
|
|
146
|
+
{ anchorRef: projectBtnRef, title: '建立第一個專案', ... },
|
|
147
|
+
]
|
|
148
|
+
// 每步渲染一個 Coachmark,anchor 到對應元素
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**設計建議**:
|
|
152
|
+
- **≤ 5 步**——超過使用者疲勞,改用靜態 onboarding 頁面
|
|
153
|
+
- **Skip 只在第一步提供**——進到 step 2+ 後 Skip 自動隱藏(canonical,見上方「CTA 語義表」);想退出走 Esc / header Close 按鈕
|
|
154
|
+
- **最後一步 `isLastStep`**——Next → Done 語意切換,讓使用者知道「這是最後一步」
|
|
155
|
+
- **每步 anchor 到對應 feature**——不 anchor 或 anchor 到無關元素 = 失去「教 X 怎麼用」的精準性
|
|
156
|
+
- **Multi-step 建議傳 `kind="tips"` 或 `"new-features"`**——header 讓使用者一眼看出 tour 性質 / 何時結束的預期
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Footer 按鈕順序
|
|
161
|
+
|
|
162
|
+
Previous(可選)→ Skip(可選)→ Next / Done。對齊 Ant Tour / Intercom convention: <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
163
|
+
|
|
164
|
+
- **Previous 最左**——回到上一步(負方向,視覺權重低)
|
|
165
|
+
- **Skip 中間**——exit escape hatch,tertiary 不搶焦點;**僅第一步顯示**(見 CTA 語義表)
|
|
166
|
+
- **Next / Done 最右**——推進主動線(正方向,primary 視覺權重高);**不強制 autoFocus** — 讓 Radix 預設行為接管(通常 focus 第一個 focusable),避免使用者還在讀 body 時按 Enter 誤推進
|
|
167
|
+
|
|
168
|
+
第 1 步通常無 Previous;最後步 Next 改 Done(由 `isLastStep` 控制)。單步驟 CTA 改 `'知道了'`。
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 視覺 Token
|
|
173
|
+
|
|
174
|
+
| 層 | Token | 說明 |
|
|
175
|
+
|----|-------|------|
|
|
176
|
+
| 浮層外殼 | 繼承 Popover(`bg-surface-raised` / `border-border` / `rounded-lg` / `--elevation-200`) | 改 Popover 自動跟進 |
|
|
177
|
+
| Media 背景 | `bg-muted` | illustration / 透明 PNG 底色 |
|
|
178
|
+
| Title | `text-body-lg font-medium text-foreground` | 比 Popover header 輕(Coachmark 無 header 分隔線) |
|
|
179
|
+
| Description | `text-body text-fg-secondary` | 主說明文字 |
|
|
180
|
+
| Step 計數 | `text-caption text-fg-secondary tabular-nums` | 數字等寬,切換步驟不跳動 |
|
|
181
|
+
| Body padding | `px-[var(--layout-space-loose)] py-[var(--layout-space-tight)]` | overlay-surface SSOT(PopoverBody) |
|
|
182
|
+
| Footer padding | 同上 | overlay-surface SSOT(PopoverFooter) |
|
|
183
|
+
| Width | 比 Popover 預設寬一階(固定,具體 class 見 `coachmark.tsx`) | 固定;consumer 可 className 覆寫 |
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 禁止事項
|
|
188
|
+
|
|
189
|
+
- ❌ **不用 Coachmark 做錯誤提示**——錯誤是系統回饋使用者動作的結果,用 `Notice` / `Alert` / `Toast`。Coachmark 是主動推送教學,語意相反
|
|
190
|
+
- ❌ **不用 Coachmark 做確認框**——確認破壞性動作必須阻斷流程,改用 `Dialog`
|
|
191
|
+
- ❌ **Media 區不放互動元件**——按鈕 / 輸入 / checkbox 一律走 footer。Media 是視覺說明不是互動區
|
|
192
|
+
- ❌ **Description 不寫超過 3 行**——Coachmark 是快速說明,超過 3 行改用 Dialog + 完整 body 或連結到說明文件
|
|
193
|
+
- ❌ **不強迫完成 tour**——永遠提供退出機制(Esc / header Close / 第一步 Skip)。沒有退出的 onboarding 讓使用者感到被綁架,反而降低完成率
|
|
194
|
+
- ❌ **單步驟 CTA 不叫 "Next"**——沒有下一步就不用 Next 字眼,用 `'知道了' / 'Got it' / 'Start'`
|
|
195
|
+
- ❌ **有 Prev 時不同時顯示 Skip**——使用者投入進度後兩個退出路徑衝突(見 CTA 語義表)
|
|
196
|
+
- ❌ **不自包視覺 token**——bg / shadow / radius / padding 一律繼承 Popover,改視覺就改 Popover
|
|
197
|
+
- ❌ **不在 Coachmark 內放 nested Popover / Dialog**——層級混亂焦點崩壞,複雜互動結束 tour 後再開
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## A11y 預設
|
|
202
|
+
|
|
203
|
+
- **焦點管理**:由 Popover(Radix)處理——開啟移焦點進 content,關閉 return to trigger
|
|
204
|
+
- **Esc 關閉**:預設啟用(= Skip 行為)——user 按 Esc 等同 skip,尊重退出意願
|
|
205
|
+
- **ARIA**:trigger 自動 `aria-expanded` / `aria-controls`,content `role="dialog"`(Radix 預設)
|
|
206
|
+
- **Step 計數 tabular-nums**:螢幕閱讀器讀「2 of 3」語意清楚
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 邊界狀態
|
|
211
|
+
|
|
212
|
+
disabled / density 繼承 Popover(density 鎖 md,見 `../Popover/popover.spec.md`);empty(title + description 都不傳)則 Body 不渲染(已於「Props 結構」規定);loading 由 consumer 決定。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 相關
|
|
217
|
+
|
|
218
|
+
- `../Popover/popover.spec.md` — Coachmark 的實作基礎,所有浮層視覺 SSOT
|
|
219
|
+
- `../Dialog/dialog.spec.md` — modal 阻斷浮層,與 Coachmark non-modal 對立
|
|
220
|
+
- `../../patterns/overlay-surface/overlay-surface.spec.md` — Body / Footer padding SSOT(經 Popover 消費)
|
|
221
|
+
- `../Tooltip/tooltip.spec.md` — hover 觸發純文字提示
|
|
222
|
+
- `../HoverCard/hover-card.spec.md` — hover 觸發互動浮層
|
|
223
|
+
- `../Notice/notice.spec.md` — 系統通知 / 錯誤訊息
|
|
224
|
+
- Apple HIG Coachmarks / Ant Design `<Tour>` / Shepherd.js — 世界級對照 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
225
|
+
|
|
226
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
227
|
+
|
|
228
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
229
|
+
|
|
230
|
+
- `aspect-ratio.spec.md`
|