@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,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: Empty
|
|
3
|
+
family: composite
|
|
4
|
+
variants: {}
|
|
5
|
+
sizes: {}
|
|
6
|
+
traits:
|
|
7
|
+
- isStructural
|
|
8
|
+
benchmark:
|
|
9
|
+
- Ant Design Empty: github.com/ant-design/ant-design/tree/master/components/empty
|
|
10
|
+
- Polaris EmptyState: github.com/Shopify/polaris/tree/main/polaris-react/src/components/EmptyState
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
14
|
+
|
|
15
|
+
# Empty 設計原則
|
|
16
|
+
|
|
17
|
+
**空狀態視覺元件**——容器內沒有內容時的居中提示。Table、SelectMenu、Combobox、Page section 等所有需要空狀態的元件統一消費。
|
|
18
|
+
|
|
19
|
+
## 定位
|
|
20
|
+
|
|
21
|
+
一個 **layout pattern**(不是 field-level 元件)。它排列 icon / title / description / action 成居中垂直堆疊,間距走 layout-space token(density-aware)。
|
|
22
|
+
|
|
23
|
+
預設只有 description——icon / title / action 全部可選。
|
|
24
|
+
|
|
25
|
+
**Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 何時用
|
|
30
|
+
|
|
31
|
+
- **Table / list / grid 空狀態**:DataTable 查無資料、搜尋無結果
|
|
32
|
+
- **SelectMenu / Combobox 下拉空**:「無選項」「找不到符合的項目」
|
|
33
|
+
- **Page section 無內容**:dashboard widget 暫無資料、設定頁未建立任何項目
|
|
34
|
+
- **初次引導**:讓使用者首次使用時知道「這裡會放什麼」+ 有 CTA 建立
|
|
35
|
+
|
|
36
|
+
## 何時不用
|
|
37
|
+
|
|
38
|
+
| 場景 | 改用 | 原因 |
|
|
39
|
+
|------|------|------|
|
|
40
|
+
| Loading 中(資料還沒來) | `Skeleton` / `CircularProgress` | Empty 是「確定沒有」,Loading 是「還沒確定」 |
|
|
41
|
+
| 錯誤 / 失敗狀態 | `Alert` + 重試按鈕 | Error 需要明確告知「發生什麼問題」+ 解決途徑,Empty 是中性提示 |
|
|
42
|
+
| 整頁級別的 404 / 無權限 | 專屬錯誤頁面 | Empty 是容器內提示,整頁錯誤需要完整頁面佈局 |
|
|
43
|
+
| Disabled 狀態 | 禁用元件本身 | Empty 是「沒東西」,disabled 是「不能操作」 |
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
[Avatar 48px neutral + icon] ← 可選
|
|
47
|
+
gap = --layout-space-tight
|
|
48
|
+
[Title 16px font-medium centered] ← 可選
|
|
49
|
+
--item-gap-label-desc-reading-lg (2px)
|
|
50
|
+
[Description 14px fg-secondary centered]
|
|
51
|
+
w-full (no max-width)
|
|
52
|
+
gap = --layout-space-loose
|
|
53
|
+
[Action Button] ← 可選
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Slots
|
|
57
|
+
|
|
58
|
+
- **Icon**(`icon?: LucideIcon | ReactElement`,預設無):LucideIcon 會自動包 48px neutral Avatar + 28px icon;ReactElement 原樣渲染(consumer 可自帶 Illustration、ColorAvatar、CircularProgress)
|
|
59
|
+
- **Title**(`title?: string`,預設無):主要標題,foreground + medium 字重,居中
|
|
60
|
+
- **Description**(`description?: string`,預設無 — 但是唯一必有的 slot):說明文字,次要色、居中
|
|
61
|
+
- **Action**(`action?: ReactNode`,預設無):CTA Button 或任何操作,居中
|
|
62
|
+
|
|
63
|
+
## 間距
|
|
64
|
+
|
|
65
|
+
固定值,不隨 density 變(Empty 是展示性元件,不是工作區域元件——展示性文字不跟 field-height tier 連動):
|
|
66
|
+
|
|
67
|
+
- **Icon → Title/Desc**:視覺 → 文字過渡需充足呼吸空間(48px icon 尺寸不宜貼近文字)
|
|
68
|
+
- **Title → Description**:緊密配對(同資訊塊,對齊 item-layout canonical 的 label ↔ desc gap)
|
|
69
|
+
- **Description → Action**:資訊 → 行動的視覺暫停,引導使用者注意 CTA
|
|
70
|
+
|
|
71
|
+
Outer padding 由 **consumer 容器** 決定(Table 空狀態需較大留白、SelectMenu dropdown 較緊湊、Page-level 最寬鬆)。
|
|
72
|
+
|
|
73
|
+
## Typography
|
|
74
|
+
|
|
75
|
+
- **Title**:body-lg + medium 字重 / foreground 色(主要閱讀重量)
|
|
76
|
+
- **Description**:body tier / **`fg-muted` placeholder 等級色**(跟 input placeholder 同色,提示「這裡暫時沒內容」)
|
|
77
|
+
|
|
78
|
+
完整 slot / gap / typography 的 class 與 px 對照見 anatomy `Overview`(Slot 與 Spacing)+ `SlotCombinations`(Slot 間距規則)stories。
|
|
79
|
+
|
|
80
|
+
## 文字不限寬
|
|
81
|
+
|
|
82
|
+
Description **不加 max-width**。文字撐滿容器,由容器 padding 控制行寬。文案設計者自己規劃換行(文案長度 = 設計的一部分),Empty 不該強制截斷。
|
|
83
|
+
|
|
84
|
+
## 垂直定位(Consumer 容器的責任)
|
|
85
|
+
|
|
86
|
+
Empty 只管**水平居中**。垂直定位由 consumer 的容器決定:
|
|
87
|
+
|
|
88
|
+
| 容器類型 | 垂直定位 | 做法 |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| **有框**(Table / Dialog / Card,有明確 border 或 shadow 包圍) | **垂直置中** | 容器 `flex items-center justify-center min-h-[...]` |
|
|
91
|
+
| **無框**(Page section,沒有外框線) | **頂部對齊 + generous padding** | 容器 `py-[calc(var(--layout-space-bottom)*2)]` |
|
|
92
|
+
|
|
93
|
+
### 為什麼有框置中、無框不置中
|
|
94
|
+
|
|
95
|
+
有框容器有明確的視覺邊界——使用者知道「這個框裡面是空的」。居中把 Empty 放在框的視覺重心,安定。
|
|
96
|
+
|
|
97
|
+
無框容器沒有邊界——如果居中,Empty 會脫離頁面視覺中心,使用者不知道空的範圍有多大。頂部對齊 + `calc(var(--layout-space-bottom) * 2)` padding 讓 Empty 有固定位置,用留白空間本身創造「這裡是空的」的視覺重量,取代框線的作用。
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## A11y 預設
|
|
102
|
+
|
|
103
|
+
Empty 是 **non-interactive layout primitive**——本身無 ARIA role(讓 consumer 容器決定 region semantics)。但 consumer 應遵循以下慣例:
|
|
104
|
+
|
|
105
|
+
| 場景 | Consumer 容器應加 | 為什麼 |
|
|
106
|
+
|------|----------------|------|
|
|
107
|
+
| Table / List 空狀態 | `<table aria-describedby={emptyId}>` 或在容器加 `aria-live="polite"` | screen reader 在資料載入完成時主動通知「無資料」(對齊 Polaris EmptyState pattern) | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
108
|
+
| Search / Filter 無結果 | container `aria-live="polite"` + 文案明確指向搜尋詞(「找不到符合『XXX』的結果」)| 對齊 Material `<NoOptions>` + Atlassian Empty Search idiom — 變動結果需 live region | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
109
|
+
| Page section 暫無內容 | `<section aria-labelledby={titleId}>` + `<h2>` 包 title slot | 對齊 WCAG 2.1 SC 2.4.6 標題明確語意 |
|
|
110
|
+
| 初次引導(有 CTA) | Action Button 自帶 a11y;無需 Empty 層額外 ARIA | CTA 是真實互動 element,自己的 a11y 足夠 |
|
|
111
|
+
|
|
112
|
+
**Title slot heading level**:Empty 不渲染 heading tag(`<h1>` / `<h2>`),只 `<div>` + 視覺 typography。Consumer 若需 heading semantic,在外層自包 `<h2>{title}</h2>` + 不傳 Empty 的 title prop(避免重複)。
|
|
113
|
+
|
|
114
|
+
**Icon slot**:LucideIcon 自動渲染 `aria-hidden="true"`(decorative);ReactElement(自帶 Avatar / Illustration)由 consumer 控制 `aria-hidden` / `alt`(若是 `<img>` 必傳 `alt=""` 表示 decorative)。
|
|
115
|
+
|
|
116
|
+
**Description 不需 live announcement**:Empty 本身是「靜態空狀態提示」(進入時就空),不是「動態變化結果」。動態變化(filter / search 結果切換)由 consumer 在容器層加 `aria-live`,不在 Empty 內。
|
|
117
|
+
|
|
118
|
+
世界級對照:
|
|
119
|
+
- **Polaris** `<EmptyState>`:容器層 `aria-labelledby` + heading 由 prop 控制 level(consumer 決定 `<h2>` / `<h3>`)
|
|
120
|
+
- **Material** `<NoOptions>`(Autocomplete 內):容器自帶 `role="listbox"` + `aria-live="polite"` 通知無結果
|
|
121
|
+
- **Carbon** `<EmptyState>`:無自帶 ARIA,文檔指引 consumer 在父容器設 `aria-describedby`
|
|
122
|
+
|
|
123
|
+
本 DS 對齊 Carbon「primitive 不自帶 ARIA,consumer 控制」哲學——避免 Empty 強加 role 跟 consumer 容器衝突。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 消費範例
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// Table 空狀態(最簡)
|
|
131
|
+
<Empty description="沒有資料" />
|
|
132
|
+
|
|
133
|
+
// SelectMenu 無結果
|
|
134
|
+
<Empty icon={SearchX} description="找不到符合的結果" />
|
|
135
|
+
|
|
136
|
+
// Page 首次引導(完整 slots)
|
|
137
|
+
<Empty
|
|
138
|
+
icon={FolderOpen}
|
|
139
|
+
title="還沒有專案"
|
|
140
|
+
description="建立第一個專案來開始使用"
|
|
141
|
+
action={<Button>建立專案</Button>}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
// 自訂色彩(success result)
|
|
145
|
+
<Empty
|
|
146
|
+
icon={<Avatar icon={CheckCircle} size={48} color="green" />}
|
|
147
|
+
title="已成功送出"
|
|
148
|
+
description="我們會盡快處理"
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
// 自訂圖片
|
|
152
|
+
<Empty
|
|
153
|
+
icon={<img src="/empty-illustration.svg" className="w-12 h-12" alt="" />}
|
|
154
|
+
description="尚無內容"
|
|
155
|
+
/>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 現有消費者改寫
|
|
159
|
+
|
|
160
|
+
| 元件 | 現況 | 改為 |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| DataTable | inline `<div>` 硬寫 className | `<Empty description={emptyState} className="py-12" />` |
|
|
163
|
+
| SelectMenu | — | `<Empty description="無選項" className="py-6" />` |
|
|
164
|
+
| Combobox | — | `<Empty description="找不到結果" className="py-6" />` |
|
|
165
|
+
|
|
166
|
+
## 禁止事項
|
|
167
|
+
|
|
168
|
+
- ❌ 把 Empty 拿來顯示 loading state(無 description 又無 spinner)— Empty 是「確定沒有」語意,loading 用 `<Skeleton>` / `<CircularProgress>` 或 `<Empty icon={<CircularProgress />}/>` compose
|
|
169
|
+
- ❌ 把 Empty 拿來顯示 error state(只有 description)— error 需明確 action(重試 / 報告 / 聯絡支援),用 `<Alert>` + 重試 button
|
|
170
|
+
- ❌ Empty title / description 文案太抽象(「Nothing here」「No data」)— 應描述「缺什麼資料」+「為什麼空」+「下一步動作」(對齊 Polaris EmptyState / Carbon Empty State copy guideline) <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
171
|
+
- ❌ Action button 用 destructive variant — Empty 是引導 onboarding 心境,destructive 視覺敵意衝突
|
|
172
|
+
- ❌ 整頁 Empty 但無 action — user 困惑「我該做什麼」;若該頁本質無 action(等待後台 invite),改用 Alert/Notice 解釋
|
|
173
|
+
|
|
174
|
+
## 為何無 Inspector / ColorMatrix / SizeMatrix / StateBehavior
|
|
175
|
+
|
|
176
|
+
Empty 是 **pure layout primitive**(排列 icon / title / description / action 成居中垂直堆疊),不是互動元件,也不是 variant-driven 元件:
|
|
177
|
+
|
|
178
|
+
- **無 Inspector**:Empty 的「關鍵決策」是 slot 組合(description only → full),已在 `SlotCombinations` story 呈現四種組合對照(最簡 → 輕引導 → 中引導 → full)。互動切換式 Inspector 不會比 slot composition 對照更有教學價值——consumer 需要的是「這四種場景怎麼選」。
|
|
179
|
+
- **無 ColorMatrix**:Empty 自身不帶任何色彩,bg transparent,text color 全部走 semantic token(`text-foreground` / `text-fg-muted`)。Avatar icon 的色彩由 consumer 透過 `<Avatar color="...">` 決定,非 Empty 層級 variant。
|
|
180
|
+
- **無 SizeMatrix**:Empty 無 `size` prop,垂直 padding 由 consumer 容器決定(Table `py-12` / SelectMenu `py-6` / Page `py-16`),固定間距不隨 density 變(展示性元件,見本 spec「間距」段)。
|
|
181
|
+
- **無 StateBehavior**:Empty 是非互動展示元件,無 hover / focus / active / selected / disabled。CTA button 的互動狀態屬 Button 層級,不屬 Empty。
|
|
182
|
+
|
|
183
|
+
對應 anatomy story:保留 `Overview` + 元件特有 `ScenarioMatrix`(常見業務場景) + 元件特有 `SlotCombinations`(slot 組合對照)。
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 相關
|
|
188
|
+
|
|
189
|
+
- `../Avatar/avatar.tsx` — Icon 渲染實作
|
|
190
|
+
- `../CircularProgress/circular-progress.spec.md` — Loading 狀態(非「空」而是「還沒來」;全頁 loading 可 `<Empty icon={<CircularProgress size={48}/>}/>` compose)
|
|
191
|
+
- `../Alert/alert.spec.md` — Error 狀態(非中性空,是需處理的問題)
|
|
192
|
+
- `../FileUpload/file-upload.spec.md` — **本元件 consumer**:FileUpload 預設 children 直接渲染 `<Empty icon={Upload} title description />`,共用 icon+title+desc SSOT
|
|
193
|
+
- `../../tokens/typography/typography.spec.md` — Typography tier
|
|
194
|
+
- `../../tokens/layoutSpace/layoutSpace.spec.md` — Layout-space token
|
|
195
|
+
- `../../patterns/element-anatomy/item-anatomy.spec.md` — label → desc gap(token `--item-gap-label-desc-reading-lg` / primitive `<ItemContent>`)
|
|
196
|
+
|
|
197
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
198
|
+
|
|
199
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
200
|
+
|
|
201
|
+
- `carousel.spec.md`
|
|
202
|
+
- `file-viewer.spec.md`
|
|
203
|
+
- `select-menu.spec.md`
|
|
204
|
+
- `skeleton.spec.md`
|
|
205
|
+
- `tree-view.spec.md`
|
|
206
|
+
|
|
207
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
208
|
+
|
|
209
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
210
|
+
|
|
211
|
+
- `combobox.spec.md`
|
|
212
|
+
- `command.spec.md`
|
|
213
|
+
- `select.spec.md`
|
|
214
|
+
- `sheet.spec.md`
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: FieldControls
|
|
3
|
+
traits:
|
|
4
|
+
- hasVariants
|
|
5
|
+
- hasSizes
|
|
6
|
+
- hasInteractiveStates
|
|
7
|
+
- isStructural
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
|
|
11
|
+
|
|
12
|
+
# Field Controls 設計原則
|
|
13
|
+
|
|
14
|
+
> **Foundational SSOT rationale**(cap 800,2026-04-25 approved):
|
|
15
|
+
> Family 4 (Field Control Layout) SSOT owner。Input / NumberInput / DatePicker / Select / Combobox / LinkInput / TimePicker / Textarea / PeoplePicker 等皆消費 `fieldWrapperStyles` / edit-readonly-disabled 三態 mode architecture / endAction 處理 / Display 子元件 pattern / Inline Action canonical(後者也 cascade 到 Sidebar / TreeView / DropdownMenu)。scope 本質 > 單一元件。
|
|
16
|
+
|
|
17
|
+
> **注意**:此文件是 Field Controls(Input / NumberInput / DatePicker / Select / Combobox / LinkInput / PeoplePicker 等)**共用**的設計原則,與 `Field/field.spec.md`(表單 Layout 容器)**不是同一個東西**。
|
|
18
|
+
>
|
|
19
|
+
> - **Field Controls**(本文件):具體的資料型別輸入元件,內部含 edit/readonly/disabled 三態 + 格式化 + DataTable Display 共用
|
|
20
|
+
> - **Field**(`Field/field.spec.md`):shadcn 風格的表單 Layout 容器(label + description + error),wrap 上述 Field Controls 元件
|
|
21
|
+
|
|
22
|
+
**Layout Family**:本 spec 是 CLAUDE.md 4-Family Model **Family 4(Field Control Layout)的 SSOT**。結構 `fieldWrapperStyles + [startIcon?] [<editable content>] [endAction?]`,**視覺對齊 Family 1(Menu item layout)**——Select trigger 的高度 / 字體 / icon size 必須跟其 SelectMenu options 連續一致。Consumers: Input(canonical), NumberInput, DatePicker, Select, Combobox, LinkInput, PeoplePicker。
|
|
23
|
+
|
|
24
|
+
## 定位
|
|
25
|
+
|
|
26
|
+
Field Controls 是資料輸入與顯示的基礎元件。每種資料類型(text、number、date、select...)對應一個元件,同時服務 Form 和 DataTable:
|
|
27
|
+
|
|
28
|
+
- **Form**:用 Field Controls 的 edit / readonly / disabled 三態(在 Field 容器內)
|
|
29
|
+
- **DataTable**:用 Field Controls 的 Display 子元件渲染 cell
|
|
30
|
+
|
|
31
|
+
每個元件擁有該類型的格式化邏輯(唯一真實來源),Form 和 DataTable 消費同一份 code。
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 架構
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Field/
|
|
39
|
+
├── field.tsx ← Field 佈局容器(label + control + desc + error)
|
|
40
|
+
├── field.spec.md ← Field 佈局容器設計原則
|
|
41
|
+
├── field-controls.spec.md ← 本文件
|
|
42
|
+
├── field-types.ts ← FieldMode、InlineActionConfig 共用型別
|
|
43
|
+
├── field-wrapper.tsx ← 共用 wrapper 樣式、bareInputStyles、EMPTY_DISPLAY
|
|
44
|
+
├── Input/ ← Input(含 mode="display")
|
|
45
|
+
├── NumberInput/ ← NumberInput(含 mode="display" + formatNumber)
|
|
46
|
+
├── DatePicker/ ← DatePicker(含 mode="display" + formatDate)
|
|
47
|
+
├── Select/ ← Select(含 mode="display")
|
|
48
|
+
├── Combobox/ ← Combobox(含 mode="display")
|
|
49
|
+
├── LinkInput/ ← LinkInput(含 mode="display")
|
|
50
|
+
├── PeoplePicker/ ← PeoplePicker + PersonDisplay(cross-component primitive)
|
|
51
|
+
└── Textarea/ ← Textarea(多行)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
每個元件統一以 `mode` prop 切換樣態:
|
|
55
|
+
1. **edit / readonly / disabled** — Form 用,可編輯 / 鎖定 / 不可用
|
|
56
|
+
2. **`mode="display"`** — DataTable cell 用,純格式化顯示(取代過往的 `XxxDisplay` 子元件)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Mode — 三種模式
|
|
61
|
+
|
|
62
|
+
| Mode | 底色 | 邊框 | 文字色 | 用途 |
|
|
63
|
+
|------|------|------|--------|------|
|
|
64
|
+
| `edit` | surface | border(hover 深一階、focus primary) | foreground | 表單可編輯欄位 |
|
|
65
|
+
| `readonly` | neutral-2 | 無 | foreground | 表單中不可編輯但可見的欄位 |
|
|
66
|
+
| `disabled` | neutral-2 | 無 | fg-disabled | 表單中被停用的欄位 |
|
|
67
|
+
|
|
68
|
+
三種模式共用同一個 wrapper 結構(`fieldWrapperStyles`),只有底色、邊框、文字色不同。
|
|
69
|
+
|
|
70
|
+
### Loading state(async 驗證 / debounce fetch 中)
|
|
71
|
+
|
|
72
|
+
Loading **不是第四個 mode**,是 `edit` mode 的子狀態,語義 = **editable 仍可輸入**(UX「邊改邊讀」:debounce search / async validation 場景中 user 常需要繼續打字修正,凍結輸入反而破壞心流)。
|
|
73
|
+
|
|
74
|
+
**世界級流派選擇**(editable 派 vs readonly 派):
|
|
75
|
+
|
|
76
|
+
| DS | Loading input 做法 | 流派 |
|
|
77
|
+
|----|-------------------|------|
|
|
78
|
+
| Ant Input.Search | **input 仍 editable**,suffix spinner;submit 另鎖 | editable |
|
|
79
|
+
| Material TextField | readonly + suffix adornment loader | readonly |
|
|
80
|
+
| Polaris TextField | readonly + helpText 提示 | readonly |
|
|
81
|
+
| Carbon TextInput | readonly + inline Loading | readonly |
|
|
82
|
+
| Atlassian TextField | disabled | disabled(少數派) |
|
|
83
|
+
| Apple HIG UITextField | visual overlay only,不阻礙輸入 | editable |
|
|
84
|
+
|
|
85
|
+
**本 DS 採 editable 派**(Ant / Apple HIG):
|
|
86
|
+
- **UX 理由**:debounce 搜尋場景,user 邊打邊看建議,凍結一格會卡節奏;async validation 若第一次失敗,user 該能立即改,不是等 spinner 完才能動
|
|
87
|
+
- **對照 readonly 派**:readonly 派適合「提交後驗證」的場景(e.g. 表單 submit → 驗證),本 DS 的 `loading` prop 用在 debounce / inline validation,editable 更 fit
|
|
88
|
+
|
|
89
|
+
**實作 canonical(Input / NumberInput / Combobox 等 Field 元件)**:
|
|
90
|
+
- API:`loading?: boolean` prop
|
|
91
|
+
- 內部:`loading=true` → wrapper `aria-busy="true"` + **endAction slot 自動塞 `<CircularProgress size={iconSize}/>`**(與 `endAction` prop 互斥,loading 優先)
|
|
92
|
+
- input **不進 readonly / disabled**,保持可編輯
|
|
93
|
+
- CircularProgress 尺寸:程式化 `iconSize`(sm/md=16, lg=20),消費者不用再傳
|
|
94
|
+
- CircularProgress 顏色:走預設 `text-primary`(表達「正在處理,請注意」)
|
|
95
|
+
- startIcon(Search 等語義 icon)**不受 loading 影響**,保留原位置
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
// 世界級 canonical:search field 在 loading 中,user 仍可修改關鍵字
|
|
99
|
+
<Input startIcon={Search} loading placeholder="搜尋..." />
|
|
100
|
+
// → search icon 在 prefix(保留語義身分)
|
|
101
|
+
// → CircularProgress 在 endAction 位置(暫時狀態)
|
|
102
|
+
// → input editable + aria-busy,user 可繼續輸入 / 修改
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
❌ 禁止手刻路線:
|
|
106
|
+
```tsx
|
|
107
|
+
// 絕對不寫
|
|
108
|
+
<div className="relative">
|
|
109
|
+
<Input startIcon={Search} />
|
|
110
|
+
<div className="absolute right-3 top-1/2 -translate-y-1/2">
|
|
111
|
+
<CircularProgress size={16} />
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
```
|
|
115
|
+
手刻 absolute 對齊容易跑掉(Field 元件內 loading 指示與既有 endAction 垂直對齊不一致)。一律用 `loading` prop。
|
|
116
|
+
|
|
117
|
+
### disabled 的停用原因
|
|
118
|
+
|
|
119
|
+
停用原因由外部承擔,不在 input 內放 info icon:
|
|
120
|
+
- **Tooltip**:包住整個 Field 元件(wrapper `<div>` 不是 disabled 元素,可正常接收 hover)
|
|
121
|
+
- **Form help text**:在 input 下方說明(Form 層負責)
|
|
122
|
+
|
|
123
|
+
### 原生屬性覆蓋
|
|
124
|
+
|
|
125
|
+
`disabled` 和 `readOnly` 原生 HTML 屬性會自動覆蓋 `mode` prop,避免衝突。
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Error — 正交於 mode
|
|
130
|
+
|
|
131
|
+
Error 是 boolean prop,獨立於 mode。只在 `edit` 模式下有視覺效果(`border-error`)。
|
|
132
|
+
|
|
133
|
+
- Error 視覺在 Field(input)層級:紅色邊框 + `aria-invalid`
|
|
134
|
+
- Error 訊息在 Form 層級:help text 顯示在 input 下方
|
|
135
|
+
- Field 不在尾部放狀態 icon(如 ⚠️)——邊框顏色已經傳達了 error 狀態
|
|
136
|
+
|
|
137
|
+
Form wrapper 可透過 context 注入 `error` prop,消費者不需要在每個 Field 上手動傳。
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Size — 與 Button 對齊
|
|
142
|
+
|
|
143
|
+
| Size | 高度 token | Tailwind | 字體 |
|
|
144
|
+
|------|-----------|----------|------|
|
|
145
|
+
| `sm` | `--field-height-sm` | `h-field-sm` | text-body |
|
|
146
|
+
| `md` | `--field-height-md` | `h-field-md` | text-body |
|
|
147
|
+
| `lg` | `--field-height-lg` | `h-field-lg` | text-body-lg |
|
|
148
|
+
|
|
149
|
+
高度使用 `--field-height-*` semantic token(rem 單位),與 Button 共用同一組 token,同 size 的 Field 和 Button 並排時高度一致。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Focus 行為
|
|
154
|
+
|
|
155
|
+
`<input>` 元素在點擊和鍵盤 Tab 時都觸發 `:focus-visible`(瀏覽器規範:文字輸入永遠 focus-visible),CSS 無法區分。
|
|
156
|
+
|
|
157
|
+
統一使用 `border-primary`(1px),不加 ring、不加粗。
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 點擊與游標原則
|
|
162
|
+
|
|
163
|
+
### 點擊穿透
|
|
164
|
+
|
|
165
|
+
Field 內部所有不會觸發獨立 action 的元素必須 `pointer-events-none`,讓點擊穿透到底層的 input/select,確保使用者點擊 Field 內任何位置都能 focus/activate。
|
|
166
|
+
|
|
167
|
+
穿透(`pointer-events-none`):startIcon、ChevronDown 下拉箭頭、tag 文字區域。
|
|
168
|
+
不穿透:endAction(clear、toggle password)、tag dismiss button——這些有自己的 action。
|
|
169
|
+
|
|
170
|
+
### 游標指引
|
|
171
|
+
|
|
172
|
+
可點擊的元素必須有明確的 cursor 變化:
|
|
173
|
+
- endAction、dismiss button → `cursor-pointer`
|
|
174
|
+
- input / select → `cursor-text` / `cursor-pointer`(原生行為)
|
|
175
|
+
- disabled → `cursor-not-allowed`
|
|
176
|
+
|
|
177
|
+
## Icon 色彩原則
|
|
178
|
+
|
|
179
|
+
跨元件統一規則(詳見 `item-anatomy.spec.md`):**icon 代表內容/類別 → 與 label 同色;icon 純指示方向 → fg-muted(neutral-7)。**
|
|
180
|
+
|
|
181
|
+
Field 內的具體套用:
|
|
182
|
+
|
|
183
|
+
- **startIcon**(Search、Calendar):`fg-muted`——指示 field 用途,不是 value
|
|
184
|
+
- **ChevronDown 下拉箭頭**:`fg-muted`——指示可下拉
|
|
185
|
+
- **代表 value 的 icon**(如狀態 icon):**foreground**——icon 本身就是 value 的一部分
|
|
186
|
+
- **disabled 時**:所有 icon 統一 `fg-disabled`
|
|
187
|
+
|
|
188
|
+
## startIcon
|
|
189
|
+
|
|
190
|
+
左側靜態 icon,輔助使用者理解 input 的用途(如 Search icon)。屬於 input 的視覺提示,不屬於 value。
|
|
191
|
+
|
|
192
|
+
- 顏色 `fg-muted`(disabled 時 `fg-disabled`)
|
|
193
|
+
- `aria-hidden`——純裝飾
|
|
194
|
+
- 命名與 Button 的 `startIcon` 一致
|
|
195
|
+
|
|
196
|
+
## 下拉箭頭(Select / Combobox)
|
|
197
|
+
|
|
198
|
+
Select 和 Combobox 的最右側固定顯示 ChevronDown icon,指示可下拉選擇。
|
|
199
|
+
|
|
200
|
+
- 顏色 `fg-muted`——指示意圖,不是 value
|
|
201
|
+
- 不可互動(`pointer-events-none`)——下拉由 select 元素本身觸發
|
|
202
|
+
- clearable 有值時:clear X 在左,ChevronDown 在右
|
|
203
|
+
- 右側元素(clear + chevron)水平間距對齊 Field container padding token(具體值見 `field-wrapper.tsx`),跟 Input 一致
|
|
204
|
+
|
|
205
|
+
## Select 顯示模式
|
|
206
|
+
|
|
207
|
+
Select 支援兩種顯示模式(`display` prop):
|
|
208
|
+
|
|
209
|
+
| 模式 | edit | readonly / disabled | 適用場景 |
|
|
210
|
+
|------|------|---------------------|---------|
|
|
211
|
+
| `text`(預設) | 原生 select 純文字 + ChevronDown | 跟 Input 一致(純文字 + 標準 padding) | 狀態、類別等文字選項 |
|
|
212
|
+
| `tag` | Tag + 隱藏 select overlay + ChevronDown | Tag + tagPadding | 需要視覺標記的選項(顏色標籤等) |
|
|
213
|
+
|
|
214
|
+
`text` 模式可搭配 `startIcon`(代表 value 的圖示,如狀態 icon)。
|
|
215
|
+
|
|
216
|
+
`tag` 模式的 edit 用 hidden select overlay(跟 Combobox 同模式),Tag 用 `pointer-events-none`,點擊穿透到 select。右側元素水平間距對齊 Field container padding token(見 `field-wrapper.tsx`)。
|
|
217
|
+
|
|
218
|
+
tagPadding 只在有 Tag 時才套用。Placeholder/空值狀態使用 fieldWrapper 的標準 px-3 padding,確保文字與邊框有足夠間距。
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## endAction(Inline Action)
|
|
223
|
+
|
|
224
|
+
右側可互動元素,用於操作動作(清除內容、顯示密碼等)。
|
|
225
|
+
|
|
226
|
+
使用宣告式 API:
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
<Input endAction={{ icon: X, label: '清除', onClick: handleClear }} />
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Field 內部用 `<ItemInlineAction>`(`item-layout.tsx` 共用元件)渲染 — 跟 Sidebar / TreeView / DropdownMenu 的 inline action **完全同一套** canonical 實作,不再有「每個 host 自己複製 18 行 button JSX」的漂移。
|
|
233
|
+
|
|
234
|
+
- 共用規則見 `patterns/element-anatomy/item-anatomy.spec.md`「Inline Action 設計規格」節
|
|
235
|
+
- Helper 規格與 API 見 `item-anatomy.spec.md` 的「Inline action 共用元件」節
|
|
236
|
+
- Field host 必須傳 `size={size}` 給 `<ItemInlineAction>`(field 不在 `RowSizeContext` 內,需明確覆寫)
|
|
237
|
+
|
|
238
|
+
Icon 色彩遵循 Inline Action 統一規則:預設 `fg-muted`,hover 時 `foreground`。
|
|
239
|
+
|
|
240
|
+
- disabled / readonly 模式不渲染 endAction
|
|
241
|
+
- 條件渲染即可——消失後不佔位,input 自然擴展
|
|
242
|
+
- 下拉箭頭不屬於 endAction,屬於 Select / Combobox
|
|
243
|
+
|
|
244
|
+
**特例:Tag dismiss**——Tag 的 dismiss button 需要 chromatic hover bg(跟 tag 的 solid variant 色相一致),不是中性的 neutral-hover,因此**沒有**用 `ItemInlineAction`,維持自己的內部 JSX。這是合理特例,見 `tag.tsx:104` 的詳細註解。
|
|
245
|
+
|
|
246
|
+
**Escape hatch**(10% case config 表達不出時):每 Field host 提供 `endSlot?: React.ReactNode`,規則 SSOT 見 `patterns/element-anatomy/inline-action.spec.md`「Escape hatch」節。
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Display — 格式化顯示
|
|
251
|
+
|
|
252
|
+
每個 Field 元件 export 一個 Display 子元件,負責把 raw value 格式化為可讀文字或 ReactNode。
|
|
253
|
+
|
|
254
|
+
Display 的消費者:
|
|
255
|
+
- **DataTable cell**:根據 `meta.type` 自動選擇對應的 Display 元件
|
|
256
|
+
- **Field readonly 模式**:內部使用相同的格式化邏輯
|
|
257
|
+
|
|
258
|
+
### null / undefined 值
|
|
259
|
+
|
|
260
|
+
Display 模式統一顯示 em dash `—`,顏色 `text-fg-muted`。edit 模式顯示空白。
|
|
261
|
+
|
|
262
|
+
此規則適用於所有 Field 類型,boolean 例外(顯示 unchecked 狀態)。
|
|
263
|
+
|
|
264
|
+
### DataTable 整合
|
|
265
|
+
|
|
266
|
+
DataTable 根據 column 的 `meta.type` 自動選擇 Display 元件:
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
// 自動渲染——不需要手寫 cell
|
|
270
|
+
col.accessor('price', {
|
|
271
|
+
header: 'Price',
|
|
272
|
+
meta: { type: 'currency', prefix: '$' },
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
// 客製化——有自訂 cell 時完全跳過 type → Display
|
|
276
|
+
col.accessor('status', {
|
|
277
|
+
header: 'Status',
|
|
278
|
+
cell: (info) => <MyCustomBadge status={info.getValue()} />,
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
兩者可在同一張 table 混用。
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 共享 contract(2026-05-12 Stream C — Selected renderer / Placeholder vocabulary / Cell surface)
|
|
287
|
+
|
|
288
|
+
**(a) Selected value renderer**:rich display(avatar+name/icon+label)元件**必**提供 consumer renderer slot,**display/readonly/disabled/edit** 4 mode 共享同一 renderer(禁 edit-only)。`Select.selectedItemRenderer` / `Combobox.tagRenderer`(edit 已接;display path unify deferred 下 cycle)/ PeoplePicker 走 `PersonDisplay`+`MultiPersonDisplay`+`Combobox.tagRenderer`。對齊 MUI Autocomplete `renderValue` / Ant Select `tagRender`+`labelRender`+`optionRender` / MUI DataGrid `renderCell`+`renderEditCell` 共享 params。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
289
|
+
|
|
290
|
+
**(b) Placeholder vocabulary**(3 props 對 3 UI state,**不可混用**):
|
|
291
|
+
- `placeholder` — trigger empty(沒選值,例「請選擇人員」)— Ant/Polaris/Carbon canonical
|
|
292
|
+
- `searchPlaceholder` — search input hint(例「搜尋人員…」)— Ant `searchPlaceholder`
|
|
293
|
+
- `emptyText`/`noResultsText` — filtered menu 無結果(例「沒有符合的人員」)— Ant `notFoundContent` / Material X `localeText.noResultsOverlayLabel`
|
|
294
|
+
|
|
295
|
+
**禁**:wrapper 把 `emptyText`(search-empty)silent forward 成 `emptyPlaceholder`(trigger-empty);**Combobox `emptyPlaceholder` deprecated**,保留 1 cycle fallback,future `placeholder` 唯一 trigger source。Hook `check_field_controls_contracts.sh` (contract b) 機械強制。
|
|
296
|
+
|
|
297
|
+
**(c) Cell surface metrics**:Field family 在 cell 內**禁** hardcode padding(`tagAreaPaddingLeftPx={isEmpty ? undefined : 8}` 反 pattern)。改 **`FieldSurface` context**(`'form' | 'toolbar' | 'table-cell'`):`useFieldSurface()` 取值,`<FieldSurfaceProvider surface="table-cell">` 自動套於 `cell-registry.resolveCellComponent`。Consumer 用 `surface === 'table-cell'` 顯式 query(取代 `variant === 'naked'` heuristic)。**risk mitigation**:`avatar.left = cell.left + computed(--table-cell-px)`,禁再加 magic 8px(double-count)。**Token scope**:`--table-cell-px/py` 是 DataTable-scoped metric(CSS 定義在 `data-table.css`,Field naked variant 是 DataTable cell substrate sub-component 故 cross-path reference 不算真 cross-component),per 2026-05-13 codex Q2 verdict + AG Grid `cellHorizontalPadding`(grid theme param)/ MUI X `cellClassName`(per-cell)/ Carbon spacing scale primitive(不升 cell padding 全域 token)idiom — **不**升 `tokens/layoutSpace/` canonical。對齊 AG Grid cellRendererSelector / Material X DataGrid 共享 params / Notion property type registry。Hook `check_field_controls_contracts.sh` (contract c) 機械強制。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
298
|
+
|
|
299
|
+
**(d) Default variant display = zero chrome SSOT**(2026-05-13 user 拍板 Path Ⅰ + codex V2 verdict):default `mode='display'` **必** zero chrome。Display 純展示語意,真要包 chrome 走 `readonly` 或 `showDisplayEndIcon=true` opt-in。**Impl**:`field-wrapper.tsx` + `textarea.tsx` compoundVariants `mode:'display'+variant:'default'` 加 `!px-0 !py-0`。對齊 Carbon read-only / Stripe display / Notion property / Polaris readonly。Hook `check_field_controls_contracts.sh` (contract d) propose。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
300
|
+
|
|
301
|
+
**(e) Display typography canonical**(2026-05-14 user I2 + codex M31 verdict):Field family display path **必** consume `fieldWrapperStyles` size variants typography token — `sm/md → text-body`(14px line-height 1.5)/ `lg → text-body-lg`(16px)。**禁**:LinkInput / Select / Combobox 非 D-path 的 bare-span 直接 render 無 font-size class(瀏覽器 default 字體);**必**包 `text-body` (sm/md) / `text-body-lg` (lg) class。對齊跨 Field family display 視覺尺寸統一(user 抓 LinkInput display 字體跟其他 Field 不一致 = SSOT 違反 漏接 typography token)。**Impl**:LinkInput / Select / Combobox / DatePicker / TimePicker non-D-path bare-span 加 size-aware text class。world-class cite:MUI X DataGrid `Typography` consistent / Atlassian @atlaskit/textfield size-prop typography token / Polaris TextField typographyToken size-aware。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## 表單驗證原則
|
|
306
|
+
|
|
307
|
+
詳見 `Field/form-validation.spec.md`。
|
|
308
|
+
|
|
309
|
+
## 禁止事項
|
|
310
|
+
|
|
311
|
+
- ❌ 不在 disabled input 內放 info icon——停用原因由外部 Tooltip 或 Form help text 承擔
|
|
312
|
+
- ❌ 不在 input 尾部放 error 狀態 icon——邊框顏色已傳達 error
|
|
313
|
+
- ❌ endAction 不可傳入 ReactNode——使用 InlineActionConfig 宣告式 API
|
|
314
|
+
- ❌ endAction 的 inline action 不可省略 `aria-label`(即 `label` 欄位)
|
|
315
|
+
- ❌ Display 的 null 值不可顯示空白——統一使用 `—`(em dash)+ `text-fg-muted`
|
|
316
|
+
- ❌ Field 的 readonly 模式不可用於 DataTable cell——readonly 有底色和 wrapper 開銷,table cell 用 Display 元件
|
|
317
|
+
|
|
318
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
319
|
+
|
|
320
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
321
|
+
|
|
322
|
+
- `checkbox.spec.md`
|
|
323
|
+
- `circular-progress.spec.md`
|
|
324
|
+
- `combobox.spec.md`
|
|
325
|
+
- `data-table.spec.md`
|
|
326
|
+
- `date-picker.spec.md`
|
|
327
|
+
- `element-anatomy.spec.md`
|
|
328
|
+
- `input.spec.md`
|
|
329
|
+
- `link-input.spec.md`
|
|
330
|
+
- `number-input.spec.md`
|
|
331
|
+
- `people-picker.spec.md`
|
|
332
|
+
- `rating.spec.md`
|
|
333
|
+
- `segmented-control.spec.md`
|
|
334
|
+
- `select.spec.md`
|
|
335
|
+
- `slider.spec.md`
|
|
336
|
+
- `switch.spec.md`
|
|
337
|
+
- `textarea.spec.md`
|
|
338
|
+
- `time-picker.spec.md`
|