@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,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Skeleton
|
|
3
|
+
family: self-contained
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes: {}
|
|
6
|
+
traits:
|
|
7
|
+
- isMatrixHeavy
|
|
8
|
+
benchmark:
|
|
9
|
+
- Ant Design Skeleton: github.com/ant-design/ant-design/tree/master/components/skeleton
|
|
10
|
+
- MUI Skeleton: github.com/mui/material-ui/tree/master/packages/mui-material/src/Skeleton
|
|
11
|
+
- Polaris SkeletonBodyText: github.com/Shopify/polaris/tree/main/polaris-react/src/components/SkeletonBodyText
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Skeleton 設計原則
|
|
15
|
+
|
|
16
|
+
## 定位
|
|
17
|
+
|
|
18
|
+
Skeleton 是**載入中的內容佔位符**——在資料載入完成前,用灰色色塊模擬真實內容的形狀與排版,讓使用者預期即將出現的佈局。
|
|
19
|
+
|
|
20
|
+
**Layout Family**:非上述 family — self-contained primitive(獨立視覺,無 slot 結構)。
|
|
21
|
+
|
|
22
|
+
**實作基礎**:shadcn passthrough——純 CSS animated gradient div。本 DS 保留 shadcn 原結構 + 橋接 DS token。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 何時用
|
|
27
|
+
|
|
28
|
+
- **初次載入資料的 list / table / card grid**:保留內容形狀讓使用者預期佈局
|
|
29
|
+
- **非同步載入的 dashboard widget / chart**:資料來之前填滿空間避免跳動
|
|
30
|
+
- **內容切換後的短暫載入**:router 切換、tab 切換後的過渡狀態
|
|
31
|
+
- **已知佈局結構的等待**:佈局固定 + 資料動態的場景
|
|
32
|
+
|
|
33
|
+
## 何時不用
|
|
34
|
+
|
|
35
|
+
| 場景 | 改用 | 原因 |
|
|
36
|
+
|------|------|------|
|
|
37
|
+
| 小區塊 / 按鈕內的 loading | `CircularProgress` | CircularProgress(indeterminate)適合不佔空間的小 inline loading |
|
|
38
|
+
| 整頁 / overlay loading | `<Empty icon={<CircularProgress/>}/>` compose | Skeleton 是內容佔位,不是頁面遮罩 |
|
|
39
|
+
| 確認「沒有資料」的空狀態 | `Empty` | Empty 是「確定沒有」,Skeleton 是「還沒來」 |
|
|
40
|
+
| 錯誤 / 失敗狀態 | `Alert` + 重試 | Skeleton 無錯誤語意 |
|
|
41
|
+
| 進度有具體百分比 | `ProgressBar` / `CircularProgress`(有 value) | Skeleton 是不定進度占位,有 % 用 determinate progress |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Skeleton vs CircularProgress
|
|
46
|
+
|
|
47
|
+
| | Skeleton | CircularProgress(indeterminate) |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| 視覺 | 內容形狀占位(灰色色塊) | 旋轉圓弧 |
|
|
50
|
+
| 尺寸 | 隨內容(list row / card / text line) | 自由 size(常用 16 / 20 / 24 / 48) |
|
|
51
|
+
| 訊號強度 | 弱(暗示「佈局已就位」) | 強(暗示「正在處理」) |
|
|
52
|
+
| 典型用途 | 初次載入 list / grid | Button loading、cell 載入、inline 等待 |
|
|
53
|
+
|
|
54
|
+
**判準**:
|
|
55
|
+
- **有已知佈局結構需保留 → Skeleton**(佔位、防跳動)
|
|
56
|
+
- **小區塊 / inline 等待 → CircularProgress**(無 value,indeterminate)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 禁止事項
|
|
61
|
+
|
|
62
|
+
- ❌ 用 Skeleton 取代 Empty(確定沒有資料的空狀態)——語意不同
|
|
63
|
+
- ❌ 用 Skeleton 取代 error state——錯誤需要明確提示 + 解決路徑
|
|
64
|
+
- ❌ Skeleton 形狀嚴重偏離真實內容——會讓使用者預期被打破、體感更慢
|
|
65
|
+
- ❌ 長時間(> 10s)的 loading 一直用 Skeleton——使用者會懷疑是否卡住,需改用 progress indicator 或說明文字
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 為何無 Inspector / ColorMatrix / SizeMatrix / StateBehavior
|
|
70
|
+
|
|
71
|
+
Skeleton 是 pure passive primitive(占位用的 animated gradient div),刻意無變體:
|
|
72
|
+
|
|
73
|
+
- **無 Inspector**:Skeleton 唯一變因是「形狀」(w / h / rounded),由 consumer 透過 className 決定。互動 Inspector 無 prop 可調——該討論的是「怎麼畫出符合實際內容的形狀」,由 `CommonShapes` story 覆蓋。
|
|
74
|
+
- **無 ColorMatrix**:Skeleton 底色固定為 `bg-muted`(2026-05-20 修正歷史 drift `bg-secondary`,實際 `skeleton.tsx:10` 用 `bg-muted` — 對齊 `color.spec.md` 「Static Subtle」段「placeholder / 退化」原則)。Dark mode 自動由 semantic token 處理,加 color variant 會誤導成狀態變化(Skeleton 是 loading 中,不該有語意色)。
|
|
75
|
+
- **無 SizeMatrix**:Skeleton 無 size prop,尺寸完全由 consumer className(`w-32 h-4`)或 parent 決定——因為它要精確模擬內容形狀,不能限制成 sm/md/lg tier。
|
|
76
|
+
- **無 StateBehavior**:Skeleton 只有「顯示 / 不顯示」兩態(consumer unmount 即消失),無 hover / focus / active / selected / disabled——非互動元件。
|
|
77
|
+
|
|
78
|
+
對應 anatomy story:保留 `Overview` + 元件特有 `CommonShapes`(避免漂移的標準形狀庫) + `DesignPrinciple`(與 CircularProgress 的分界)。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## A11y 預設
|
|
83
|
+
|
|
84
|
+
Skeleton 是**純視覺 loading placeholder**,預設 ARIA 行為:
|
|
85
|
+
|
|
86
|
+
- **`aria-hidden="true"`(預設,Skeleton 內部自動設)**:Skeleton 純視覺占位,SR 不朗讀 N 條 placeholder shape
|
|
87
|
+
- **`aria-busy="true"` 由 consumer 容器 own**:loading region 的容器(如 DataTable / Card / Sidebar group)應設 `aria-busy="true"`,告知 SR「該區域 loading 中」;data ready 後 consumer 移除 `aria-busy` 同時 unmount Skeleton
|
|
88
|
+
- **不取得 focus**:Skeleton 永遠 non-interactive,無鍵盤行為
|
|
89
|
+
- **動畫**:`prefers-reduced-motion: reduce` 用戶自動 stop pulse 動畫(對齊 WCAG 2.3.3 Animation from Interactions)
|
|
90
|
+
- **替代文字**:長時間 loading(>3s)consumer 應 fallback 為 `<Empty icon={<CircularProgress/>} description="載入中..." />`(SR-friendly text)— Skeleton 適合 < 3s 短暫 placeholder
|
|
91
|
+
- **驗證**:Storybook a11y addon panel 0 critical violation;不該被 axe 警告「missing label」(因為 aria-hidden 排除)
|
|
92
|
+
|
|
93
|
+
## 相關
|
|
94
|
+
|
|
95
|
+
- `../CircularProgress/circular-progress.spec.md` — 小區塊 / inline loading 的對應元件(取代 Spinner)
|
|
96
|
+
- `../Empty/empty.spec.md` — 確定沒有資料的空狀態
|
|
97
|
+
- `../Alert/alert.spec.md` — 錯誤 / 失敗狀態
|
|
98
|
+
- `../../tokens/color/color.spec.md` — Skeleton 底色 token(`bg-muted` / animated gradient,2026-05-20 修 drift)
|
|
99
|
+
|
|
100
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
101
|
+
|
|
102
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
103
|
+
|
|
104
|
+
- `progress-bar.spec.md`
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Slider
|
|
3
|
+
family: 4
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes:
|
|
6
|
+
sm:
|
|
7
|
+
px: 28
|
|
8
|
+
when: "Toolbar / inline 編輯;對齊 field-height-sm"
|
|
9
|
+
world-class: ["VS Code zoom slider", "Figma toolbar inline"]
|
|
10
|
+
md:
|
|
11
|
+
px: 36
|
|
12
|
+
when: "預設 — Form + 設定面板 + DataTable cell inline edit"
|
|
13
|
+
world-class: ["Material Slider default", "Polaris RangeSlider", "Ant Slider"]
|
|
14
|
+
lg:
|
|
15
|
+
px: 44
|
|
16
|
+
when: "Marketing hero 互動 / 高 touch 區"
|
|
17
|
+
world-class: ["Apple HIG slider touch zone"]
|
|
18
|
+
traits:
|
|
19
|
+
- hasSizes
|
|
20
|
+
- hasInteractiveStates
|
|
21
|
+
- isMatrixHeavy
|
|
22
|
+
benchmark:
|
|
23
|
+
- Radix Slider primitive: github.com/radix-ui/primitives/tree/main/packages/react/slider
|
|
24
|
+
- Ant Design Slider: github.com/ant-design/ant-design/tree/master/components/slider
|
|
25
|
+
- MUI Slider: github.com/mui/material-ui/tree/master/packages/mui-material/src/Slider
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
29
|
+
|
|
30
|
+
# Slider 設計原則
|
|
31
|
+
|
|
32
|
+
**數值範圍選取器**——基於 Radix Slider primitive,橋接設計系統 token。
|
|
33
|
+
|
|
34
|
+
> 命名:`Slider`(沿用 Radix / shadcn / Material 慣例)。
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 定位
|
|
39
|
+
|
|
40
|
+
使用者沿著一條軌道拖曳 thumb 選擇一個數值(single)或一段範圍(range)。適合**連續或密集離散的數值選取**,當使用者在意「相對位置」勝過「精確數字」時使用。
|
|
41
|
+
|
|
42
|
+
**Layout Family**:非上述 family — self-contained primitive(track + thumb + range,非 row / pill / field 結構)。高度對齊 Field family 僅為視覺整齊(`size` prop 映射 `h-field-*`),並非消費 Field layout 的 slot 結構。
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 何時用
|
|
47
|
+
|
|
48
|
+
- **「感受性」連續值**:亮度 / 音量 / 縮放 / 透明度
|
|
49
|
+
- **範圍選取**:價格區間、日期區間、分數區間
|
|
50
|
+
- **使用者在意「相對位置」勝過「精確數字」**:粗略調整 > 精確輸入
|
|
51
|
+
- **搭配顯示值**:thumb 旁標籤或同步 NumberInput 讓使用者掌握精確數字
|
|
52
|
+
|
|
53
|
+
## 何時不用
|
|
54
|
+
|
|
55
|
+
| 場景 | 改用 | 原因 |
|
|
56
|
+
|------|------|------|
|
|
57
|
+
| 離散且少量選項(3–5 個) | `SegmentedControl` / `RadioGroup` | Slider 為連續值設計,離散少量用分段控件視覺更清楚 |
|
|
58
|
+
| 精確數字輸入 | `NumberInput` | Slider 難以拖到精確值,打字更快 |
|
|
59
|
+
| 布林切換 | `Switch` | 布林不是數值 |
|
|
60
|
+
| 「多少」而非「哪裡」(計數) | `NumberInput`(含 ±step) | Slider 傳達 position,不是 quantity |
|
|
61
|
+
| 純篩選布林 | `Checkbox` | 非數值型篩選 |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 尺寸
|
|
66
|
+
|
|
67
|
+
### 一種視覺,多種容器尺寸
|
|
68
|
+
|
|
69
|
+
**Slider 的視覺是固定的**——track 厚度、thumb 直徑、focus ring 都是單一值,不會隨 `size` 變動。這是跟 Button / Input 等元件的明顯差異,理由是:
|
|
70
|
+
|
|
71
|
+
- Slider 的 thumb 必須足夠容易被手指 / 鼠標捕捉,改小會降低可用性
|
|
72
|
+
- 連續拖曳的 track 太細會看不清楚 range
|
|
73
|
+
- 業界(Material / Ant / Radix Themes / shadcn)都只有一組 thumb / track 視覺,不做多尺寸
|
|
74
|
+
|
|
75
|
+
**但**,Slider 可以被丟進 `Field` 容器跟 `Input` / `Select` / `NumberInput` 等並排,這時它**必須跟該 Field 的 `size` 對齊高度**(否則一排 sm field 裡混一個 md 高度的 slider,breakline rhythm 會崩)。
|
|
76
|
+
|
|
77
|
+
### 解決方式:`size` prop 只控容器外高
|
|
78
|
+
|
|
79
|
+
Slider 接收 `size?: 'sm' | 'md' | 'lg'` prop(預設 `md`),**這個 prop 只決定 root 容器的 `h-field-*` class**,不改變 track 厚度、thumb 直徑、ring 尺寸。內部視覺元素透過 flex `items-center` 在容器中**垂直置中**,所以不論容器高度是 28 / 32 / 36 px,track 和 thumb 的位置都在中間,視覺體驗一致。
|
|
80
|
+
|
|
81
|
+
這樣做的效果:
|
|
82
|
+
- 視覺:一種尺寸,任何 Field context 長得都一樣
|
|
83
|
+
- 對齊:完美對齊 Field family 的 field-height tier
|
|
84
|
+
- API 一致性:跟 Input / NumberInput 同樣有 `size` prop,消費者不需要特別記「Slider 沒有 size」
|
|
85
|
+
|
|
86
|
+
### 為什麼不完全對齊 `--field-height-*`
|
|
87
|
+
|
|
88
|
+
- **現況**:容器高 = `--field-height-sm/md/lg`(對齊);track 厚度固定 4px / thumb 直徑固定 16px / focus ring 固定 2px,**皆不隨 size 變化**(偏離 size-proportional scaling)
|
|
89
|
+
- **Rationale**:Slider 的 thumb 是「位置指示器」,必須足夠大好捕捉(Fitts's Law);縮小成比例(sm=12 / lg=20 之類)會讓 sm 幾乎無法精確拖曳。業界共識:track/thumb 是**單一視覺規格**,`size` 只控容器外高讓 Slider 並排對齊,內部透過 `flex items-center` 垂直置中
|
|
90
|
+
- **世界級對照**:Material 3 Slider(track 4dp thumb 20dp 固定)/ iOS UISlider(track 3pt thumb 28pt 固定)/ Ant Design Slider(track 4px thumb 14px 固定)/ Radix Slider(default 4px track)——全部 thumb / track 尺寸獨立於 form-size system <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 視覺規格(單一組,不隨 size 變)
|
|
95
|
+
|
|
96
|
+
| 元素 | 值 | Token |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| **Track** 厚度 | 4px(`h-1`) | — |
|
|
99
|
+
| **Track** 底色 rest | `bg-secondary` | `--secondary`(neutral-3,跟 Tag neutral / Badge low 同級「微淡可辨」)|
|
|
100
|
+
| **Track** 底色 disabled | `bg-muted` | `--muted`(neutral-2,disabled-like 退化)|
|
|
101
|
+
| **Range** 填滿色 rest | `bg-primary` | `--primary` |
|
|
102
|
+
| **Range** 填滿色 disabled | `bg-border`(neutral-5)| `--border` |
|
|
103
|
+
| **Thumb** 直徑 | 16px(`h-4 w-4`) | — |
|
|
104
|
+
| **Thumb** 底色(rest + disabled 不變)| `bg-surface`(白) | `--surface` |
|
|
105
|
+
| **Thumb** 邊框 rest | `border-2 border-primary`(= Range rest 同色)| `--primary` |
|
|
106
|
+
| **Thumb** 邊框 disabled | `border-border`(= Range disabled 同色)| `--border` |
|
|
107
|
+
| **Thumb** hover | border `primary-hover` + 陰影 `--elevation-100` | `--primary-hover` |
|
|
108
|
+
| **Thumb** active | 陰影 `--elevation-200` | — |
|
|
109
|
+
| **Focus ring** | `ring-2 ring-ring ring-offset-2 ring-offset-background` | `--ring` |
|
|
110
|
+
| **Disabled cursor** | `cursor-not-allowed` + hover 陰影關閉 | — |
|
|
111
|
+
|
|
112
|
+
### 為什麼 thumb 是**白底 + 邊框**,不是**實心 primary**
|
|
113
|
+
|
|
114
|
+
實心 primary thumb 會讓 thumb fill 與 range fill 使用同一 token → 失去位置辨識語意(特別是 range mode 兩個 thumb 與 primary range 共存時)。白底 + 邊框讓 thumb 與 range 視覺可區分——thumb 作為位置指示器,必須能從 range 中辨別。這是 Material 3 / iOS / Linear 的共同解法。
|
|
115
|
+
|
|
116
|
+
### 為什麼 Track 永遠是 `bg-muted`,不跟 state 變動
|
|
117
|
+
|
|
118
|
+
Track 是「凹槽底線」,它的視覺角色是「告訴使用者這條線是 slider 可滑動範圍」——這個語意不會因為 enabled / disabled 改變,所以**顏色也不該變**。當整個 slider 被 disable 時,Range 和 Thumb border 會降級(rest 的 primary → border),但 Track 的灰色凹槽身分始終不變。
|
|
119
|
+
|
|
120
|
+
為什麼用 `bg-muted` 而非其他 token?
|
|
121
|
+
- `--muted` 是 semantic token,屬於「shadcn Badge / skeleton 底色」家族,語意歸屬明確
|
|
122
|
+
- 是最淡的 subtle bg,符合「track 是背景凹槽,不是主角」的視覺層級
|
|
123
|
+
- **優先用 semantic token,不直接引用 primitive**——這是系統的基本原則
|
|
124
|
+
|
|
125
|
+
> **若覺得 `--muted` 在 white canvas 上太淡**,那是 `--muted` 本身的系統級議題,應該統一調整 `--muted` 的定義(影響 Badge / skeleton / Slider 一起),而不是在 Slider 裡偷偷用 primitive `--color-neutral-3` 繞過。
|
|
126
|
+
|
|
127
|
+
### Range 色 ↔ Thumb border 色的綁定規則
|
|
128
|
+
|
|
129
|
+
Range 填滿色和 Thumb border 色**永遠是同一個 token**:
|
|
130
|
+
|
|
131
|
+
| State | Range bg | Thumb border | 共享 token |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| Rest | `bg-primary` | `border-primary` | `--primary` |
|
|
134
|
+
| Disabled | `bg-border` | `border-border` | `--border` |
|
|
135
|
+
|
|
136
|
+
**為什麼綁在一起**:thumb 坐落在 range 的端點上,border 是 range 的視覺延續;兩者同色讓 thumb 作為「range 的終點標記」而非獨立元素,對齊物理滑桿 handle 屬於軌道一部分的 mental model(具體視覺呈現見 `.principles.stories.tsx` 的 ThumbBindingRule)。
|
|
137
|
+
|
|
138
|
+
**強制規則**:未來若要改 Range 的 disabled 色(例如加新 variant),必須同步改 Thumb border。不要讓兩者漂移。
|
|
139
|
+
|
|
140
|
+
### 為什麼 hover / active 用陰影不用色變
|
|
141
|
+
|
|
142
|
+
Slider 不是 button——它是「當前位置指示器」,底色不該動(動了會暗示是另一個狀態)。陰影(elevation)是世界級 slider 的標準 hover 語言:Material 3 的 state layer + elevation、iOS slider 的 scale + shadow、Linear 的 drop shadow。對齊 `elevation.spec.md` 的 `--elevation-100` / `--elevation-200`。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## API
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
<Slider
|
|
150
|
+
value={number[]} // controlled
|
|
151
|
+
defaultValue={number[]} // uncontrolled
|
|
152
|
+
onValueChange={(value) => void}
|
|
153
|
+
onValueCommit={(value) => void} // 放開滑鼠時才觸發
|
|
154
|
+
min={number} // 預設 0
|
|
155
|
+
max={number} // 預設 100
|
|
156
|
+
step={number} // 預設 1
|
|
157
|
+
size="sm" | "md" | "lg" // 預設 md(只影響容器外高)
|
|
158
|
+
disabled={boolean}
|
|
159
|
+
orientation="horizontal" // 不支援 vertical(用 TickSlider / 垂直尺若未來需要再擴充)
|
|
160
|
+
minStepsBetweenThumbs={number} // range mode 時兩個 thumb 的最小距離
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Range mode(雙 thumb)
|
|
165
|
+
|
|
166
|
+
Radix Slider 原生支援多 thumb——只要 `value` / `defaultValue` 傳長度 > 1 的 array,就自動渲染對應數量的 thumb,range(填滿段)落在最小和最大 thumb 之間。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
// 單值
|
|
170
|
+
<Slider defaultValue={[50]} />
|
|
171
|
+
|
|
172
|
+
// 範圍
|
|
173
|
+
<Slider defaultValue={[20, 80]} />
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 跟 Field 整合
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<Field>
|
|
180
|
+
<FieldLabel>音量</FieldLabel>
|
|
181
|
+
<Slider size="md" defaultValue={[60]} />
|
|
182
|
+
<FieldDescription>拖曳調整音量大小</FieldDescription>
|
|
183
|
+
</Field>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`size` prop 必須跟 Field 內其他 field 元件(Input / Select / NumberInput)傳同一個 size,才能對齊 field-height。
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## States
|
|
191
|
+
|
|
192
|
+
| State | 視覺 | 觸發 |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| Rest | track `bg-muted`,range `bg-primary`,thumb `bg-surface + border-primary` | 預設 |
|
|
195
|
+
| Hover(thumb) | 加 `--elevation-100` 陰影 | 滑鼠 hover 在 thumb 上 |
|
|
196
|
+
| Active(拖曳中) | 加 `--elevation-200` 陰影 | 按住拖曳 |
|
|
197
|
+
| Focus | `ring-2 ring-ring ring-offset-2` | 鍵盤 Tab 聚焦 |
|
|
198
|
+
| Disabled | 灰階降級:range `bg-border`、thumb `border-border`(= range 同 token)、thumb bg 保留 `bg-surface` 白底、`cursor-not-allowed`、hover 陰影關閉 | `disabled` prop 或 Field context disabled |
|
|
199
|
+
|
|
200
|
+
**Mode / readonly / dark mode / density** 詳見 `../Field/field-controls.spec.md`(Slider 作為 Field 家族整合時繼承其 canonical;semantic token 自動處理 dark mode,無需元件內特殊 handling)。
|
|
201
|
+
|
|
202
|
+
### Disabled 視覺階層
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
track (muted, n-2) < range = thumb border (border, n-5) < text (n-7+)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**三階**,不是四階。Range 和 Thumb border 刻意用同一個 token(見前面「Range 色 ↔ Thumb border 色的綁定規則」),不拆成兩階。
|
|
209
|
+
|
|
210
|
+
- **Track n-2**:最底的凹槽底線
|
|
211
|
+
- **Range + Thumb border n-5**:同層——thumb border 是 range 的連續視覺,兩者融為一體;thumb 的 fill 保持 surface 色,與 range fill 對比,位置由 range 的長度段決定
|
|
212
|
+
- **Text n-7+**:label / description 在所有視覺元件之上
|
|
213
|
+
|
|
214
|
+
### 為什麼 range disabled 不用 `--fg-disabled`
|
|
215
|
+
|
|
216
|
+
`--fg-disabled`(neutral-6)的語意是「**disabled 狀態下的文字前景色**」,它存在的目的是讓 disabled text 有足夠對比度可讀。把它拿來當 range 的 background 是**混用 fg token 當 bg 色**——在設計系統語意上是 smell,偶然 work 只是因為 neutral-6 剛好是我想要的深度。
|
|
217
|
+
|
|
218
|
+
正確選擇是 `--border`(neutral-5):
|
|
219
|
+
- **語意對**:`--border` 屬於 Border family,「視覺分隔 / 容器邊框」語意,跟 range 的「填充視覺指示器」角色接近
|
|
220
|
+
- **Family 對**:非文字的視覺元素,不借用 fg family
|
|
221
|
+
- **可同時作為 border-color**:`border-border` 在 Thumb 上直接用,Range bg 跟 Thumb border 可共享同一個 token(這是綁定規則的前提)
|
|
222
|
+
- **跟 fg-disabled 解耦**:未來若 `--fg-disabled` 被微調,Slider 不會被拖著一起變
|
|
223
|
+
|
|
224
|
+
詳細的 fg / bg token family 借用規則見 `tokens/color/color.spec.md` 的「fg token 不可當 bg 用」節。
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Disabled 策略
|
|
229
|
+
|
|
230
|
+
**Slider 用灰階不用 opacity**。這是系統內重要的判準,反覆確認後的結論——系統有兩個 disabled 處理派別,Slider 屬於**灰階派**(跟 Button / Checkbox 同家族)。判準比「多色彩 vs 單色彩」更精準,是:
|
|
231
|
+
|
|
232
|
+
### 判準:**顏色是否是 semantic state 的唯一載體?**
|
|
233
|
+
|
|
234
|
+
| 元件 | 顏色的角色 | State 載體 | Disabled 策略 |
|
|
235
|
+
|---|---|---|---|
|
|
236
|
+
| **Switch** | `bg-primary` vs `bg-border` 是 on/off 的**唯一視覺差異**(track 和 thumb 形狀在 on/off 之間完全相同,只有顏色變)| **顏色本身就是 state** | **`opacity-disabled`** — 必須保留色彩身分,否則灰階後失去狀態區辨 |
|
|
237
|
+
| **Checkbox** | 勾了有 checkmark,沒勾沒 checkmark——**形狀**決定 state,顏色只是美學 | **形狀(checkmark)** | **灰階 swap**(`bg-disabled`)— 灰色框裡的 checkmark 仍清楚可辨 |
|
|
238
|
+
| **Button** | Primary 色是品牌美學,不是 state | — | **灰階 swap** |
|
|
239
|
+
| **Slider** | Range 藍色是「已選長度」的美學視覺,**位置 + 長度是 state**,顏色只是裝飾 | **位置(thumb)+ 長度(range 佔比)** | **灰階 swap** — 灰色 range 跟灰色 thumb 的位置/長度仍然完全可辨 |
|
|
240
|
+
|
|
241
|
+
### Slider 的完整論證
|
|
242
|
+
|
|
243
|
+
使用者看到 disabled slider 需要理解兩件事:
|
|
244
|
+
1. **Thumb 在 track 的哪個位置**(例如「60% 處」)
|
|
245
|
+
2. **Range 的填滿長度**(例如「20% 到 80%」)
|
|
246
|
+
|
|
247
|
+
這兩個資訊**完全不依賴顏色**:
|
|
248
|
+
- 灰階 thumb 在灰階 track 上,x 座標位置跟 primary 版本一模一樣
|
|
249
|
+
- 灰階填滿段的長度跟 primary 版本一模一樣
|
|
250
|
+
|
|
251
|
+
**失去藍色沒有任何資訊損失**。Slider 跟 Checkbox 同類——semantic state 由形狀/位置承載,顏色是純裝飾。
|
|
252
|
+
|
|
253
|
+
### 對照 Switch 的差異
|
|
254
|
+
|
|
255
|
+
Switch 是**唯一需要 opacity 的特例**,因為它的 on/off 沒有任何形狀差異:
|
|
256
|
+
- On:track + thumb
|
|
257
|
+
- Off:track + thumb(同樣形狀,thumb 在不同位置)
|
|
258
|
+
|
|
259
|
+
唯一的 state 視覺載體是 track 顏色(primary vs border)。灰階 swap 會讓 on/off 視覺無法區分——必須靠 opacity 保留顏色。
|
|
260
|
+
|
|
261
|
+
**這個 rationale 不適用 Slider**,因為 Slider 的 state 載體不是顏色。
|
|
262
|
+
|
|
263
|
+
### 為什麼 shadcn / Material 3 用 opacity 仍然不是理由
|
|
264
|
+
|
|
265
|
+
- **shadcn 的 Slider 用 `opacity-50`**:shadcn 追求「最短 code path」,不是「設計嚴謹」,它對所有 disabled 元件都 lazy-apply opacity。這是實作偷懶,不是 design decision。
|
|
266
|
+
- **Material 3 的 38% opacity 全局規則**:M3 是為 Android 生態系設計的,opacity-based disabled 能跟 Android 原生控件的視覺一致。我們的系統是 web,不受此約束,且 Button / Checkbox / Input 已經選了灰階路線,Slider 跟進對齊才是 system consistency 的正確解。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
267
|
+
|
|
268
|
+
### 常見錯誤(避免)
|
|
269
|
+
|
|
270
|
+
**不要把 thumb 的 disabled bg 改成 `bg-muted`**——`--muted` 和 `--bg-disabled` 在這個系統都等於 `var(--color-neutral-2)`,同一個顏色。Thumb `bg-muted` 會跟 track `bg-muted` 完全融色,只剩 border 可見,失去 thumb 形狀辨識(真實踩過的 bug)。**保留 `bg-surface` 白底**,只改 border 顏色即可達成降級。
|
|
271
|
+
|
|
272
|
+
**不要同時套 opacity + 灰階 swap**——兩個策略互斥,同時用會導致「灰階 swap 後再打 opacity 一層」,視覺雙重降級,整個 slider 褪色過度。選一條路走到底。
|
|
273
|
+
|
|
274
|
+
### 無 Error state
|
|
275
|
+
|
|
276
|
+
Slider 沒有獨立的 error 視覺——拖曳選值本身不太會「無效」。如果業務邏輯需要限制範圍,用 `min` / `max` 直接限制使用者能拖到的範圍,不要讓他拖到再報錯。
|
|
277
|
+
|
|
278
|
+
### 無 readonly mode
|
|
279
|
+
|
|
280
|
+
Slider 的 `readonly` 等同於 `disabled`——一個不能操作的 slider 本質上就是 disabled。不同於 Input 有「可以 focus 但不能改」的 readonly 差異,slider 的 focus 除了拖曳沒有其他行為。若要顯示「歷史值」,用純文字或另一個 display 元件。
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 鍵盤操作(Radix 原生,免手工)
|
|
285
|
+
|
|
286
|
+
- **Left / Right Arrow**:- / + `step`
|
|
287
|
+
- **Up / Down Arrow**:+ / - `step`(vertical-inverted 時相反)
|
|
288
|
+
- **PageUp / PageDown**:± `step × 10`(Radix 預設)
|
|
289
|
+
- **Home / End**:跳到 `min` / `max`
|
|
290
|
+
- **Tab**:在多個 thumb 間切換焦點(range mode)
|
|
291
|
+
|
|
292
|
+
無需額外實作,Radix Slider primitive 已經全部處理。
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Do / Don't
|
|
297
|
+
|
|
298
|
+
✅ **Do**
|
|
299
|
+
- 用 Slider 選「連續」或「密集離散」的數值
|
|
300
|
+
- Range mode 用於範圍選取(價格、日期、分數)
|
|
301
|
+
- 搭配顯示值(thumb tooltip 或旁邊的 NumberInput 同步)讓使用者知道精確數字
|
|
302
|
+
- 用 Field 包裝時傳跟 siblings 同一個 `size`
|
|
303
|
+
|
|
304
|
+
❌ **Don't**
|
|
305
|
+
- 用 Slider 選離散少量選項(用 SegmentedControl / RadioGroup)
|
|
306
|
+
- 用 Slider 表達「多/少」的 boolean(用 Switch)
|
|
307
|
+
- 硬寫 thumb / track 尺寸——單一視覺規格,跟 size 無關
|
|
308
|
+
- 用實心 primary thumb(thumb fill 與 range fill 使用同一 token → 失去位置辨識語意)
|
|
309
|
+
- thumb hover-fill 切換色(破壞「這是位置指示器」的 mental model,hover 應透過陰影表達而非色變)
|
|
310
|
+
- 給 Slider 加 error 紅色——用 min/max 限制輸入範圍,不讓錯誤發生
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 為何無 Inspector
|
|
315
|
+
|
|
316
|
+
Slider 決策維度是 `size`(容器外高)× `range mode`(single / range)× track / range / thumb 的色彩綁定規則——已由 `SizeMatrix` / `StateBehavior` / `ColorMatrix` / 元件特有 `ColorBindingRule`(range ↔ thumb border 綁定規則) / `KeyboardMatrix`(Radix 原生鍵盤) 五張 story 完整覆蓋。
|
|
317
|
+
|
|
318
|
+
互動 Inspector 拉動 thumb 無法呈現「range 色和 thumb border 永遠同 token」這類設計綁定規則——這是 side-by-side 對照題,不是單值拉動題。鍵盤互動已由 `KeyboardMatrix` 以對照表呈現比 Inspector 試玩更完整。
|
|
319
|
+
|
|
320
|
+
對應 anatomy story:保留 `Overview` + `ColorMatrix` + `SizeMatrix` + `StateBehavior` + 元件特有 `ColorBindingRule` + `KeyboardMatrix`。
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 相關
|
|
325
|
+
|
|
326
|
+
- `../NumberInput/number-input.spec.md` — 精確數字輸入的對應元件
|
|
327
|
+
- `../SegmentedControl/segmented-control.spec.md` — 離散少量選項的對應元件
|
|
328
|
+
- `../../tokens/uiSize/uiSize.spec.md` — `field-height-*` token family
|
|
329
|
+
- `../../tokens/elevation/elevation.spec.md` — Elevation hover / active 語意
|
|
330
|
+
- `../../tokens/color/color.spec.md` — Primary / muted / fg-disabled token
|
|
331
|
+
- `../Field/field.spec.md` — Field 容器整合規則
|
|
332
|
+
- Radix Slider primitive API — `@radix-ui/react-slider`
|
|
333
|
+
|
|
334
|
+
## A11y 預設
|
|
335
|
+
|
|
336
|
+
**ARIA / Pattern**:繼承 Radix `slider` primitive a11y 預設(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/slider#accessibility)。
|
|
337
|
+
|
|
338
|
+
**Keyboard 行為**:
|
|
339
|
+
|
|
340
|
+
- Tab — focus thumb
|
|
341
|
+
- ←/→ — 微調
|
|
342
|
+
- Home/End — min/max
|
|
343
|
+
- PageUp/Down — 大步階
|
|
344
|
+
|
|
345
|
+
**Focus**:Radix primitive 自管 focus trap / restoration / visible ring(`outline: 2px solid var(--ring)` per design-system focus-visible canonical)。
|
|
346
|
+
|
|
347
|
+
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
348
|
+
|
|
349
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
350
|
+
|
|
351
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
352
|
+
|
|
353
|
+
- `switch.spec.md`
|