@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,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ProgressBar
|
|
3
|
+
family: self-contained
|
|
4
|
+
traits: []
|
|
5
|
+
variants: {}
|
|
6
|
+
sizes: {}
|
|
7
|
+
benchmark:
|
|
8
|
+
- Radix Progress primitive: github.com/radix-ui/primitives/tree/main/packages/react/progress
|
|
9
|
+
- Ant Design Progress: github.com/ant-design/ant-design/tree/master/components/progress
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
13
|
+
|
|
14
|
+
# ProgressBar 設計原則
|
|
15
|
+
|
|
16
|
+
**水平進度條(linear determinate progress)**——表達「已完成 X%、還剩 Y%」的量化進度視覺 primitive。0–100% 的已知進度、單向推進、可預期終點。circular 形式(含 indeterminate)走 `CircularProgress`。
|
|
17
|
+
|
|
18
|
+
**Layout Family**:非上述 family — self-contained primitive(獨立視覺,無 slot 結構;僅 `affix` 附加區可選顯示進度文字或狀態 icon)。
|
|
19
|
+
|
|
20
|
+
**實作基礎**:基於 Radix `@radix-ui/react-progress` primitive(原生提供 `role="progressbar"` + `aria-valuenow` / `aria-valuemin` / `aria-valuemax` / `aria-valuetext`),外包本 DS 的 status / affix 語意與 token。高度**固定 4px**,不提供 size 選項(見下「單一高度」節)。
|
|
21
|
+
|
|
22
|
+
> 最薄的 linear determinate progress primitive。沒有 indeterminate animation(那屬 `CircularProgress` 無 value 模式的職責)、沒有 buffered fill(目前無 streaming 場景)、沒有自訂色(只能走 inProgress / success / error 三狀態)。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 定位
|
|
27
|
+
|
|
28
|
+
ProgressBar 是**量化 linear 進度** primitive——consumer 必須能回答「目前進度是百分之幾」才能使用。若無法量化(e.g. fetching 中不知道要多久),改用 `CircularProgress`(不傳 value,indeterminate 模式)。
|
|
29
|
+
|
|
30
|
+
世界級對照:
|
|
31
|
+
- **Material** `LinearProgress`(determinate) — 同樣區分 determinate / indeterminate 兩模式,indeterminate 在我們系統由 `CircularProgress`(無 value)承擔
|
|
32
|
+
- **Ant Design** `Progress` — 支援百分比文字、status(success/exception/normal),我們以 `affix="value"` / `status` 對應 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
33
|
+
- **Polaris** `ProgressBar` — 單一直線進度,不含 status 色區分,我們加上 status 對應上傳完成 / 失敗語意 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
34
|
+
- **shadcn** `Progress` — 同為 Radix Progress 薄包裝
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 何時用
|
|
39
|
+
|
|
40
|
+
- **批次任務進度**:CSV 匯入、批量同步、報表生成(Linear batch action / Jira bulk edit / Airtable import)
|
|
41
|
+
- **下載 / 匯出進度**(非檔案上傳列表情境):單檔下載進度、匯出 zip、報表生成
|
|
42
|
+
- **多步驟流程的整體進度**:表單 wizard「步驟 3/5 = 60%」(但**步驟結構本身**用 `Steps` 元件,ProgressBar 只表達整體完成比例)
|
|
43
|
+
- **Table cell / row 內的 inline 進度**:DataTable 裡「配額使用率 45%」、「完成度 78%」等單列靜態指標
|
|
44
|
+
|
|
45
|
+
## 何時不用
|
|
46
|
+
|
|
47
|
+
| 場景 | 改用 | 原因 |
|
|
48
|
+
|------|------|------|
|
|
49
|
+
| **檔案上傳 / 下載列表** | `FileItem` | FileItem 是檔案情境 canonical consumer-facing primitive,內部已消費 ProgressBar(見「與 FileItem 的分界」)——consumer 不自組 raw ProgressBar + 檔名 + icon 做上傳 UI |
|
|
50
|
+
| 進度無法量化(fetch / 等待 server) | `CircularProgress`(無 value,indeterminate) | ProgressBar 需已知 0-100%,無法估算終點時用 CircularProgress 的 indeterminate 語意 |
|
|
51
|
+
| <1 秒的短暫操作 | `CircularProgress` 或不顯示 | ProgressBar 動畫(300ms transition)在極短操作反而造成閃爍 |
|
|
52
|
+
| 骨架載入(預期內容形狀) | `Skeleton` | Skeleton 保留 layout,ProgressBar 只傳達「執行中量化」 |
|
|
53
|
+
| 步驟導覽(顯示 step 1/2/3 結構) | `Steps` | Steps 強調 step 本身是什麼、ProgressBar 只看整體百分比 |
|
|
54
|
+
| 容量 / 配額靜態顯示(非動態進行中) | 可用 ProgressBar(不傳 status,預設 inProgress 即可) | 可接受——ProgressBar 也能表達靜態 ratio,但若只是裝飾比例、非「進行中」語意,考慮 Chart bar 類元件 |
|
|
55
|
+
| 評分顯示(5 顆星 80%) | `Rating` | Rating 有離散刻度語意 |
|
|
56
|
+
| 小空間 / inline icon 位置的量化進度 | `CircularProgress`(有 value,determinate) | ProgressBar 在 16–24px 的小空間視覺比例不如 circular arc |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 與 CircularProgress 的分界(SSOT)
|
|
61
|
+
|
|
62
|
+
**本節為 ProgressBar ↔ CircularProgress 分界的 single source of truth**,`circular-progress.spec.md` 的定位表以 pointer 指向本節深度規則。
|
|
63
|
+
|
|
64
|
+
**核心判斷**:兩個維度擇一(兩者都必須通過才選 ProgressBar):
|
|
65
|
+
1. **能量化進度嗎?**(ProgressBar 必須能;CircularProgress 兩態都接受)
|
|
66
|
+
2. **形狀適合 linear 還是 circular?**(頁面級 / 表單 wizard / 上傳列表 = linear;inline 小空間 / Button / Field = circular)
|
|
67
|
+
|
|
68
|
+
| 維度 | ProgressBar | CircularProgress |
|
|
69
|
+
|------|-------------|------------------|
|
|
70
|
+
| **形狀** | linear(水平直線) | circular(圓弧) |
|
|
71
|
+
| **進度模式** | determinate(0–100% 已知) | 兩態合一:無 value → indeterminate / 有 value → determinate |
|
|
72
|
+
| **視覺** | 水平直線從左往右填充 | 圓弧從 12 點順時針填充 / indeterminate 整體旋轉 |
|
|
73
|
+
| **典型情境** | 批次處理 / 表單 wizard / 頁面級大區塊 / quota(檔案上傳 → 走 FileItem) | Button loading / Field loading / cell 局部 / inline 小 % |
|
|
74
|
+
| **可量化時機** | **必須能量化**(100% 結束可預期) | determinate 能量化 / indeterminate 不需要 |
|
|
75
|
+
| **a11y** | `role="progressbar"` + `aria-valuenow` | `role="progressbar"`(有 value) / `role="status"`(無 value) |
|
|
76
|
+
| **終止條件** | 到 100% 或 status 變 success / error | 任務完成(卸載或 aria-busy 移除) |
|
|
77
|
+
| **typical 時長** | 秒級到分鐘級(值得顯示比例) | 秒級(短暫等待) / 秒到分鐘(determinate) |
|
|
78
|
+
|
|
79
|
+
**選擇 flowchart**:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
1. 有進度數值嗎?
|
|
83
|
+
├─ 沒有 / 不知道時長 ────────→ CircularProgress(不傳 value)
|
|
84
|
+
│ ├─ < 1 秒 ──→ 不顯示(避免閃爍)
|
|
85
|
+
│ ├─ 1-10 秒 ──→ CircularProgress indeterminate
|
|
86
|
+
│ └─ > 10 秒 + 無量化 ──→ CircularProgress + 額外文字說明
|
|
87
|
+
│
|
|
88
|
+
└─ 有(0-100%)
|
|
89
|
+
2. 場景形狀適合?
|
|
90
|
+
├─ 頁面級 / 表單級 / 上傳列表 / 大區塊 ─→ ProgressBar
|
|
91
|
+
└─ inline 小空間 / Button / Field / cell ─→ CircularProgress(傳 value)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**禁止混搭**:同一操作內不能先 CircularProgress 再 ProgressBar(會讓使用者以為是兩個獨立步驟)。一個操作若一開始不知進度、中段才取得 → 維持 indeterminate CircularProgress 到底,或改由上層 overlay 控制切換。
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## API
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
export interface ProgressBarProps {
|
|
102
|
+
/** 當前進度 0-100,超出範圍自動 clamp */
|
|
103
|
+
value: number
|
|
104
|
+
/** inProgress=進行中 / success=完成 / error=失敗 */
|
|
105
|
+
status?: 'inProgress' | 'success' | 'error'
|
|
106
|
+
/** 右側附加:value=顯示 `{value}%` / status-icon=顯示狀態圖示 / ReactNode=客製 */
|
|
107
|
+
affix?: 'value' | 'status-icon' | React.ReactNode
|
|
108
|
+
/**
|
|
109
|
+
* Track 高度 override(**非 consumer API**)。
|
|
110
|
+
* 僅 FileItem 的 compact mode 內部使用,匹配極密集 row 的視覺比例。
|
|
111
|
+
* Consumer 不要傳此 prop;若有新需求應先討論是否開新 variant,而非濫用此逃生艙。
|
|
112
|
+
*/
|
|
113
|
+
height?: number
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Status 語意
|
|
118
|
+
|
|
119
|
+
| Status | 語意 | fill token | 使用時機 |
|
|
120
|
+
|--------|------|-----------|---------|
|
|
121
|
+
| `inProgress`(預設) | 進行中 / 未完成 ratio | `--primary` | 處理中、靜態比例顯示、CSV 匯入 |
|
|
122
|
+
| `success` | 完成 / 成功 | `--success` | value 到 100% 且操作成功完成 |
|
|
123
|
+
| `error` | 失敗 / 中斷 | `--error` | 處理中斷、配額超出警示 |
|
|
124
|
+
|
|
125
|
+
**禁止新增 `warning` status**:ProgressBar 的語意是「進行中 / 成功 / 失敗」二元終態,warning 屬於 Notice / Alert 的範疇。若要表達配額警示(如 90% 快滿),consumer 自己根據 value 切換到 `error`,不要在 ProgressBar 加中間色。
|
|
126
|
+
|
|
127
|
+
### 單一高度 4px(2026-04-20 決策)
|
|
128
|
+
|
|
129
|
+
本元件**不提供 size 選項**,track 固定 `4px`——對齊 Material 3 / Carbon / Ant Design 慣例(皆固定單一高度)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
130
|
+
|
|
131
|
+
**為什麼不分 size**:
|
|
132
|
+
- 過往分 size 的刻度差太小,視覺差異使用者幾乎無法區分,形同冗餘 API
|
|
133
|
+
- 分 size 反而讓 consumer 每次要「判斷該選哪個」,增加認知負擔
|
|
134
|
+
- 世界級 canonical:Material LinearProgress / Carbon ProgressBar / Ant Progress 皆固定單一高度,無 size variant <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
135
|
+
- 若需要視覺強調(hero level progress),改用 full-width 排版 + 放大百分比文字 / swap 為 CircularProgress 大尺寸,不靠 size 階梯撐
|
|
136
|
+
|
|
137
|
+
### 與 FileItem 的分界(consumer 選哪個)
|
|
138
|
+
|
|
139
|
+
**檔案上傳 UI 一律走 `FileItem`,不直接消費 ProgressBar**。FileItem 是檔案情境的 canonical consumer-facing primitive(檔名 / icon / 進度 / status / actions 一條龍);FileItem 內部**可能**消費 ProgressBar(實作細節,consumer 不用關心)。
|
|
140
|
+
|
|
141
|
+
| 情境 | 用什麼 |
|
|
142
|
+
|------|--------|
|
|
143
|
+
| 單檔 / 多檔上傳列表 / 下載 progress | **FileItem**(`components/FileItem/`)|
|
|
144
|
+
| CSV 匯入 / 批次處理 / 表單 wizard / quota 使用率 | **ProgressBar** 直接用 |
|
|
145
|
+
| 短暫 loading(不知時長) | **CircularProgress**(indeterminate) |
|
|
146
|
+
|
|
147
|
+
**世界級對照**:Ant Design 的 `Upload` vs `Progress`(Upload.List 內部用 Progress,consumer 不直接拼 Progress 做上傳 UI)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
148
|
+
|
|
149
|
+
### Affix 選擇
|
|
150
|
+
|
|
151
|
+
| Affix | 適用時機 | 範例 |
|
|
152
|
+
|-------|---------|------|
|
|
153
|
+
| `"value"` | 靜態 poll 場景 / 使用者想知道具體百分比 | DataTable cell「配額 78%」、FileItem「45%」 |
|
|
154
|
+
| `"status-icon"` | final state(success ✓ / error ✗)| 上傳完成顯示勾、失敗顯示叉 |
|
|
155
|
+
| `ReactNode` | 客製(e.g. action button「取消」、file size「2.3/5.0 MB」) | 上傳中顯示「取消」按鈕 |
|
|
156
|
+
| 不傳 | in-flight 不需額外資訊 | 短暫過渡狀態、nested 容器已有進度文字 |
|
|
157
|
+
|
|
158
|
+
**禁止**:同時在 affix 顯示 value 又在旁邊額外寫 `{value}%` 文字——會重複。取一個。
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 禁止事項
|
|
163
|
+
|
|
164
|
+
❌ **不得硬寫色值**——所有 status 色必走 `--primary` / `--success` / `--error` token,consumer 不可 override fill 色(若業務需要其他色,提到系統層討論新 status,不是每個消費者自己改)
|
|
165
|
+
|
|
166
|
+
❌ **不得將 ProgressBar 當 CircularProgress 用**——進度不可量化的操作一律用 `CircularProgress`(不傳 value),不要傳 `value={indeterminate ? ... : ...}` 假裝進度
|
|
167
|
+
|
|
168
|
+
❌ **不得堆疊多個 ProgressBar 在同一操作**——每個操作一個 bar。多檔上傳清單 = 每檔一個 ProgressBar,但「整體進度」不再加一條總 bar(Dropbox / Google Drive 皆此做法)
|
|
169
|
+
|
|
170
|
+
❌ **不得用於 <1 秒的短暫操作**——動畫 transition(300ms)會造成閃爍,改用 CircularProgress 或不顯示
|
|
171
|
+
|
|
172
|
+
❌ **不得用於未知進度**(詳見「與 CircularProgress 的分界」)
|
|
173
|
+
|
|
174
|
+
❌ **不得加 `warning` status**(見 Status 語意節)
|
|
175
|
+
|
|
176
|
+
❌ **不得在 ProgressBar 內塞內容(children)**——它是純視覺,附加資訊走 `affix`
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 狀態與邊界
|
|
181
|
+
|
|
182
|
+
- **Disabled**:本元件無 disabled 狀態。ProgressBar 是純視覺回饋,不接受互動事件。若整個上傳流程被禁用,由 parent container 控制(e.g. 包裝 `<fieldset disabled>` 或不 render)
|
|
183
|
+
- **Loading**:ProgressBar 本身就是 loading 的視覺,不再疊加 CircularProgress
|
|
184
|
+
- **Empty / 0%**:value=0 時仍 render 整條 track(灰底 + 無填充),不做特殊 empty state
|
|
185
|
+
- **Dark mode**:fill 色透過 semantic token(`--primary` / `--success` / `--error`)自動反轉,詳見 `color.spec.md`
|
|
186
|
+
- **Density**:本元件不隨 density 縮放(track 單一高度,見 tsx)
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## A11y 預設
|
|
191
|
+
|
|
192
|
+
Radix `Progress.Root` 自動提供:
|
|
193
|
+
- `role="progressbar"`
|
|
194
|
+
- `aria-valuenow={value}` / `aria-valuemin={0}` / `aria-valuemax={100}`
|
|
195
|
+
- 如需客製 announce(e.g.「上傳中 45%」),在 parent 傳 `aria-valuetext="上傳中 45%"` override
|
|
196
|
+
|
|
197
|
+
**Consumer 需補**:若此 ProgressBar 代表特定語境任務,在 parent 加 `aria-label`(e.g.「檔案上傳進度」)讓螢幕閱讀器能辨認。
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 為何無 StateBehavior
|
|
202
|
+
|
|
203
|
+
ProgressBar 是**純視覺百分比指示**,本身**無互動狀態**(見「狀態與邊界」段:無 disabled,不接受互動事件)。唯一的「行為」是 value 變化時 fill 寬度動畫——那是 controlled prop 的資料更新,不是 UI state 切換。color variant(inProgress / success / error)依 value 狀態切換的行為已在 `ColorMatrix` + 元件特有 `AffixBehavior`(percent / icon-on-complete 驅動邏輯)覆蓋。
|
|
204
|
+
|
|
205
|
+
對應 anatomy story:保留 `Overview` + `Inspector`(value 試玩) + `ColorMatrix` + 元件特有 `AffixBehavior`。無 `SizeMatrix`(高度固定 4px)。
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 相關
|
|
210
|
+
|
|
211
|
+
- **CircularProgress 分界** — 本 spec「與 CircularProgress 的分界」節(SSOT)
|
|
212
|
+
- **CircularProgress 元件** — `components/CircularProgress/circular-progress.spec.md`(circular 兩態 primitive)
|
|
213
|
+
- **FileItem 消費** — `components/FileItem/file-item.tsx`(canonical 檔案情境 consumer-facing primitive,內部消費 ProgressBar 的 4px 單一高度)
|
|
214
|
+
- **Steps** — `components/Steps/steps.spec.md`(步驟結構非百分比)
|
|
215
|
+
- **Skeleton** — `components/Skeleton/skeleton.spec.md`(骨架載入非進度)
|
|
216
|
+
- **Color tokens** — `tokens/color/color.spec.md`(`--primary` / `--success` / `--error` 定義)
|
|
217
|
+
|
|
218
|
+
## 遷移記錄(2026-04-20)
|
|
219
|
+
|
|
220
|
+
元件由 `Progress`(folder `Progress/` + identifier `Progress`)重命名為 `ProgressBar`(folder `ProgressBar/` + identifier `ProgressBar`)。Breaking change:
|
|
221
|
+
|
|
222
|
+
- `import { Progress } from '.../Progress/progress'` → `import { ProgressBar } from '.../ProgressBar/progress-bar'`
|
|
223
|
+
- `<Progress value={N}/>` → `<ProgressBar value={N}/>`(props 契約未變)
|
|
224
|
+
- `ProgressProps` type name → `ProgressBarProps`
|
|
225
|
+
|
|
226
|
+
重命名理由:`CircularProgress` 元件(circular 兩態合一)納入系統後,需和 `Progress`(原 linear)在名稱上明確區分形狀。`ProgressBar` 對齊 Polaris / shadcn 命名慣例,使用者一看即知是 linear。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
227
|
+
|
|
228
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
229
|
+
|
|
230
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
231
|
+
|
|
232
|
+
- `file-item.spec.md`
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: RadioGroup
|
|
3
|
+
family: 4
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes:
|
|
6
|
+
sm:
|
|
7
|
+
when: "form field-height 28 / compact chrome / dialog / panel context"
|
|
8
|
+
md:
|
|
9
|
+
when: "default general UI"
|
|
10
|
+
lg:
|
|
11
|
+
when: "touch / prominent CTA / stakeholder-facing surface"
|
|
12
|
+
traits:
|
|
13
|
+
- hasSizes
|
|
14
|
+
- hasInteractiveStates
|
|
15
|
+
- isSelectionMulti
|
|
16
|
+
benchmark:
|
|
17
|
+
- Radix RadioGroup primitive: github.com/radix-ui/primitives/tree/main/packages/react/radio-group
|
|
18
|
+
- Ant Design Radio: github.com/ant-design/ant-design/tree/master/components/radio
|
|
19
|
+
- MUI Radio: github.com/mui/material-ui/tree/master/packages/mui-material/src/Radio
|
|
20
|
+
- Polaris RadioButton: github.com/Shopify/polaris/tree/main/polaris-react/src/components/RadioButton
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
24
|
+
|
|
25
|
+
# RadioGroup 設計原則
|
|
26
|
+
|
|
27
|
+
## 定位
|
|
28
|
+
|
|
29
|
+
RadioGroup 是**互斥單選且全選項可見**的表單控件——從 2-5 個選項中挑恰好一個,每個選項一行獨立呈現(支援 label + description + 完整閱讀)。
|
|
30
|
+
|
|
31
|
+
**Layout Family**:非上述 family — self-contained primitive(獨立視覺,無 slot 結構)。
|
|
32
|
+
|
|
33
|
+
**實作基礎**:基於 Radix RadioGroup(shadcn 包裝)+ 橋接 DS token。
|
|
34
|
+
|
|
35
|
+
共用規則見 `../Checkbox/checkbox.spec.md`(Checkbox & RadioGroup 設計原則,含 SelectionItem 佈局與 clamp 政策)。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 何時用
|
|
40
|
+
|
|
41
|
+
- **決策節點的互斥單選**:付款方式、訂閱方案、票種、權限角色——使用者需要**對比評估**
|
|
42
|
+
- **選項需要描述文字**:法律條款、方案價格、feature 比較(Radio 的 description 支援完整閱讀,不截斷)
|
|
43
|
+
- **2-5 個選項且全部可見**:讓使用者一眼看完所有選項,不需要點兩次(Select)
|
|
44
|
+
- **空間允許 O(n) 垂直展開**:form 內、dialog 內、setting section 內
|
|
45
|
+
|
|
46
|
+
## 何時不用
|
|
47
|
+
|
|
48
|
+
**與 Select 的分界詳見 `../Select/select.spec.md` 的「與 RadioGroup 的分界」**(SSOT)——Select 是 Select vs RadioGroup 判斷的 owner。簡言:RadioGroup 用於「使用者需對比評估的決策節點」,Select 用於「label 自帶語意、空間受限、使用者熟悉選項」。
|
|
49
|
+
|
|
50
|
+
| 場景 | 改用 | 原因 |
|
|
51
|
+
|------|------|------|
|
|
52
|
+
| 空間受限 / 選項超過 5 個 | `Select` | RadioGroup 全可見,O(n) 垂直空間成本過高 |
|
|
53
|
+
| 2-5 個緊湊切換(toolbar / filter) | `SegmentedControl` | compact control,pill 尺寸融入 toolbar |
|
|
54
|
+
| 多選(可選多個)| `Checkbox` | Radio 是互斥單選,Checkbox 是獨立 toggle |
|
|
55
|
+
| 布林 on/off | `Switch`(即時)/ 單個 `Checkbox`(on-submit) | 布林不需要「選一個」的心智模型 |
|
|
56
|
+
| 大量選項需要搜尋 | `Select` + `searchable` | RadioGroup 不支援搜尋 |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 與 Checkbox 的差異
|
|
61
|
+
|
|
62
|
+
視覺語言共用(見 Checkbox spec),差異僅在:
|
|
63
|
+
|
|
64
|
+
- **形狀**:`rounded-full`(Checkbox 是 `rounded-md`)
|
|
65
|
+
- **指示器**:filled dot(Checkbox 是 check / minus icon)
|
|
66
|
+
- **語意**:互斥單選(Checkbox 可多選)
|
|
67
|
+
- **`fieldLayout`**:`'block'`(放進 `<Field>` 時 Field 自動切 block 模式;Checkbox 沒有此 static 屬性,因為單個 Checkbox 是 inline primitive)
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 尺寸
|
|
72
|
+
|
|
73
|
+
共用 Checkbox 的 sm/md/lg 控件尺寸(sm/md=16px, lg=20px),詳見 `../Checkbox/checkbox.spec.md`「尺寸」。
|
|
74
|
+
|
|
75
|
+
### 為什麼不完全對齊 `--field-height-*`
|
|
76
|
+
|
|
77
|
+
- **現況**:控件 sm=16 / md=16 / lg=20px(不等於 `--field-height-sm/md/lg` = 28/32/36px)
|
|
78
|
+
- **Rationale**:Radio 與 Checkbox 視覺語言共用(只是形狀 round vs square),rationale 完全繼承 Checkbox——控件是選擇指示器(indicator)不是容器,走 icon tier(16/16/20),行高對齊透過 SelectionItem 的 `py = (field-height - 1lh) / 2` 保證
|
|
79
|
+
- **世界級對照**:Material 3 Radio = 20px / Ant Design Radio = 16px / Polaris RadioButton = 16px——全部獨立於 field-height,與 Checkbox 控件尺寸對齊 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## StateBehavior(RadioGroup 層級特有)
|
|
84
|
+
|
|
85
|
+
Item-level default / hover / active / checked / disabled **色彩**與 Checkbox 共用同一套 SelectionItem 規則,由 `ColorMatrix` story 承載;RadioGroup 的 `StateBehavior` story 展示**群組層級的互斥行為**(單選模型 / 個別 disabled / 整組 disabled),這是 Checkbox 沒有的維度。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Mode / disabled / readonly / 驗證 / a11y
|
|
90
|
+
|
|
91
|
+
繼承 Field family,詳見 `../Field/field-controls.spec.md` + `../Field/form-validation.spec.md`。
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 禁止事項
|
|
96
|
+
|
|
97
|
+
- ❌ 單選卻用 Checkbox 群組模擬——selection model 不對,keyboard navigation 與 a11y 角色錯誤
|
|
98
|
+
- ❌ RadioGroup 沒有 group label(`<Field>` 的 label 或 `aria-labelledby`)——螢幕閱讀器無法念出這是哪組選項
|
|
99
|
+
- ❌ 巢狀 RadioGroup(radio 內包 radio)——互斥模型只適用單層,需要階層選擇改用樹狀 Select
|
|
100
|
+
- ❌ 選項數量超過 5 或空間受限時硬用 RadioGroup,不改 Select(見「何時不用」)
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 邊界案例
|
|
105
|
+
|
|
106
|
+
- **Disabled**:Group-level `disabled` 套用至所有 radio items;item-level `disabled` 單獨 disable 該選項。視覺繼承 SelectionItem SSOT(`text-fg-disabled` + 灰 radio circle + 不可點 + 鍵盤導覽自動 skip)。
|
|
107
|
+
- **Loading(async option fetch)**:async option list 載入時 consumer 應渲 `<Skeleton>` 對應 radio item count(常見 3-5 行 skeleton),而非空 RadioGroup;RadioGroup 自身不獨立 own loading prop。
|
|
108
|
+
- **Empty(no options)**:罕見場景。應由 consumer 條件性渲 `<Empty>` placeholder(「無可選項目」)取代空 RadioGroup,不渲 0-radio 空 group(SR 會讀「empty group」造成混淆)。
|
|
109
|
+
- **No value selected**:`value=null` 為合法 initial state(所有 radio 都 unchecked);Field validation 在 required + null 時觸發 error。
|
|
110
|
+
- **Dark mode / density**:走 SelectionItem semantic token 自動 adapt;垂直 gap 隨 layoutSpace token density-aware。
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 相關
|
|
115
|
+
|
|
116
|
+
- `../Checkbox/checkbox.spec.md` — 共用規則(SelectionItem 佈局 / clamp 政策 / 視覺語言)
|
|
117
|
+
- `../Select/select.spec.md` — 「與 RadioGroup 的分界」SSOT(Select vs RadioGroup 決策的 owner)
|
|
118
|
+
- `../SegmentedControl/segmented-control.spec.md` — compact 互斥切換的替代
|
|
119
|
+
- `../Switch/switch.spec.md` — 布林開關
|
|
120
|
+
- `../Field/field.spec.md` — RadioGroup 作為 Field control 時的 block layout 整合
|
|
121
|
+
|
|
122
|
+
## A11y 預設
|
|
123
|
+
|
|
124
|
+
**ARIA / Pattern**:繼承 Radix `radio-group` primitive a11y 預設(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/radio-group#accessibility)。
|
|
125
|
+
|
|
126
|
+
**Keyboard 行為**:
|
|
127
|
+
|
|
128
|
+
- Tab — 進入 group
|
|
129
|
+
- ↑/↓ — 切 option
|
|
130
|
+
- Space — 選擇
|
|
131
|
+
|
|
132
|
+
**Focus**:Radix primitive 自管 focus trap / restoration / visible ring(`outline: 2px solid var(--ring)` per design-system focus-visible canonical)。
|
|
133
|
+
|
|
134
|
+
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
135
|
+
|
|
136
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
137
|
+
|
|
138
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
139
|
+
|
|
140
|
+
- `selection-item.spec.md`
|
|
141
|
+
- `steps.spec.md`
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Rating
|
|
3
|
+
family: 4
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes: {}
|
|
6
|
+
traits:
|
|
7
|
+
- hasInteractiveStates
|
|
8
|
+
- isMatrixHeavy
|
|
9
|
+
benchmark:
|
|
10
|
+
- Ant Design Rate: github.com/ant-design/ant-design/tree/master/components/rate
|
|
11
|
+
- MUI Rating: github.com/mui/material-ui/tree/master/packages/mui-material/src/Rating
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
15
|
+
|
|
16
|
+
# Rating 設計原則
|
|
17
|
+
|
|
18
|
+
## 定位
|
|
19
|
+
|
|
20
|
+
Rating 是**離散 1–5 分評分元件**——使用者對商品、服務、體驗給出 1 到 max(預設 5)分的星等,或將已提交的平均分數唯讀展示。
|
|
21
|
+
|
|
22
|
+
**實作基礎**:自建,無 shadcn 核心或 Radix primitive 對應(shadcn 不提供 Rating,Ant Design `<Rate>` / Material `<Rating>` 為世界級對照)。內部以 lucide-react `Star` 為預設 icon,外層 `role="slider"` / `role="img"` 依 `readOnly` 切換。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
23
|
+
|
|
24
|
+
**Layout Family**:非 4-Family Model —— **self-contained primitive**(獨立視覺,無 slot 結構,類似 Switch / Checkbox / Badge / CircularProgress)。
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 何時用
|
|
29
|
+
|
|
30
|
+
- **送出評分**(interactive):Yelp / Google Reviews / Amazon 購物完後「幫這次服務評分」的送出前狀態
|
|
31
|
+
- **展示評分**(readOnly):商品列表的星等 `4.7 ★★★★★`、評論列表每則評論的作者星等、Airbnb 房源總分
|
|
32
|
+
- **後台商品管理**:店家自己給商品的推薦星等(interactive)
|
|
33
|
+
- **精度展示**:平均分 `4.7`(`precision="half"` 顯示半星),單筆 `5`(`precision="full"` 整星)
|
|
34
|
+
|
|
35
|
+
## 何時不用
|
|
36
|
+
|
|
37
|
+
| 情境 | 改用 | 原因 |
|
|
38
|
+
|------|------|------|
|
|
39
|
+
| 純資訊標記(「熱門」「Beta」「新品」)| `Badge` | Rating 是量化 1–5 分,不是分類標籤 |
|
|
40
|
+
| 非 1–5 的連續數值(音量、亮度、價格範圍)| `Slider` | Rating 是離散 tier,Slider 是連續值 |
|
|
41
|
+
| 二元喜歡 / 不喜歡(thumbs up/down、like)| `Switch` 或自組 icon button | Like 是 binary,Rating 是 graded 1–5 |
|
|
42
|
+
| 多維度評比(服務 / 品質 / 速度 各 5 分)| 自組多個 Rating 縱向排列 | 單一 Rating 只表達單一維度 |
|
|
43
|
+
| 進度顯示(任務完成度、上傳進度) | `ProgressBar`(linear)/ `CircularProgress`(circular,有 value) | Rating 不是進度指標,別誤用星星做「完成 4/5 步」|
|
|
44
|
+
| 已提交固定分數但可跳轉「看詳情」| readOnly Rating + 旁邊 Button/Link | Rating 本身不點擊跳頁 |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
| Prop | 型別 | 預設 | 說明 |
|
|
51
|
+
|------|------|------|------|
|
|
52
|
+
| `value` | `number` | — | 當前評分(controlled,0 ~ `max`) |
|
|
53
|
+
| `defaultValue` | `number` | `0` | uncontrolled 預設值 |
|
|
54
|
+
| `onChange` | `(value: number) => void` | — | 評分改變 callback |
|
|
55
|
+
| `max` | `number` | `5` | 滿分星數(世界級慣例 = 5,超過 7 會讓使用者無法快速掃視) |
|
|
56
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | 尺寸。standalone 展示建議 `xs`(24px,對齊 Avatar/Tag sm);Field 內跟 Field size 傳 sm/md/lg |
|
|
57
|
+
| `precision` | `'full' \| 'half'` | `'full'` | 整星 or 半星 |
|
|
58
|
+
| `readOnly` | `boolean` | `false` | 唯讀展示(不響應 hover / click / 鍵盤) |
|
|
59
|
+
| `disabled` | `boolean` | `false` | 完全停用 |
|
|
60
|
+
| `icon` | `LucideIcon` | `Star` | 自訂 icon(極少用;禁止換成 Heart / ThumbsUp,見禁止事項) |
|
|
61
|
+
| `aria-label` | `string` | — | `readOnly` 時必填(例:「平均評分 4.7 星,共 5 星」) |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Size
|
|
66
|
+
|
|
67
|
+
| Size | Container 高度 | Star icon | 使用情境 | 配對 field |
|
|
68
|
+
|------|---------------|-----------|---------|-----------|
|
|
69
|
+
| `xs` | **24px**(`h-field-xs`) | 20px | **Standalone 建議值**:商品卡、評論列表旁、搜尋結果 row 的星等展示(非 Field 內時) | — |
|
|
70
|
+
| `sm` | 28px(`h-field-sm`) | 20px | Field sm 並排 | field sm |
|
|
71
|
+
| `md` | 32px(`h-field-md`) | 24px | **Field 預設**。一般表單評分欄位 | field md |
|
|
72
|
+
| `lg` | 36px(`h-field-lg`) | 24px | 送出評分的 review form、強調的主 CTA 區塊 | field lg |
|
|
73
|
+
|
|
74
|
+
### Standalone vs Field 尺寸選擇(canonical)
|
|
75
|
+
|
|
76
|
+
- **Standalone 展示**(非 Field 內):用 **`xs`**(container 24 / icon 20)——對齊 Avatar sm 20px / Tag sm;Airbnb / Yelp 商品卡星星亦此大小 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
77
|
+
- **Field 內**(`<Field>` 表單內當 control):跟 Field size 對應傳 sm/md/lg(Field 預設 md)
|
|
78
|
+
- 世界級對照:Material Rating standalone ≈ 24dp;Ant Rate 在 Form 內跟 Form itemSize。兩種 context 分開設計,不強求單一預設 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
79
|
+
|
|
80
|
+
### Icon 尺寸對齊 **Avatar inline**,不對齊 icon tier(2026-04-21 AR48 canonical)
|
|
81
|
+
|
|
82
|
+
Rating 的 **container 高度消費 `--field-height-*` token**(sm=28 / md=32 / lg=36),讓它可以與 Input / Select / NumberInput / Button 等 field-height family 元件並排時 row-align 一致。
|
|
83
|
+
|
|
84
|
+
**Star icon 大小對齊 `item-anatomy` 的 inline Avatar 尺寸**(sm=20 / md=24 / lg=24),**不走 icon tier**(16/16/20)。
|
|
85
|
+
|
|
86
|
+
| Size | Rating star | Avatar inline | Icon tier | 使用者選到 |
|
|
87
|
+
|------|-------------|---------------|-----------|-----------|
|
|
88
|
+
| sm | **20px** ← Avatar | 20px | 16px | Avatar(更重視覺) |
|
|
89
|
+
| md | **24px** ← Avatar | 24px | 16px | Avatar |
|
|
90
|
+
| lg | **24px** ← Avatar | 24px | 20px | Avatar |
|
|
91
|
+
|
|
92
|
+
**為什麼對齊 Avatar 不對齊 icon tier**:
|
|
93
|
+
|
|
94
|
+
1. **視覺份量**:Rating 的「一顆星」是 **filled shape**(整個 icon 面積都是重量),不像純 outline icon 靠 stroke。跟 filled identity 元件(Avatar)同尺寸才能在 row 裡 visual weight 對齊。
|
|
95
|
+
2. **語意**:Rating 是「主要資料視覺」(一顆星 = 一個資料點),不是次要 affordance。次要 affordance(如 Input 的 startIcon、Button iconOnly)才走 icon tier(16/16/20)。
|
|
96
|
+
3. **世界級對照**:Ant Rate in Form = 20px(對齊 Form avatar-like components);Material MUI Rating default 24px;Airbnb 商品卡星星 24px。皆走 identity 重量,不走 icon tier。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
97
|
+
4. **歷史錯誤**:早期設 16/16/20 跟 icon tier 齊,但視覺上跟 inline avatar / tag 並排時星星顯得比 avatar「小一號」,失去「這一顆星是資料點」的語感——AR48 修正。
|
|
98
|
+
|
|
99
|
+
### 放入 Field 的可組合性
|
|
100
|
+
|
|
101
|
+
Rating 可直接塞進 `<Field>`(讓使用者能套 Field label / error / hint 共用機制):
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<Field>
|
|
105
|
+
<FieldLabel required>整體滿意度</FieldLabel>
|
|
106
|
+
<Rating value={rating} onChange={setRating} size="md" />
|
|
107
|
+
{rating === 0 && <FieldError>請至少給 1 星</FieldError>}
|
|
108
|
+
</Field>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Field 高度由 Rating container(`h-field-md`)自然對齊其他 field control,不需 consumer 額外調整 min-h。`aria-invalid` 透過 FieldContext 自動傳入,視覺錯誤提示由 FieldError 承擔。
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Precision — full vs half
|
|
116
|
+
|
|
117
|
+
| Precision | 顯示值 | 使用情境 |
|
|
118
|
+
|-----------|--------|---------|
|
|
119
|
+
| `full` | 1, 2, 3, 4, 5 | **送出評分**——使用者給分當下只選整數(Yelp / Google Reviews 送出流程就是整星)|
|
|
120
|
+
| `half` | 0.5, 1, 1.5, ..., 5 | **展示平均分**——`4.7` 這類小數只有半星能視覺呈現(Amazon / Shopify 的 `4.7 ★★★★★` 商品列表)|
|
|
121
|
+
|
|
122
|
+
**原則**:**interactive = full**(使用者按整星清晰、無猶豫),**display average = half**(小數需要更細的視覺刻度)。要給使用者「打半星」的能力只在極特殊情境(如影評社群),一般 SaaS 不建議。
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Interactive vs ReadOnly
|
|
127
|
+
|
|
128
|
+
| Mode | 觸發 | 行為 | ARIA |
|
|
129
|
+
|------|------|------|------|
|
|
130
|
+
| **interactive**(預設)| `readOnly={false} && disabled={false} && loading={false}` | hover 預覽、click 設值、鍵盤 Arrow Left/Right/Up/Down 改值、Focus ring | `role="slider"` + `aria-valuenow/valuemin/valuemax` + `tabIndex={0}` |
|
|
131
|
+
| **readOnly** | `readOnly={true}` | 純顯示,不響應 hover / click / 鍵盤 | `role="img"` + `aria-label`(**必填**,給螢幕閱讀器描述分數)|
|
|
132
|
+
| **disabled** | `disabled={true}` | 不響應,視覺淡化(`opacity-disabled`)| `aria-disabled="true"` |
|
|
133
|
+
| **loading** | `loading={true}` | 不響應,視覺同 disabled(uniform dim)——但語義是「正在取得既有評分 / 正在儲存」,非永久不可互動 | `aria-busy="true"`(screen reader 宣告「忙碌中」) |
|
|
134
|
+
|
|
135
|
+
**判斷法**:
|
|
136
|
+
- **送出前 = interactive**,**送出後 / 顯示他人評分 = readOnly**。
|
|
137
|
+
- **loading 跟 disabled 視覺相同但語義不同**:loading = 暫時性(fetch / save in flight);disabled = 永久性業務規則(例:評分期限已過)。screen reader 會區分(`aria-busy` vs `aria-disabled`)。
|
|
138
|
+
|
|
139
|
+
一顆星 Rating 同時給自己評和看別人評的常見錯誤是都用 interactive——使用者會誤以為可以改別人的分數。
|
|
140
|
+
|
|
141
|
+
### Loading canonical(composite 元件 opacity pattern)
|
|
142
|
+
|
|
143
|
+
Rating 是**複合 element**(多顆星共同組成評分值),loading 走 **composite 整塊 dim** 策略(對齊 FileUpload / Sidebar menu row),**不**套 skeleton 替換星星:
|
|
144
|
+
- **為什麼不 skeleton**:星星數是 schema(`max=5`)不是 data,loading 中消失變成「動態結構」,使用者誤以為星星數本身在變
|
|
145
|
+
- **為什麼不 spinner**:會與 readOnly 圖示混淆;loading 是**暫時性等待**不是「純展示」
|
|
146
|
+
|
|
147
|
+
API:`loading?: boolean` prop(對齊 `../Field/field-controls.spec.md` Field 家族 loading canonical,但這裡採 composite dim 非 endAction spinner)。
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 視覺 Token
|
|
152
|
+
|
|
153
|
+
| Role | Token | 色值(light) | 說明 |
|
|
154
|
+
|------|-------|--------------|------|
|
|
155
|
+
| Filled star | `var(--warning)` | yellow-6 | 世界級黃星 convention(Amazon / Yelp / Google / Shopify / Airbnb 都是黃)| <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
156
|
+
| Empty star | `var(--color-neutral-4)` | 中灰 | 未填的輪廓色,與 disabled / empty state 同級 |
|
|
157
|
+
| Hover 放大 | `scale-110` + `transition-transform` | — | interactive 時 hover 單顆星放大 10%,給予 preview 回饋 |
|
|
158
|
+
| Focus ring | `ring-2 ring-ring ring-offset-2` + `rounded-md` | — | 鍵盤 focus 時整個 Rating 容器顯示 focus ring(**per-star 無 ring / border / outline**——focus 視覺由 parent container 統一承擔)|
|
|
159
|
+
| Gap between stars | `gap-1` | 4px | 五顆星之間的間距,不隨 size 變化 |
|
|
160
|
+
| Disabled | `opacity-disabled` + `pointer-events-none` | — | 整體降透明度,阻擋所有事件 |
|
|
161
|
+
|
|
162
|
+
### Star icon 無 stroke outline
|
|
163
|
+
|
|
164
|
+
Star icon 渲染時明確設 `stroke="none"`(Lucide Star 預設有 1.5px outline stroke,保留會讓 filled 星星多一層深色 outline,破壞純 fill-only shape canonical)。**Rating 是純 fill-only shape**,不保留 outline——對齊 Ant Rate / Material MUI Rating 的世界級慣例。Empty star 靠 `--color-neutral-4` 的 fill 本身與 canvas 對比區隔,不需 outline 補視覺。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
165
|
+
|
|
166
|
+
### 為什麼用 `--warning`(黃色)而不用 `--primary`
|
|
167
|
+
|
|
168
|
+
黃星是**世界級 convention**——Amazon / Yelp / Google Reviews / Shopify / Airbnb / TripAdvisor 全部用黃。使用者的視覺記憶已經把「黃星 = 評分」綁定,換成品牌 primary 色(藍、綠、紫)會破壞這個直覺。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
169
|
+
|
|
170
|
+
`--warning` 在本系統指向 yellow-6,與 Rating **共用色相但語境不同**——evaluation convention color,非 status color。這是 documented 例外(見 `color.spec.md`),不是每個元件都能這樣共用。
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## A11y 預設
|
|
175
|
+
|
|
176
|
+
- **interactive**:`role="slider"` + `aria-valuenow={value}` + `aria-valuemin={0}` + `aria-valuemax={max}` + `tabIndex={0}`,鍵盤 Arrow Left/Right/Up/Down 改值(precision=half 時 step=0.5,否則 step=1)
|
|
177
|
+
- **readOnly**:`role="img"` + `aria-label`(**必填**),例:`aria-label="平均評分 4.7 星,共 5 星"`。無 tabIndex
|
|
178
|
+
- **disabled**:`aria-disabled="true"` + `pointer-events-none`
|
|
179
|
+
- **單顆星** `aria-hidden`:所有內部 `<button>`(包含 half-precision 的兩個 hover zone)都是 `aria-hidden` 不干擾螢幕閱讀器,父層 role 獨自表達語意
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 禁止事項
|
|
184
|
+
|
|
185
|
+
- ❌ **不用其他色相填充**(藍 / 綠 / 紫 / 紅)——黃星是世界級 convention,破壞使用者的視覺記憶
|
|
186
|
+
- ❌ **不換成 Heart / ThumbsUp / ThumbsDown icon**——那是 like / dislike 的 binary 表達,不是 graded rating。愛心用 `Button iconOnly startIcon={Heart} pressed={liked}`
|
|
187
|
+
- ❌ **`readOnly` 必填 `aria-label`**——純視覺的星星螢幕閱讀器讀不出「4.7 分」
|
|
188
|
+
- ❌ **不用 Rating 做 progress bar**——Rating 語意是「給分」,用「填了 4 顆星」表達「完成 4/5 步」會誤導
|
|
189
|
+
- ❌ **不用於 binary 情境**(「喜歡 / 不喜歡」)——改用 Switch 或 thumbs icon button
|
|
190
|
+
- ❌ **interactive 狀態下不與 `Field` 的 `Label` 分離超過一個 section**——使用者要清楚「這個評分屬於誰 / 哪個面向」
|
|
191
|
+
- ❌ **`max` 不設超過 7**——超過使用者無法快速掃視,若需更細分度改用 Slider(連續 0–100)
|
|
192
|
+
- ❌ **send-form 用 `precision="half"`**——送出評分選半星會讓使用者猶豫(`4` 跟 `4.5` 差在哪?);半星只用於展示平均值
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 相關
|
|
197
|
+
|
|
198
|
+
- **`Slider`** — 連續數值選擇(0–100、音量、亮度、價格區間)。Rating vs Slider 分界:離散 tier = Rating,連續值 = Slider
|
|
199
|
+
- **`Badge`** — 靜態分類標記(「熱門」「Beta」「NEW」)。Rating 是量化,Badge 是分類
|
|
200
|
+
- **`Switch`** — 二元 on/off。Rating 是 graded,Switch 是 binary
|
|
201
|
+
- **`Button iconOnly + pressed={liked}`** — 愛心 / like 的正確實作
|
|
202
|
+
- **Color token 例外** — `color.spec.md`「共用 `--warning` 色相但語境不同」段落
|
|
203
|
+
|
|
204
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
205
|
+
|
|
206
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
207
|
+
|
|
208
|
+
- `uiSize.spec.md`
|