@qijenchen/design-system 0.1.0-beta.83 → 0.1.0-beta.84
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 +8 -8
- package/README.md +3 -2
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +1 -1
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +22 -2
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +4 -4
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/Button/button.d.ts +2 -2
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +12 -3
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +13 -5
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +7 -1
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +8 -3
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Chart/chart.d.ts.map +1 -1
- package/dist/components/Chart/chart.js +1 -0
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +1 -1
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +8 -4
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +1 -1
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +10 -3
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +5 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +30 -13
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +53 -62
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/column-types.d.ts +10 -4
- package/dist/components/DataTable/column-types.d.ts.map +1 -1
- package/dist/components/DataTable/column-types.js.map +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +1 -1
- package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.js +607 -0
- package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table-sort-manager.js +140 -0
- package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +5 -6
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +36 -15
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DataTable/filter-operators.js +140 -0
- package/dist/components/DataTable/filter-operators.js.map +1 -0
- package/dist/components/DataTable/filter-tree.js +312 -0
- package/dist/components/DataTable/filter-tree.js.map +1 -0
- package/dist/components/DataTable/index.d.ts +3 -0
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/index.js +12 -1
- package/dist/components/DataTable/index.js.map +1 -1
- package/dist/components/DataTable/lib/column-meta.js +25 -0
- package/dist/components/DataTable/lib/column-meta.js.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +3 -1
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +7 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +105 -74
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts +20 -3
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +38 -20
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Field/field-context.d.ts +45 -5
- package/dist/components/Field/field-context.d.ts.map +1 -1
- package/dist/components/Field/field-context.js +19 -0
- package/dist/components/Field/field-context.js.map +1 -1
- package/dist/components/Field/field-edit-keys.d.ts +21 -0
- package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
- package/dist/components/Field/field-edit-keys.js +19 -0
- package/dist/components/Field/field-edit-keys.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +20 -1
- package/dist/components/Field/field-types.d.ts.map +1 -1
- package/dist/components/Field/field-types.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +3 -2
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +38 -39
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +2 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FileItem/file-item.d.ts.map +1 -1
- package/dist/components/FileItem/file-item.js +1 -1
- package/dist/components/FileItem/file-item.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts +1 -1
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +7 -2
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
- package/dist/components/FileViewer/image-renderer.js +22 -1
- package/dist/components/FileViewer/image-renderer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +5 -3
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/InlineEdit/index.d.ts +2 -0
- package/dist/components/InlineEdit/index.d.ts.map +1 -0
- package/dist/components/InlineEdit/index.js +5 -0
- package/dist/components/InlineEdit/index.js.map +1 -0
- package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
- package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
- package/dist/components/InlineEdit/inline-edit.js +164 -0
- package/dist/components/InlineEdit/inline-edit.js.map +1 -0
- package/dist/components/Input/input.d.ts +6 -11
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +43 -13
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +2 -2
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +6 -5
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts +14 -2
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js +25 -3
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +3 -3
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +6 -5
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/pagination.js +1 -1
- package/dist/components/Pagination/pagination.js.map +1 -1
- package/dist/components/PeoplePicker/index.js +7 -1
- package/dist/components/PeoplePicker/index.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +23 -10
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +6 -3
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +19 -14
- package/dist/components/PeoplePicker/person-display.js.map +1 -1
- package/dist/components/Popover/popover.d.ts.map +1 -1
- package/dist/components/Popover/popover.js +3 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +2 -2
- package/dist/components/ProfileCard/profile-card.js +3 -3
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +15 -9
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +6 -3
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/Select/select.d.ts +46 -5
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +109 -28
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +3 -1
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +8 -1
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
- package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
- package/dist/components/SelectionControl/boolean-value.js +23 -0
- package/dist/components/SelectionControl/boolean-value.js.map +1 -0
- package/dist/components/SelectionControl/index.d.ts +1 -0
- package/dist/components/SelectionControl/index.d.ts.map +1 -1
- package/dist/components/SelectionControl/index.js +2 -0
- package/dist/components/SelectionControl/index.js.map +1 -1
- package/dist/components/Sheet/index.js +2 -1
- package/dist/components/Sheet/sheet.d.ts +7 -1
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js +5 -2
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +9 -4
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +8 -10
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +6 -6
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +3 -2
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +15 -1
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +2 -2
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +50 -42
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
- package/dist/components/TimePicker/time-columns.js +42 -38
- package/dist/components/TimePicker/time-columns.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +8 -6
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/Tooltip/tooltip.js +7 -5
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +56 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +211 -12
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/index.d.ts +115 -58
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +93 -108
- package/dist/index.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/tokens/categorical-color.js +15 -0
- package/dist/tokens/categorical-color.js.map +1 -1
- package/dist/tokens/motion/motion.d.ts +7 -6
- package/dist/tokens/motion/motion.d.ts.map +1 -1
- package/dist/tokens/motion/motion.js +6 -6
- package/dist/tokens/motion/motion.js.map +1 -1
- package/dist/tokens/motion/overlay-motion.d.ts +19 -0
- package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
- package/dist/tokens/motion/overlay-motion.js +9 -0
- package/dist/tokens/motion/overlay-motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.js +5 -0
- package/dist/tokens/uiSize/icon-size.js.map +1 -0
- package/ds-canonical/fork/governance.lock +31 -19
- package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
- package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
- package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/fork/manifest.json +15 -0
- package/ds-canonical/fork/preamble.md +20 -18
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
- package/ds-canonical/hooks/README.md +1 -1
- package/ds-canonical/hooks/block_prototype_imports.py +15 -4
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
- package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
- package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
- package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
- package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
- package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
- package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
- package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
- package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
- package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
- package/ds-canonical/hooks/check_story_determinism.sh +2 -0
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
- package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
- package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
- package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
- package/ds-canonical/hooks/stop_self_audit.sh +31 -0
- package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
- package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
- package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
- package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
- package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
- package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
- package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
- package/ds-canonical/references/build-ui-canonicals.md +2 -1
- package/ds-canonical/references/failure-class-registry.json +145 -0
- package/ds-canonical/references/governance-audit-coverage.md +33 -0
- package/ds-canonical/references/item-anatomy-recipe.md +2 -2
- package/ds-canonical/references/scenario-definition.md +6 -9
- package/ds-canonical/references/ssot-consultation.md +2 -2
- package/ds-canonical/references/ssot-index.md +5 -4
- package/ds-canonical/references/story-baseline-registry.json +8 -2
- package/ds-canonical/references/structural-token-retention.md +6 -9
- package/ds-canonical/rules/meta-patterns.md +8 -8
- package/ds-canonical/rules/self-verify.md +4 -3
- package/ds-canonical/rules/story-rules.md +2 -2
- package/ds-canonical/rules/ui-development.md +2 -2
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
- package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
- package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
- package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
- package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
- package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
- package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
- package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
- package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
- package/ds-canonical/skills/governance-health/SKILL.md +1 -1
- package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
- package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
- package/ds-canonical/skills/new-component/SKILL.md +5 -5
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
- package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
- package/ds-canonical/skills/propose-options/SKILL.md +3 -3
- package/ds-canonical/skills/prototype/SKILL.md +1 -1
- package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
- package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
- package/ds-canonical/skills/story-writing/SKILL.md +3 -3
- package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
- package/ds-story-manifest.json +29 -20
- package/llms-full.txt +22 -1
- package/llms.txt +5 -4
- package/package.json +7 -3
- package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
- package/src/components/Accordion/accordion.stories.tsx +16 -1
- package/src/components/Alert/alert.principles.stories.tsx +1 -1
- package/src/components/Alert/alert.spec.md +8 -10
- package/src/components/Alert/alert.stories.tsx +28 -28
- package/src/components/Alert/alert.tsx +1 -1
- package/src/components/AppShell/_demo-helpers.tsx +6 -3
- package/src/components/AppShell/app-shell.spec.md +4 -4
- package/src/components/AppShell/app-shell.tsx +28 -2
- package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
- package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
- package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
- package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
- package/src/components/Avatar/avatar.spec.md +2 -2
- package/src/components/Avatar/avatar.stories.tsx +8 -6
- package/src/components/Avatar/avatar.tsx +13 -5
- package/src/components/Badge/badge.principles.stories.tsx +1 -1
- package/src/components/Badge/badge.spec.md +2 -0
- package/src/components/Badge/badge.stories.tsx +4 -2
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
- package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
- package/src/components/Button/button.principles.stories.tsx +1 -1
- package/src/components/Button/button.spec.md +2 -2
- package/src/components/Button/button.tsx +18 -3
- package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
- package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
- package/src/components/Calendar/calendar.spec.md +5 -4
- package/src/components/Calendar/calendar.stories.tsx +7 -4
- package/src/components/Calendar/calendar.tsx +26 -7
- package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
- package/src/components/Carousel/carousel.spec.md +2 -2
- package/src/components/Carousel/carousel.tsx +11 -3
- package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
- package/src/components/Chart/chart.principles.stories.tsx +1 -1
- package/src/components/Chart/chart.stories.tsx +2 -8
- package/src/components/Chart/chart.tsx +3 -0
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
- package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.spec.md +11 -26
- package/src/components/Checkbox/checkbox.stories.tsx +11 -8
- package/src/components/Checkbox/checkbox.tsx +18 -13
- package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
- package/src/components/Chip/chip.principles.stories.tsx +1 -1
- package/src/components/Chip/chip.spec.md +5 -4
- package/src/components/Chip/chip.tsx +5 -1
- package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
- package/src/components/CircularProgress/circular-progress.spec.md +3 -3
- package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
- package/src/components/Coachmark/coachmark.spec.md +5 -5
- package/src/components/Coachmark/coachmark.stories.tsx +3 -1
- package/src/components/Coachmark/coachmark.tsx +10 -3
- package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
- package/src/components/Combobox/combobox.tsx +53 -19
- package/src/components/Command/command.anatomy.stories.tsx +2 -2
- package/src/components/Command/command.principles.stories.tsx +1 -1
- package/src/components/Command/command.stories.tsx +42 -10
- package/src/components/DataTable/cell-registry.tsx +86 -63
- package/src/components/DataTable/column-types.ts +10 -1
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
- package/src/components/DataTable/data-table-filter-panel.tsx +4 -1
- package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
- package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
- package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
- package/src/components/DataTable/data-table.spec.md +32 -12
- package/src/components/DataTable/data-table.stories.tsx +16 -17
- package/src/components/DataTable/data-table.tsx +103 -60
- package/src/components/DataTable/index.ts +3 -0
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
- package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
- package/src/components/DateGrid/date-grid.spec.md +1 -1
- package/src/components/DateGrid/date-grid.tsx +3 -1
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
- package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
- package/src/components/DatePicker/date-picker.spec.md +3 -3
- package/src/components/DatePicker/date-picker.stories.tsx +4 -5
- package/src/components/DatePicker/date-picker.tsx +99 -45
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
- package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.spec.md +3 -3
- package/src/components/DescriptionList/description-list.stories.tsx +7 -6
- package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
- package/src/components/Dialog/dialog.spec.md +9 -0
- package/src/components/Dialog/dialog.stories.tsx +66 -5
- package/src/components/Dialog/dialog.tsx +60 -25
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
- package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
- package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
- package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
- package/src/components/Empty/empty.spec.md +2 -2
- package/src/components/Field/field-context.ts +69 -5
- package/src/components/Field/field-controls.spec.md +62 -8
- package/src/components/Field/field-edit-keys.ts +66 -0
- package/src/components/Field/field-types.ts +58 -9
- package/src/components/Field/field-wrapper.tsx +50 -42
- package/src/components/Field/field.anatomy.stories.tsx +9 -6
- package/src/components/Field/field.spec.md +1 -1
- package/src/components/Field/field.stories.tsx +1 -1
- package/src/components/Field/field.tsx +2 -1
- package/src/components/Field/form-validation.spec.md +3 -3
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
- package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
- package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
- package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
- package/src/components/FileItem/file-item.spec.md +5 -8
- package/src/components/FileItem/file-item.stories.tsx +36 -25
- package/src/components/FileItem/file-item.tsx +8 -6
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
- package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
- package/src/components/FileUpload/file-upload.spec.md +1 -1
- package/src/components/FileUpload/file-upload.tsx +1 -1
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
- package/src/components/FileViewer/file-viewer.spec.md +30 -12
- package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
- package/src/components/FileViewer/file-viewer.tsx +12 -4
- package/src/components/FileViewer/image-renderer.tsx +35 -7
- package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
- package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
- package/src/components/HoverCard/hover-card.spec.md +5 -5
- package/src/components/HoverCard/hover-card.stories.tsx +16 -16
- package/src/components/HoverCard/hover-card.tsx +5 -3
- package/src/components/InlineEdit/index.ts +5 -0
- package/src/components/InlineEdit/inline-edit.spec.md +149 -0
- package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
- package/src/components/InlineEdit/inline-edit.tsx +287 -0
- package/src/components/Input/input.anatomy.stories.tsx +8 -7
- package/src/components/Input/input.principles.stories.tsx +2 -12
- package/src/components/Input/input.spec.md +13 -18
- package/src/components/Input/input.tsx +69 -22
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
- package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
- package/src/components/LinkInput/link-input.tsx +11 -10
- package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
- package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
- package/src/components/Menu/menu-item.spec.md +22 -15
- package/src/components/Menu/menu-item.stories.tsx +39 -11
- package/src/components/Menu/menu-item.tsx +38 -4
- package/src/components/Notice/notice.principles.stories.tsx +1 -1
- package/src/components/Notice/notice.spec.md +16 -3
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
- package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
- package/src/components/NumberInput/number-input.spec.md +4 -4
- package/src/components/NumberInput/number-input.tsx +19 -12
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
- package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
- package/src/components/Pagination/pagination.spec.md +1 -1
- package/src/components/Pagination/pagination.stories.tsx +2 -6
- package/src/components/Pagination/pagination.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
- package/src/components/PeoplePicker/people-picker.spec.md +6 -6
- package/src/components/PeoplePicker/people-picker.tsx +56 -16
- package/src/components/PeoplePicker/person-display.tsx +32 -16
- package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
- package/src/components/Popover/popover.tsx +3 -1
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
- package/src/components/ProfileCard/profile-card.spec.md +3 -3
- package/src/components/ProfileCard/profile-card.tsx +6 -6
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
- package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
- package/src/components/RadioGroup/radio-group.tsx +41 -15
- package/src/components/Rating/rating.spec.md +11 -3
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.spec.md +7 -3
- package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
- package/src/components/ScrollArea/scroll-area.tsx +17 -4
- package/src/components/Select/select.anatomy.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +27 -17
- package/src/components/Select/select.stories.tsx +33 -0
- package/src/components/Select/select.tsx +190 -36
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
- package/src/components/SelectMenu/select-menu.spec.md +15 -7
- package/src/components/SelectMenu/select-menu.tsx +16 -3
- package/src/components/SelectionControl/boolean-value.tsx +39 -0
- package/src/components/SelectionControl/index.ts +1 -0
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.spec.md +3 -3
- package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
- package/src/components/Separator/separator.spec.md +2 -2
- package/src/components/Separator/separator.stories.tsx +6 -27
- package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
- package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
- package/src/components/Sheet/sheet.spec.md +2 -2
- package/src/components/Sheet/sheet.tsx +9 -5
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
- package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
- package/src/components/Sidebar/sidebar.spec.md +13 -15
- package/src/components/Sidebar/sidebar.stories.tsx +8 -7
- package/src/components/Sidebar/sidebar.tsx +37 -25
- package/src/components/Skeleton/skeleton.stories.tsx +4 -11
- package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
- package/src/components/Slider/slider.principles.stories.tsx +2 -2
- package/src/components/Slider/slider.spec.md +5 -5
- package/src/components/Slider/slider.tsx +3 -1
- package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
- package/src/components/Steps/steps.principles.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +1 -1
- package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
- package/src/components/Switch/switch.principles.stories.tsx +4 -4
- package/src/components/Switch/switch.spec.md +8 -8
- package/src/components/Switch/switch.stories.tsx +9 -24
- package/src/components/Switch/switch.tsx +17 -13
- package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
- package/src/components/Tabs/tabs.spec.md +1 -1
- package/src/components/Tabs/tabs.tsx +21 -1
- package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
- package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
- package/src/components/Textarea/textarea.spec.md +4 -4
- package/src/components/Textarea/textarea.tsx +72 -46
- package/src/components/TimePicker/time-columns.tsx +6 -2
- package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
- package/src/components/TimePicker/time-picker.spec.md +3 -3
- package/src/components/TimePicker/time-picker.tsx +16 -10
- package/src/components/Toast/toast.stories.tsx +7 -4
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
- package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
- package/src/components/Tooltip/tooltip.spec.md +1 -1
- package/src/components/Tooltip/tooltip.stories.tsx +4 -39
- package/src/components/Tooltip/tooltip.tsx +8 -6
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
- package/src/components/TreeView/tree-view.spec.md +42 -11
- package/src/components/TreeView/tree-view.stories.tsx +1 -0
- package/src/components/TreeView/tree-view.tsx +322 -17
- package/src/index.ts +584 -60
- package/src/patterns/action-bar/action-bar.spec.md +9 -0
- package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
- package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
- package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
- package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
- package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
- package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
- package/src/styles/tokens.css +3 -0
- package/src/tokens/README.md +1 -1
- package/src/tokens/color/color.spec.md +3 -3
- package/src/tokens/color/color.stories.tsx +3 -3
- package/src/tokens/density/density.stories.tsx +16 -3
- package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
- package/src/tokens/motion/motion.css +33 -21
- package/src/tokens/motion/motion.spec.md +32 -15
- package/src/tokens/motion/motion.stories.tsx +58 -5
- package/src/tokens/motion/motion.ts +7 -6
- package/src/tokens/motion/overlay-motion.ts +26 -0
- package/src/tokens/orphan-tokens.spec.md +4 -4
- package/src/tokens/token-system.spec.md +1 -0
- package/src/tokens/uiSize/uiSize.spec.md +1 -1
- package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
- package/src/tokens/utility-registry.json +160 -23
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
2
|
// @anatomy-exempt: anatomy specs / token 對照表格用 raw <table>,非業務資料表。業務資料表才用 <DataTable>。
|
|
3
|
+
// @overlay-open-skip: 本檔絕大多數 story 直接 render ProfileCard(內容不藏在浮層,snapshot 可見);
|
|
4
|
+
// 唯一 HoverCard demo 只示範「hover 整合」消費方式,open-state 內容已由同檔直接 render 的
|
|
5
|
+
// stories 完整快照,forced defaultOpen 反而讓浮層蓋住旁邊的說明。
|
|
3
6
|
// @anatomy-rationale:
|
|
4
7
|
// SizeMatrix N/A — ProfileCard 是固定寬度(320px)hover content template,
|
|
5
8
|
// 不提供 size prop;所有尺寸 token 已於 Overview「Layout Token」段列出
|
|
@@ -51,12 +54,7 @@ export const Overview: Story = {
|
|
|
51
54
|
subtitle="Design Engineer · Engineering"
|
|
52
55
|
status="online"
|
|
53
56
|
statusMessage="目前 Sprint 23 衝刺中,訊息可能稍慢回覆"
|
|
54
|
-
actions={
|
|
55
|
-
<>
|
|
56
|
-
<Button variant="primary" size="sm" startIcon={MessageCircle}>傳訊</Button>
|
|
57
|
-
<Button variant="tertiary" size="sm" startIcon={UserPlus}>追蹤</Button>
|
|
58
|
-
</>
|
|
59
|
-
}
|
|
57
|
+
actions={<ProfileCardDefaultActions />}
|
|
60
58
|
fields={[
|
|
61
59
|
{ label: 'Email', value: 'ada.chen@example.com' },
|
|
62
60
|
{ label: '團隊', value: 'Engineering' },
|
|
@@ -228,18 +226,13 @@ export const SectionMatrix: Story = {
|
|
|
228
226
|
|
|
229
227
|
<div>
|
|
230
228
|
<H3>+ Actions</H3>
|
|
231
|
-
<Desc>加上快速動作——留言區 hover
|
|
229
|
+
<Desc>加上快速動作——留言區 hover 顯示「Chat」/「Audio call」(canonical `ProfileCardDefaultActions`),減少跳轉 profile 頁的摩擦。</Desc>
|
|
232
230
|
<div className="border border-dashed border-divider rounded-md p-4 inline-block">
|
|
233
231
|
<ProfileCard
|
|
234
232
|
name="Diana Lin"
|
|
235
233
|
subtitle="Engineering Manager"
|
|
236
234
|
status="online"
|
|
237
|
-
actions={
|
|
238
|
-
<>
|
|
239
|
-
<Button variant="primary" size="sm" startIcon={MessageCircle}>傳訊</Button>
|
|
240
|
-
<Button variant="tertiary" size="sm" startIcon={UserPlus}>追蹤</Button>
|
|
241
|
-
</>
|
|
242
|
-
}
|
|
235
|
+
actions={<ProfileCardDefaultActions />}
|
|
243
236
|
/>
|
|
244
237
|
</div>
|
|
245
238
|
</div>
|
|
@@ -271,12 +264,7 @@ export const SectionMatrix: Story = {
|
|
|
271
264
|
subtitle="Design Engineer · Engineering"
|
|
272
265
|
status="online"
|
|
273
266
|
statusMessage="目前專案 Sprint 23 衝刺中"
|
|
274
|
-
actions={
|
|
275
|
-
<>
|
|
276
|
-
<Button variant="primary" size="sm" startIcon={MessageCircle}>傳訊</Button>
|
|
277
|
-
<Button variant="tertiary" size="sm" startIcon={UserPlus}>追蹤</Button>
|
|
278
|
-
</>
|
|
279
|
-
}
|
|
267
|
+
actions={<ProfileCardDefaultActions />}
|
|
280
268
|
fields={[
|
|
281
269
|
{ label: 'Email', value: 'ada.chen@example.com' },
|
|
282
270
|
{ label: '團隊', value: 'Engineering' },
|
|
@@ -366,14 +354,14 @@ export const HoverCardIntegration: Story = {
|
|
|
366
354
|
</Desc>
|
|
367
355
|
<div className="border border-border rounded-lg p-6 flex items-center gap-8">
|
|
368
356
|
{[
|
|
369
|
-
{ name: 'Ada Chen
|
|
370
|
-
{ name: 'Alice Wang', subtitle: 'Frontend Engineer', status: 'busy' as const },
|
|
371
|
-
{ name: 'Bob Chen', subtitle: 'PM, Growth', status: 'away' as const },
|
|
357
|
+
{ name: 'Ada Chen', subtitle: 'Design Engineer', status: 'online' as const, avatarUrl: 'https://i.pravatar.cc/80?u=ada-chen' },
|
|
358
|
+
{ name: 'Alice Wang', subtitle: 'Frontend Engineer', status: 'busy' as const, avatarUrl: 'https://i.pravatar.cc/80?u=alice-wang' },
|
|
359
|
+
{ name: 'Bob Chen', subtitle: 'PM, Growth', status: 'away' as const, avatarUrl: 'https://i.pravatar.cc/80?u=bob-chen' },
|
|
372
360
|
].map(p => (
|
|
373
361
|
<HoverCard key={p.name}>
|
|
374
362
|
<HoverCardTrigger asChild>
|
|
375
363
|
<span className="inline-block cursor-pointer">
|
|
376
|
-
<Avatar alt={p.name} size={40} status={p.status} />
|
|
364
|
+
<Avatar src={p.avatarUrl} alt={p.name} size={40} status={p.status} />
|
|
377
365
|
</span>
|
|
378
366
|
</HoverCardTrigger>
|
|
379
367
|
<HoverCardContent align="start" className="p-0">{/* sideOffset 不 override — spec 禁止事項(default 即 OVERLAY_SIDE_OFFSET) */}
|
|
@@ -381,6 +369,7 @@ export const HoverCardIntegration: Story = {
|
|
|
381
369
|
name={p.name}
|
|
382
370
|
subtitle={p.subtitle}
|
|
383
371
|
status={p.status}
|
|
372
|
+
avatar={{ src: p.avatarUrl, alt: p.name }}
|
|
384
373
|
fields={[
|
|
385
374
|
{ label: 'Email', value: `${p.name.split(' ')[0].toLowerCase()}@example.com` },
|
|
386
375
|
{ label: '團隊', value: 'Engineering' },
|
|
@@ -57,13 +57,13 @@ ProfileCard 是**三層 chrome 結構**(2026-04-23 canonical):
|
|
|
57
57
|
│ BODY(可垂直捲動) │ ← Status section(v12 conditional)+ Info fields(always-render)
|
|
58
58
|
│ ↕ 空間不足時此區捲動 │ Status undefined → 整 status block skip
|
|
59
59
|
├─────────────────────────────┤
|
|
60
|
-
│ FOOTER(固定不捲) │ ← View more(
|
|
60
|
+
│ FOOTER(固定不捲) │ ← View more(傳 onViewMore 時顯示,詳「View More」)
|
|
61
61
|
└─────────────────────────────┘
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
- **Header 固定**:Profile + Actions 一體,**不捲動**(使用者的視覺 anchor:誰 + 可對他做什麼)
|
|
65
65
|
- **Body 可捲動**:Status section + Info fields。以 `<ScrollArea>` 包(cross-OS overlay 捲軸)
|
|
66
|
-
- **Footer
|
|
66
|
+
- **Footer 固定**:傳入 `onViewMore` 時 View more 固定於底(條件渲染 `{onViewMore && …}`,未傳則不渲染 footer)——是 hover preview 到完整 profile 的 escape hatch(對齊本 spec「View More」段 + `profile-card.tsx` footer 條件渲染)
|
|
67
67
|
|
|
68
68
|
**Status section v12 conditional rule(2026-05-14 user 拍板)**:`status` 在 production 一定會被設定(每個 user 都有 presence state)。如果 status undefined,**唯一可能性 = 資料還沒讀到(loading transient)**,**不**是「user 沒設定狀態」。所以 status undefined 期間 → **整 status block 隱藏**(等資料到才 render),**禁** render「Status not set」這種 placeholder 文字(語義錯,user presence 不會「沒設定」)。**此規則 ProfileCard-specific 不外推至 DS 其他元件**(FileItem / DescriptionList / DataTable cell 各自 placeholder 邏輯 unrelated)。
|
|
69
69
|
|
|
@@ -134,7 +134,7 @@ ProfileCard 的 default actions **是 `Chat + Audio call`**(chat app 標配,cano
|
|
|
134
134
|
|
|
135
135
|
- **Name / Subtitle 超長**:自然換行撐高 header,不截斷(text column 最小高度對齊 avatar,見「Profile Header」)
|
|
136
136
|
- **Status / statusMessage 缺值**:status undefined = loading transient → 整 status block 隱藏(v12 rule,見「結構」);ProfileCard **無整卡 loading prop**,資料未到的整卡呈現由 consumer 決定
|
|
137
|
-
- **Info fields 缺值**:default fields 永遠 render
|
|
137
|
+
- **Info fields 缺值**:default fields 永遠 render,缺資料顯半形 `-` placeholder(`text-foreground`——對齊 DS 空值顯示 canonical:不可編輯供檢視的空值同 readonly 值色;section 結構不收合);consumer `fields` label 撞 default 時 consumer 值 win(dedup canonical,詳 `profile-card.tsx`)
|
|
138
138
|
- **內容過長**:Body 在固定高度內以 ScrollArea 捲動,不 clamp 行數(見「Status 區」)
|
|
139
139
|
|
|
140
140
|
---
|
|
@@ -105,7 +105,7 @@ const STATUS_LABEL: Record<StatusType, string> = {
|
|
|
105
105
|
* 各自不一致(同 person 在 DataTable / PeoplePicker / avatar.principles 看起來不同)。
|
|
106
106
|
*
|
|
107
107
|
* v11 canonical(歷史):ProfileCard 當時 always renders 4 default sections — 缺 data → 顯
|
|
108
|
-
* `EMPTY_PLACEHOLDER`("
|
|
108
|
+
* `EMPTY_PLACEHOLDER`("-")。現行:default fields 縮為 2(v15.7)+ status 條件 render(v12),
|
|
109
109
|
* 「視覺結構 SSOT 在此元件,不依賴 consumer」原則不變。
|
|
110
110
|
*
|
|
111
111
|
* ── 對齊 world-class ──
|
|
@@ -128,7 +128,7 @@ const DEFAULT_FIELD_LABEL: Record<ProfileCardDefaultFieldKey, string> = {
|
|
|
128
128
|
employeeNumber: 'Employee number',
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
const FIELD_PLACEHOLDER = '
|
|
131
|
+
const FIELD_PLACEHOLDER = '-'
|
|
132
132
|
|
|
133
133
|
export interface ProfileCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
134
134
|
name: string
|
|
@@ -139,7 +139,7 @@ export interface ProfileCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
139
139
|
actions?: React.ReactNode
|
|
140
140
|
/**
|
|
141
141
|
* Consumer 傳的 field 資料(partial)。預設 keys 走 `NAMECARD_DEFAULT_FIELD_KEYS` —
|
|
142
|
-
* 只有 id / employeeNumber 兩個 default field 永遠 render(缺資料顯
|
|
142
|
+
* 只有 id / employeeNumber 兩個 default field 永遠 render(缺資料顯 `-`);email / phone /
|
|
143
143
|
* department / location 等其他欄位一律 opt-in by consumer 透過本 prop 傳入。Consumer 想新增
|
|
144
144
|
* 自訂 field 直接傳入(在 default 之後 append),想 override default key value 也直接傳。
|
|
145
145
|
*/
|
|
@@ -178,7 +178,7 @@ const ProfileCard = React.forwardRef<HTMLDivElement, ProfileCardProps>(
|
|
|
178
178
|
//
|
|
179
179
|
// **Dedup canonical(2026-05-07 v15.8 fix Bug E)**:consumer 的 `fields` array 若含
|
|
180
180
|
// label 撞 default(eg. 「ID」「Employee number」),consumer 值 win — defaults 那一行
|
|
181
|
-
// 跳過(否則 same label 連 render 兩次,如 default placeholder
|
|
181
|
+
// 跳過(否則 same label 連 render 兩次,如 default placeholder `-` + consumer 真值)。
|
|
182
182
|
// 這是遷移期 forgiving 行為:DEV warn 提示應改用 `defaultFieldValues`,但 production
|
|
183
183
|
// 不破壞既有 consumer。對齊 React `key` 唯一性 + Linear / Slack profile card 一 label
|
|
184
184
|
// 一 row idiom。
|
|
@@ -292,7 +292,7 @@ const ProfileCard = React.forwardRef<HTMLDivElement, ProfileCardProps>(
|
|
|
292
292
|
message 是一組;沒 status 就沒 status message)。缺 statusMessage 顯 placeholder。 */}
|
|
293
293
|
<DescriptionList>
|
|
294
294
|
<DescriptionItem label="Status message">
|
|
295
|
-
{statusMessage ?? <span className="text-
|
|
295
|
+
{statusMessage ?? <span className="text-foreground">{FIELD_PLACEHOLDER}</span>}
|
|
296
296
|
</DescriptionItem>
|
|
297
297
|
</DescriptionList>
|
|
298
298
|
</div>
|
|
@@ -304,7 +304,7 @@ const ProfileCard = React.forwardRef<HTMLDivElement, ProfileCardProps>(
|
|
|
304
304
|
{allFields.map((f) => (
|
|
305
305
|
<DescriptionItem key={f.label} label={f.label}>
|
|
306
306
|
{f.value === FIELD_PLACEHOLDER
|
|
307
|
-
? <span className="text-
|
|
307
|
+
? <span className="text-foreground">{FIELD_PLACEHOLDER}</span>
|
|
308
308
|
: f.value}
|
|
309
309
|
</DescriptionItem>
|
|
310
310
|
))}
|
|
@@ -74,8 +74,10 @@ export const Overview = {
|
|
|
74
74
|
<div className="h-full rounded-full bg-info" style={{ width: '45%' }} />
|
|
75
75
|
</div>
|
|
76
76
|
</div>
|
|
77
|
+
{/* 2026-07-14 dim-55 修:`--magenta`/`--magenta-subtle` 不存在(semantic magenta namespace
|
|
78
|
+
只有 hover/active)→ anatomy 圖解標記屬 categorical 靜態色,消費 primitive step token */}
|
|
77
79
|
<span className="rounded px-2 py-0.5 text-[11px] font-mono border border-dashed"
|
|
78
|
-
style={{ borderColor: 'var(--magenta)', backgroundColor: 'var(--magenta-
|
|
80
|
+
style={{ borderColor: 'var(--color-magenta-6)', backgroundColor: 'var(--color-magenta-1)', color: 'var(--color-magenta-7)' }}>affix</span>
|
|
79
81
|
</div>
|
|
80
82
|
<span className="text-[10px] text-fg-muted font-mono">wrapper: flex items-center gap-2 · bar: flex-1 min-w-0</span>
|
|
81
83
|
</div>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
// @story-baseline: packages/design-system/src/components/DataTable/data-table.anatomy.stories.tsx#AlignmentRule
|
|
1
2
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
|
+
import type { ColumnDef } from '@tanstack/react-table'
|
|
2
4
|
import { FileText, Table as TableIcon } from 'lucide-react'
|
|
3
5
|
import { ProgressBar } from './progress-bar'
|
|
6
|
+
import { DataTable } from '@/design-system/components/DataTable/data-table'
|
|
7
|
+
import '@/design-system/components/DataTable/column-types' // ColumnMeta declaration merging
|
|
4
8
|
|
|
5
9
|
const meta: Meta<typeof ProgressBar> = {
|
|
6
10
|
title: 'Design System/Components/ProgressBar/展示',
|
|
@@ -70,50 +74,54 @@ export const BatchTask: Story = {
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
// ── 真實情境 3: DataTable cell inline 進度 ─────────────────────────────
|
|
77
|
+
// 2026-07-14 audit(R1 A.2):手刻 table markup → 消費真 <DataTable>(對齊 Skeleton
|
|
78
|
+
// TableRowLoading 同款 consumer-自訂-cell 模式;columns 不設 meta.type 走自訂 cell)。
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
name:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</tr>
|
|
97
|
-
</thead>
|
|
98
|
-
<tbody>
|
|
99
|
-
{rows.map((r) => (
|
|
100
|
-
<tr key={r.name} className="border-t border-divider">
|
|
101
|
-
<td className="px-4 py-3">
|
|
102
|
-
<div className="flex items-center gap-2">
|
|
103
|
-
<FileText size={16} className="text-fg-muted shrink-0" />
|
|
104
|
-
{r.name}
|
|
105
|
-
</div>
|
|
106
|
-
</td>
|
|
107
|
-
<td className="px-4 py-3">
|
|
108
|
-
<ProgressBar value={r.quota} status={r.status} affix="value" />
|
|
109
|
-
</td>
|
|
110
|
-
</tr>
|
|
111
|
-
))}
|
|
112
|
-
</tbody>
|
|
113
|
-
</table>
|
|
114
|
-
</div>
|
|
80
|
+
interface QuotaRow {
|
|
81
|
+
name: string
|
|
82
|
+
quota: number
|
|
83
|
+
status: 'inProgress' | 'success' | 'error'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const quotaRows: QuotaRow[] = [
|
|
87
|
+
{ name: 'Acme Corp 專案', quota: 45, status: 'inProgress' },
|
|
88
|
+
{ name: 'Globex 整合', quota: 78, status: 'inProgress' },
|
|
89
|
+
{ name: 'Initech 改版', quota: 100, status: 'success' },
|
|
90
|
+
{ name: 'Umbrella 導入', quota: 12, status: 'inProgress' },
|
|
91
|
+
{ name: 'Wonka 客製化', quota: 95, status: 'error' },
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
const quotaColumns: ColumnDef<QuotaRow>[] = [
|
|
95
|
+
{
|
|
96
|
+
id: 'name',
|
|
97
|
+
header: '專案',
|
|
98
|
+
cell: ({ row }) => (
|
|
99
|
+
<div className="flex items-center gap-2">
|
|
100
|
+
<FileText size={16} className="text-fg-muted shrink-0" />
|
|
101
|
+
{row.original.name}
|
|
115
102
|
</div>
|
|
116
|
-
)
|
|
103
|
+
),
|
|
117
104
|
},
|
|
105
|
+
{
|
|
106
|
+
id: 'quota',
|
|
107
|
+
header: '配額使用率',
|
|
108
|
+
meta: { width: 240 },
|
|
109
|
+
cell: ({ row }) => (
|
|
110
|
+
<ProgressBar value={row.original.quota} status={row.original.status} affix="value" />
|
|
111
|
+
),
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
export const InlineTableCell: Story = {
|
|
116
|
+
name: 'DataTable 儲存格內進度',
|
|
117
|
+
render: () => (
|
|
118
|
+
<div className="flex flex-col gap-4 w-[560px]">
|
|
119
|
+
<SectionTitle>配額使用率(DataTable inline)</SectionTitle>
|
|
120
|
+
<SectionDesc>
|
|
121
|
+
Table cell 內顯示配額使用率(4px 細線不搶走主要欄位的閱讀重量)。value affix 讓使用者快速讀數字。
|
|
122
|
+
</SectionDesc>
|
|
123
|
+
<DataTable columns={quotaColumns} data={quotaRows} getRowId={(r) => r.name} height="auto" />
|
|
124
|
+
</div>
|
|
125
|
+
),
|
|
118
126
|
}
|
|
119
127
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Meta } from '@storybook/react'
|
|
2
2
|
import { useState } from 'react'
|
|
3
3
|
import { RadioGroup, RadioGroupItem } from './radio-group'
|
|
4
|
-
import { SelectionItem } from '@/design-system/components/SelectionControl/selection-item'
|
|
5
4
|
|
|
6
5
|
const meta: Meta = {
|
|
7
6
|
title: 'Design System/Components/RadioGroup/設計規格',
|
|
@@ -287,20 +286,18 @@ const InspectorInner = () => {
|
|
|
287
286
|
{/* Live preview */}
|
|
288
287
|
<div className="px-10 py-8 rounded-lg bg-canvas border border-divider flex items-center justify-center gap-6">
|
|
289
288
|
<RadioGroup defaultValue={checked === 'checked' ? 'preview' : undefined} className="flex gap-4">
|
|
290
|
-
<
|
|
289
|
+
<RadioGroupItem
|
|
291
290
|
size={size}
|
|
292
|
-
|
|
291
|
+
value="preview"
|
|
293
292
|
label="信用卡"
|
|
294
293
|
description={withDescription ? '支援 Visa / Mastercard / JCB,結帳時直接扣款' : undefined}
|
|
295
|
-
htmlFor="preview-radio"
|
|
296
294
|
disabled={state === 'disabled'}
|
|
297
295
|
/>
|
|
298
|
-
<
|
|
296
|
+
<RadioGroupItem
|
|
299
297
|
size={size}
|
|
300
|
-
|
|
298
|
+
value="other"
|
|
301
299
|
label="ATM 轉帳"
|
|
302
300
|
description={withDescription ? '取得虛擬帳號後 3 天內完成付款' : undefined}
|
|
303
|
-
htmlFor="preview-other"
|
|
304
301
|
disabled={state === 'disabled'}
|
|
305
302
|
/>
|
|
306
303
|
</RadioGroup>
|
|
@@ -534,26 +531,9 @@ export const SizeMatrix = {
|
|
|
534
531
|
<div key={sz} className="flex flex-col gap-2">
|
|
535
532
|
<span className="text-[11px] text-fg-muted font-mono">size="{sz}" ({SIZE_SPECS[sz].controlPx}px)</span>
|
|
536
533
|
<RadioGroup defaultValue="a">
|
|
537
|
-
<
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
label="即時"
|
|
541
|
-
htmlFor={`sz-${sz}-a`}
|
|
542
|
-
/>
|
|
543
|
-
<SelectionItem
|
|
544
|
-
size={sz}
|
|
545
|
-
control={<RadioGroupItem value="b" id={`sz-${sz}-b`} size={sz} />}
|
|
546
|
-
label="每日摘要"
|
|
547
|
-
description="每天晚上 9 點寄一次"
|
|
548
|
-
htmlFor={`sz-${sz}-b`}
|
|
549
|
-
/>
|
|
550
|
-
<SelectionItem
|
|
551
|
-
size={sz}
|
|
552
|
-
control={<RadioGroupItem value="c" id={`sz-${sz}-c`} size={sz} disabled />}
|
|
553
|
-
label="每週摘要"
|
|
554
|
-
htmlFor={`sz-${sz}-c`}
|
|
555
|
-
disabled
|
|
556
|
-
/>
|
|
534
|
+
<RadioGroupItem size={sz} value="a" label="即時" />
|
|
535
|
+
<RadioGroupItem size={sz} value="b" label="每日摘要" description="每天晚上 9 點寄一次" />
|
|
536
|
+
<RadioGroupItem size={sz} value="c" label="每週摘要" disabled />
|
|
557
537
|
</RadioGroup>
|
|
558
538
|
</div>
|
|
559
539
|
))}
|
|
@@ -629,8 +609,10 @@ const StateBehaviorInner = () => {
|
|
|
629
609
|
{/* Whole group disabled */}
|
|
630
610
|
<div className="flex flex-col gap-3">
|
|
631
611
|
<span className="text-caption font-medium text-fg-secondary">行為 3:整組 disabled(Field context 接管)</span>
|
|
612
|
+
{/* 架構理由(移出 user-visible Desc,per story-rules.md 人話原則):item 經 useResolvedFieldDisabled
|
|
613
|
+
繼承 Field 的 disabled;SSOT = field-controls.spec.md cascade 段。 */}
|
|
632
614
|
<Desc>
|
|
633
|
-
|
|
615
|
+
整組放進停用的 Field 時,裡面每個選項會自動一起變灰,不需逐一設定。下方為靜態示意(逐 item 傳 disabled 重現相同視覺);實際使用以 {'<Field disabled>'} 包裹即可。
|
|
634
616
|
</Desc>
|
|
635
617
|
<div className="flex gap-6 items-start">
|
|
636
618
|
<div className="px-6 py-5 rounded-lg bg-canvas border border-divider min-w-[280px]">
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @story-trait-rationale: hasSizes 由 anatomy.stories.tsx SizeMatrix auto-compile owns size showcase(2026-05-15 F-migration);Default scenario 由 WithLabel / HorizontalLayout 等真實 form 情境 story 覆蓋。
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
3
3
|
import { RadioGroup, RadioGroupItem } from './radio-group'
|
|
4
|
-
import { SelectionItem } from '@/design-system/components/SelectionControl/selection-item'
|
|
5
4
|
|
|
6
5
|
const meta: Meta<typeof RadioGroupItem> = {
|
|
7
6
|
title: 'Design System/Components/RadioGroup/展示',
|
|
@@ -12,6 +11,10 @@ const meta: Meta<typeof RadioGroupItem> = {
|
|
|
12
11
|
export default meta
|
|
13
12
|
type Story = StoryObj<typeof RadioGroupItem>
|
|
14
13
|
|
|
14
|
+
// 2026-07-14 dim-68 修:展示層原直用 internal <SelectionItem control={...} htmlFor>(selection-item.spec.md
|
|
15
|
+
// 「何時用」明文禁止裸用)→ 收斂為公開 <RadioGroupItem value label description>(自動 wire SelectionItem
|
|
16
|
+
// + id/htmlFor),與同元件 principles / anatomy 層一致 — 三層 story 一律示範公開 API。
|
|
17
|
+
|
|
15
18
|
// @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with display card.
|
|
16
19
|
/* ── 四模式 ── */
|
|
17
20
|
export const Modes: Story = {
|
|
@@ -21,35 +24,35 @@ export const Modes: Story = {
|
|
|
21
24
|
<div>
|
|
22
25
|
<h3 className="text-body font-bold text-foreground mb-2">edit</h3>
|
|
23
26
|
<RadioGroup defaultValue="yearly" aria-label="付款方案(edit mode demo)">
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
+
<RadioGroupItem value="monthly" label="月付方案" />
|
|
28
|
+
<RadioGroupItem value="yearly" label="年付方案" description="每年 $2,990,省下兩個月" />
|
|
29
|
+
<RadioGroupItem value="lifetime" label="終身方案" />
|
|
27
30
|
</RadioGroup>
|
|
28
31
|
</div>
|
|
29
32
|
<div>
|
|
30
33
|
<h3 className="text-body font-bold text-foreground mb-2">display</h3>
|
|
31
34
|
<RadioGroup mode="display" value="yearly" aria-label="付款方案(display mode demo)">
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
+
<RadioGroupItem value="monthly" label="月付方案" />
|
|
36
|
+
<RadioGroupItem value="yearly" label="年付方案" description="每年 $2,990,省下兩個月" />
|
|
37
|
+
<RadioGroupItem value="lifetime" label="終身方案" />
|
|
35
38
|
</RadioGroup>
|
|
36
39
|
</div>
|
|
37
40
|
<div>
|
|
38
41
|
<h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
|
|
39
|
-
<RadioGroup value="yearly" aria-label="付款方案(readonly mode demo)">
|
|
40
|
-
<
|
|
41
|
-
<
|
|
42
|
-
<
|
|
42
|
+
<RadioGroup mode="readonly" value="yearly" aria-label="付款方案(readonly mode demo)">
|
|
43
|
+
<RadioGroupItem value="monthly" label="月付方案" />
|
|
44
|
+
<RadioGroupItem value="yearly" label="年付方案" />
|
|
45
|
+
<RadioGroupItem value="lifetime" label="終身方案" />
|
|
43
46
|
</RadioGroup>
|
|
44
47
|
</div>
|
|
45
48
|
<div>
|
|
46
49
|
<h3 className="text-body font-bold text-foreground mb-2">disabled</h3>
|
|
47
50
|
{/* mode="disabled" → Radix Root disabled 原生 propagate 全 item(radio 控件真停用);
|
|
48
|
-
|
|
51
|
+
RadioGroupDisabledContext 同步讓每個 item 的 label/description 降 text-fg-disabled */}
|
|
49
52
|
<RadioGroup mode="disabled" value="yearly" aria-label="付款方案(disabled mode demo)">
|
|
50
|
-
<
|
|
51
|
-
<
|
|
52
|
-
<
|
|
53
|
+
<RadioGroupItem value="monthly" label="月付方案" />
|
|
54
|
+
<RadioGroupItem value="yearly" label="年付方案" />
|
|
55
|
+
<RadioGroupItem value="lifetime" label="終身方案" />
|
|
53
56
|
</RadioGroup>
|
|
54
57
|
</div>
|
|
55
58
|
</div>
|
|
@@ -58,7 +61,7 @@ export const Modes: Story = {
|
|
|
58
61
|
|
|
59
62
|
// @story-trait-rationale: States retired 2026-05-17 per audit Dim 24 —
|
|
60
63
|
// anatomy.stories.tsx SizeMatrix + StateBehavior own size/state trait grid。
|
|
61
|
-
// 展示層保留 typical real-product Group 情境(Vertical/Horizontal/Modes
|
|
64
|
+
// 展示層保留 typical real-product Group 情境(Vertical/Horizontal/Modes)。
|
|
62
65
|
|
|
63
66
|
/* ── 垂直 Group ── */
|
|
64
67
|
export const VerticalGroup: Story = {
|
|
@@ -69,9 +72,9 @@ export const VerticalGroup: Story = {
|
|
|
69
72
|
<div key={size}>
|
|
70
73
|
<p className="text-caption text-fg-muted mb-1">size="{size}"</p>
|
|
71
74
|
<RadioGroup defaultValue="monthly">
|
|
72
|
-
<
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
+
<RadioGroupItem size={size} value="monthly" label="月付方案" />
|
|
76
|
+
<RadioGroupItem size={size} value="yearly" label="年付方案" description="每年 $2,990,省下兩個月" />
|
|
77
|
+
<RadioGroupItem size={size} value="lifetime" label="終身方案" />
|
|
75
78
|
</RadioGroup>
|
|
76
79
|
</div>
|
|
77
80
|
))}
|
|
@@ -84,20 +87,14 @@ export const Horizontal: Story = {
|
|
|
84
87
|
name: '水平排列',
|
|
85
88
|
render: () => (
|
|
86
89
|
<RadioGroup defaultValue="light" className="flex gap-6 max-w-md">
|
|
87
|
-
<
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
+
<RadioGroupItem value="light" label="淺色" />
|
|
91
|
+
<RadioGroupItem value="dark" label="深色" />
|
|
92
|
+
<RadioGroupItem value="system" label="系統" />
|
|
90
93
|
</RadioGroup>
|
|
91
94
|
),
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<RadioGroup defaultValue="bank" className="max-w-sm">
|
|
99
|
-
<SelectionItem control={<RadioGroupItem value="bank" id="dis-a" disabled />} label="銀行轉帳" description="帳單已開立,付款方式鎖定" htmlFor="dis-a" disabled />
|
|
100
|
-
<SelectionItem control={<RadioGroupItem value="invoice" id="dis-b" disabled />} label="月結發票" description="需企業方案才能使用" htmlFor="dis-b" disabled />
|
|
101
|
-
</RadioGroup>
|
|
102
|
-
),
|
|
103
|
-
}
|
|
97
|
+
// @story-trait-rationale: Disabled retired 2026-07-14 per audit Dim 24 —
|
|
98
|
+
// disabled 覆蓋已由 Modes story 的 disabled 列 + anatomy StateBehavior
|
|
99
|
+
// 「Mutual Exclusion + Disabled Item Matrix」owns;對齊 Checkbox / Switch
|
|
100
|
+
// 同 Family 已 retire 的獨立 Disabled story。
|
|
@@ -10,7 +10,8 @@ import { useFieldContext, useResolvedFieldMode, useResolvedFieldDisabled, useRes
|
|
|
10
10
|
import { SelectionItem } from "@/design-system/components/SelectionControl/selection-item"
|
|
11
11
|
import type { LucideIcon } from "lucide-react"
|
|
12
12
|
import type { AvatarData } from "@/design-system/components/Avatar/avatar"
|
|
13
|
-
import {
|
|
13
|
+
import { fieldWrapperStyles } from "@/design-system/components/Field/field-wrapper"
|
|
14
|
+
import { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'
|
|
14
15
|
|
|
15
16
|
// ── RadioGroup display mode ─────────────────────────────────────────────────
|
|
16
17
|
// RadioGroup mode='display' 時:Group 不渲染 Radix primitive(無 radio 視覺),
|
|
@@ -44,6 +45,11 @@ export interface RadioGroupProps
|
|
|
44
45
|
// (item 已支援 readOnly prop + data-[readonly] 樣式;Radix Root 無 readOnly,故用 context)。
|
|
45
46
|
const RadioGroupReadonlyContext = React.createContext(false)
|
|
46
47
|
|
|
48
|
+
// group-level disabled(standalone <RadioGroup disabled>)→ context 傳給 items,讓 SelectionItem
|
|
49
|
+
// label/description 也降 text-fg-disabled(Radix Root disabled 只 propagate 給 radio 圈、不碰 label 色)。
|
|
50
|
+
// 對齊本檔 RadioGroupReadonlyContext 既有模式 + spec「Disabled」邊界案例(Group-level disabled 視覺繼承 SelectionItem SSOT text-fg-disabled)。
|
|
51
|
+
const RadioGroupDisabledContext = React.createContext(false)
|
|
52
|
+
|
|
47
53
|
// walk children 找 control.value === selectedValue 的 SelectionItem label(display / readonly-in-Field 共用)
|
|
48
54
|
function findSelectedRadioLabel(children: React.ReactNode, selectedValue: string | undefined): React.ReactNode {
|
|
49
55
|
let selectedLabel: React.ReactNode = null
|
|
@@ -73,6 +79,7 @@ const RadioGroup = React.forwardRef<
|
|
|
73
79
|
>(({ className, mode, variant: _chrome, value, defaultValue, ...props }, ref) => {
|
|
74
80
|
// 2026-06-08 SSOT cascade:resolvedMode 經 resolver hook 讀 fieldCtx(原 root 完全不讀 → <Field disabled>/<Field mode> 失效)
|
|
75
81
|
const resolvedMode = useResolvedFieldMode({ mode, disabled: (props as { disabled?: boolean }).disabled })
|
|
82
|
+
const emptyDisplay = useFieldEmptyDisplay()
|
|
76
83
|
const fieldCtx = useFieldContext()
|
|
77
84
|
// readonly 灰框 size:走 SSOT resolver(RadioGroup 無 size prop → ctx > 'md')
|
|
78
85
|
const resolvedBoxSize = useResolvedFieldSize(undefined, 'md') as 'sm' | 'md' | 'lg'
|
|
@@ -100,7 +107,7 @@ const RadioGroup = React.forwardRef<
|
|
|
100
107
|
if (resolvedMode === 'display') {
|
|
101
108
|
const selectedValue = (value ?? defaultValue) as string | undefined
|
|
102
109
|
if (!selectedValue) {
|
|
103
|
-
return <div {...restDomProps} ref={ref as React.Ref<HTMLDivElement>} role="group" className={cn('grid', className)}><span className=
|
|
110
|
+
return <div {...restDomProps} ref={ref as React.Ref<HTMLDivElement>} role="group" className={cn('grid', className)}><span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span></div>
|
|
104
111
|
}
|
|
105
112
|
const selectedLabel = findSelectedRadioLabel(props.children, selectedValue)
|
|
106
113
|
return (
|
|
@@ -136,7 +143,7 @@ const RadioGroup = React.forwardRef<
|
|
|
136
143
|
>
|
|
137
144
|
{selectedValue
|
|
138
145
|
? <span className="text-foreground">{selectedLabel ?? selectedValue}</span>
|
|
139
|
-
: <span className=
|
|
146
|
+
: <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>}
|
|
140
147
|
</div>
|
|
141
148
|
)
|
|
142
149
|
}
|
|
@@ -145,20 +152,34 @@ const RadioGroup = React.forwardRef<
|
|
|
145
152
|
// mode='readonly' → context 傳 readOnly 給 items(item 渲染為 data-[readonly] 鎖互動 + aria-readonly)。
|
|
146
153
|
return (
|
|
147
154
|
<RadioGroupReadonlyContext.Provider value={resolvedMode === 'readonly'}>
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
<RadioGroupDisabledContext.Provider value={resolvedMode === 'disabled'}>
|
|
156
|
+
<RadioGroupPrimitive.Root
|
|
157
|
+
className={cn("grid", className)}
|
|
158
|
+
value={value}
|
|
159
|
+
defaultValue={defaultValue}
|
|
160
|
+
// Field 內:role="radiogroup" 的 <div> 無法被 <label for> 命名 → 自讀 fieldCtx 接
|
|
161
|
+
// aria-labelledby / aria-invalid / aria-describedby(field-context.ts「下游 control 需自讀
|
|
162
|
+
// labelId」;對齊 slider.tsx / Rating / TimePicker 的 fieldLabelId 接線 + 上方 readonly-in-Field 分支)。
|
|
163
|
+
// standalone(無 Field)時皆 undefined,consumer 的 {...props} aria-* 照舊生效(置於 spread 前故可被覆蓋)。
|
|
164
|
+
aria-labelledby={fieldCtx?.labelId}
|
|
165
|
+
aria-invalid={fieldCtx?.invalid || undefined}
|
|
166
|
+
aria-describedby={fieldCtx?.descriptionId}
|
|
167
|
+
// a11y(2026-07-14 dim-10):readonly 語意放 radiogroup(aria-readonly 合法 role;
|
|
168
|
+
// 對齊上方 readonly-in-Field 分支 L133)。item(role=radio)不帶 aria-readonly —
|
|
169
|
+
// axe 實證 radio 不允許該屬性,item 靠 data-readonly + tabIndex + click guard 鎖互動。
|
|
170
|
+
aria-readonly={resolvedMode === 'readonly' || undefined}
|
|
171
|
+
{...props}
|
|
172
|
+
disabled={resolvedMode === 'disabled'}
|
|
173
|
+
ref={ref}
|
|
174
|
+
/>
|
|
175
|
+
</RadioGroupDisabledContext.Provider>
|
|
156
176
|
</RadioGroupReadonlyContext.Provider>
|
|
157
177
|
)
|
|
158
178
|
})
|
|
159
179
|
RadioGroup.displayName = 'RadioGroup'
|
|
160
180
|
// Field layout 宣告:RadioGroup 是 block primitive(多項堆疊),
|
|
161
|
-
// 進入 <Field> 時 control area 自動切 items-start
|
|
181
|
+
// 進入 <Field> 時 control area 自動切 items-start(block 分支不設 min-h、不加 padding-top,
|
|
182
|
+
// 高度由內容決定;額外加 paddingTop 會 double padding — field.tsx block control area SSOT)。
|
|
162
183
|
// Convention 詳見 components/Field/field.spec.md「Control area:Inline vs Block」段落。
|
|
163
184
|
;(RadioGroup as unknown as { fieldLayout: 'block' }).fieldLayout = 'block'
|
|
164
185
|
|
|
@@ -261,7 +282,10 @@ const RadioGroupItem = React.forwardRef<
|
|
|
261
282
|
// RadioGroupItem 的 label 是「該選項」的 label(每 item 各自擁有),
|
|
262
283
|
// FieldLabel 則是整個 RadioGroup 的 label。
|
|
263
284
|
// 因此 RadioGroupItem 的 label 不因 Field context 被忽略。
|
|
264
|
-
|
|
285
|
+
// group-level disabled(standalone <RadioGroup disabled>)也要降 label/description 色 —— Radix Root
|
|
286
|
+
// disabled 只 propagate 給 radio 圈,label 色由 SelectionItem disabled 決定,故讀 RadioGroupDisabledContext 補上。
|
|
287
|
+
const groupDisabled = React.useContext(RadioGroupDisabledContext)
|
|
288
|
+
const resolvedDisabled = useResolvedFieldDisabled(disabled) || groupDisabled
|
|
265
289
|
// group-level readonly(RadioGroup mode='readonly')或 item-level readOnly,任一 true 即鎖互動。
|
|
266
290
|
const groupReadonly = React.useContext(RadioGroupReadonlyContext)
|
|
267
291
|
const effectiveReadonly = readOnly || groupReadonly
|
|
@@ -274,7 +298,9 @@ const RadioGroupItem = React.forwardRef<
|
|
|
274
298
|
id={inputId}
|
|
275
299
|
ref={ref}
|
|
276
300
|
disabled={resolvedDisabled}
|
|
277
|
-
aria-readonly
|
|
301
|
+
// a11y(2026-07-14 dim-10):item(role=radio)不帶 aria-readonly — axe 實證 radio 不允許
|
|
302
|
+
// 該屬性(readonly 語意由 Root role=radiogroup 宣告,見上方 L167-170)。item 靠
|
|
303
|
+
// data-readonly + tabIndex + click guard 鎖互動。
|
|
278
304
|
data-readonly={effectiveReadonly || undefined}
|
|
279
305
|
tabIndex={effectiveReadonly ? -1 : undefined}
|
|
280
306
|
className={cn(radioItemVariants({ size }), className)}
|
|
@@ -331,7 +357,7 @@ export const radioGroupMeta = {
|
|
|
331
357
|
},
|
|
332
358
|
sizes: {
|
|
333
359
|
// iconSize = 渲染指示器尺寸(對齊 checkbox/switch meta 慣例:checkbox iconSize=真 Check glyph 12/12/16)。
|
|
334
|
-
// Radio 指示器是 filled dot 非 glyph,真值 = dotSize 8/8/10
|
|
360
|
+
// Radio 指示器是 filled dot 非 glyph,真值 = 上方 `const dotSize` map 8/8/10;
|
|
335
361
|
// 控件框 16/16/20 與 Checkbox 對齊但那是 box 非「指示器」,不入此鍵(避免 metadata 語意 drift)。
|
|
336
362
|
sm: { fieldHeight: 28, iconSize: 8, typography: 'body' },
|
|
337
363
|
md: { fieldHeight: 32, iconSize: 8, typography: 'body' },
|