@qijenchen/design-system 0.1.0-beta.82 → 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 +37 -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 +17 -5
- 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 +36 -0
- package/ds-canonical/fork/hooks/check_story_determinism.sh +39 -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 +20 -0
- package/ds-canonical/fork/preamble.md +22 -18
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +9 -3
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
- package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +7 -0
- package/ds-canonical/fork/skills/performance-audit/SKILL.md +4 -2
- 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 +10 -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_benchmark_citation.sh +5 -3
- 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 +17 -5
- 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 +36 -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_propose_without_benchmark.sh +6 -2
- package/ds-canonical/hooks/check_ssot_header_declaration.sh +55 -0
- package/ds-canonical/hooks/check_story_determinism.sh +39 -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_benchmark_citation.sh +3 -3
- 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_fork_user_plugin_install.sh +3 -1
- package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +41 -2
- package/ds-canonical/hooks/tests/test_check_ssot_header_declaration.sh +72 -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/spec-rules.md +1 -1
- package/ds-canonical/rules/story-rules.md +2 -2
- package/ds-canonical/rules/ui-development.md +4 -2
- package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +9 -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 +57 -68
- 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 +5 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +27 -26
- 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 +2 -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 +7 -5
- package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
- package/ds-canonical/skills/performance-audit/SKILL.md +2 -2
- 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 +10 -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 +14 -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
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { X, Calendar as CalendarIcon, ArrowRight } from 'lucide-react'
|
|
5
5
|
import { cn } from '@/lib/utils'
|
|
6
|
-
import type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'
|
|
7
|
-
import { fieldWrapperStyles, bareInputStyles,
|
|
6
|
+
import type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'
|
|
7
|
+
import { fieldWrapperStyles, bareInputStyles, nakedCellRowModeAlign, fieldDisplayTextClass } from '@/design-system/components/Field/field-wrapper'
|
|
8
8
|
import { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
9
9
|
import { Popover, PopoverTrigger, PopoverAnchor, PopoverContent } from '@/design-system/components/Popover/popover'
|
|
10
10
|
import { DateGrid } from '@/design-system/components/DateGrid/date-grid'
|
|
11
11
|
import { Button } from '@/design-system/components/Button/button'
|
|
12
12
|
import { SurfaceFooter } from '@/design-system/patterns/overlay-surface/overlay-surface'
|
|
13
|
-
import { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid } from '@/design-system/components/Field/field-context'
|
|
13
|
+
import { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'
|
|
14
14
|
import {
|
|
15
15
|
TimeColumns,
|
|
16
16
|
isoToTimeParts,
|
|
@@ -53,7 +53,15 @@ function formatDate(
|
|
|
53
53
|
value: string | number | Date,
|
|
54
54
|
options: DateFormatOptions = {},
|
|
55
55
|
): string {
|
|
56
|
-
|
|
56
|
+
// TZ-safe:date-only / datetime ISO string 走 isoToDate(local-time 語意,new Date(y,m-1,d))
|
|
57
|
+
// 而非 new Date('YYYY-MM-DD')(ECMAScript 以 UTC 解析 → 負時區 off-by-one,如 LA 顯前一天)。
|
|
58
|
+
// 非 ISO string(RFC 'Mar 12 2025' 等)fallback new Date();number timestamp 直接 new Date()。
|
|
59
|
+
const date =
|
|
60
|
+
value instanceof Date
|
|
61
|
+
? value
|
|
62
|
+
: typeof value === 'string'
|
|
63
|
+
? (isoToDate(value) ?? new Date(value))
|
|
64
|
+
: new Date(value)
|
|
57
65
|
if (Number.isNaN(date.getTime())) return String(value)
|
|
58
66
|
// 若 consumer 顯式傳 formatOptions / locale → 走 Intl.DateTimeFormat
|
|
59
67
|
if (options.formatOptions || options.locale) {
|
|
@@ -103,11 +111,11 @@ function isoToDate(iso: string | null | undefined): Date | undefined {
|
|
|
103
111
|
* 或 ISO datetime(YYYY-MM-DDTHH:MM[:SS])。
|
|
104
112
|
*
|
|
105
113
|
* 支援 format(per Material X DatePicker / Ant DatePicker typed input idiom):
|
|
106
|
-
* - `YYYY-MM-DD` / `YYYY/MM/DD` / `YYYY.MM.DD`(ISO + 慣例 separator)
|
|
107
|
-
* - `MM/DD/YYYY` / `MM-DD-YYYY`(US locale)
|
|
108
|
-
* - `DD/MM/YYYY` / `DD-MM-YYYY`(EU locale)
|
|
114
|
+
* - `YYYY-MM-DD` / `YYYY/MM/DD` / `YYYY.MM.DD`(ISO + 慣例 separator,明確 parse branch)
|
|
109
115
|
* - `YYYY-MM-DD HH:MM[:SS]` / `YYYY-MM-DDTHH:MM[:SS]`(datetime,showTime 才接)
|
|
110
|
-
* - native `Date.parse()` fallback(handle 'Mar 12 2025' 等英文 RFC)
|
|
116
|
+
* - native `Date.parse()` fallback(handle 'Mar 12 2025' 等英文 RFC;US `MM/DD/YYYY` 亦由此判讀,ambiguous)
|
|
117
|
+
* ⚠️ 不支援 EU `DD/MM/YYYY`:無專屬 parser branch;native Date.parse 把 slash 日期當 US MM/DD,
|
|
118
|
+
* `31/12/2026`(月 > 12)直接 Invalid。v1 known-gap,需 EU 請走 formatOptions/locale 或另加 parser branch。
|
|
111
119
|
*
|
|
112
120
|
* Return:`{ iso, valid }`。Invalid → `valid=false` + `iso=null`,UI 顯 aria-invalid。
|
|
113
121
|
* Partial input(打到一半)→ valid=false 但不顯 error UI(consumer 用 onBlur / Enter 才檢驗)。
|
|
@@ -123,6 +131,9 @@ function parseDateInput(input: string, opts: { allowTime: boolean }): { iso: str
|
|
|
123
131
|
const [, y, m, d, hh, mm, ss] = isoDateMatch
|
|
124
132
|
const date = new Date(Number(y), Number(m) - 1, Number(d), Number(hh ?? 0), Number(mm ?? 0), Number(ss ?? 0))
|
|
125
133
|
if (isNaN(date.getTime()) || date.getMonth() !== Number(m) - 1) return { iso: null, valid: false }
|
|
134
|
+
// time 分量越界校驗:JS Date 會 silently normalize(25:99:99 → 隔日某時,getTime 仍 valid、
|
|
135
|
+
// getMonth 未必變),但回傳 iso 用的是原始越界字串 → 需在此擋掉 hh>23 / mm>59 / ss>59。
|
|
136
|
+
if (hh != null && (Number(hh) > 23 || Number(mm) > 59 || Number(ss ?? 0) > 59)) return { iso: null, valid: false }
|
|
126
137
|
const datePart = dateToIso(date)
|
|
127
138
|
if (hh != null && opts.allowTime) {
|
|
128
139
|
const h2 = String(Number(hh)).padStart(2, '0')
|
|
@@ -290,6 +301,9 @@ export interface DatePickerProps
|
|
|
290
301
|
mode?: FieldMode
|
|
291
302
|
/** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */
|
|
292
303
|
variant?: FieldVariant
|
|
304
|
+
/** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮(value 寬 + slot 寬 + gap + 內 padding);
|
|
305
|
+
* chrome 與互動不變。SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */
|
|
306
|
+
width?: FieldWidth
|
|
293
307
|
error?: boolean
|
|
294
308
|
size?: 'sm' | 'md' | 'lg'
|
|
295
309
|
/** ISO date(YYYY-MM-DD)或 ISO datetime(YYYY-MM-DDTHH:MM:SS,當 showTime=true) */
|
|
@@ -362,6 +376,7 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
362
376
|
{
|
|
363
377
|
mode,
|
|
364
378
|
variant: variantProp,
|
|
379
|
+
width,
|
|
365
380
|
error: errorProp = false,
|
|
366
381
|
size: sizeProp,
|
|
367
382
|
value,
|
|
@@ -396,7 +411,8 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
396
411
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
397
412
|
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="display"> 漏 cascade
|
|
398
413
|
const resolvedMode = useResolvedFieldMode({ mode, disabled })
|
|
399
|
-
const
|
|
414
|
+
const emptyDisplay = useFieldEmptyDisplay()
|
|
415
|
+
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
400
416
|
const isEditable = resolvedMode === 'edit'
|
|
401
417
|
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
|
|
402
418
|
const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
@@ -408,11 +424,14 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
408
424
|
// a11y:role="combobox" 必須有 accessible name(aria-label / labelledby / fieldCtx label)
|
|
409
425
|
const accessibleName = ariaLabelProp ?? (ariaLabelledByProp ? undefined : (fieldCtx?.id ? undefined : resolvedPlaceholder))
|
|
410
426
|
|
|
411
|
-
// Sync draft from value
|
|
412
|
-
// clobber user
|
|
427
|
+
// Sync draft from value:closed 期間恆跟隨 + open false→true 同步(避免 popover 開啟期間
|
|
428
|
+
// value 改變 clobber user 的編輯)。
|
|
429
|
+
// 2026-07-14 audit Dim 26(V4 state shadow):needConfirm trigger 讀 draft,原「只在 false→true
|
|
430
|
+
// 同步」使 controlled value 於關閉期間更新後,trigger 仍顯示舊值直到再次開啟 —— 改為
|
|
431
|
+
// 只要 open=false 就同步(與 range picker 分支 L83x 同款 canonical)。
|
|
413
432
|
const lastOpenRef = React.useRef(open)
|
|
414
433
|
React.useEffect(() => {
|
|
415
|
-
if (!lastOpenRef.current
|
|
434
|
+
if (!open || !lastOpenRef.current) setDraft(value ?? null)
|
|
416
435
|
lastOpenRef.current = open
|
|
417
436
|
}, [open, value])
|
|
418
437
|
|
|
@@ -464,16 +483,16 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
464
483
|
if (!showDisplayEndIcon) {
|
|
465
484
|
// 2026-05-14 I2 fix(spec contract (e) display typography canonical):bare span 套
|
|
466
485
|
// `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)— 對齊 Field family 統一。
|
|
467
|
-
if (!value) return <span className={cn(fieldDisplayTextClass(size),
|
|
486
|
+
if (!value) return <span className={cn(fieldDisplayTextClass(size), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
|
|
468
487
|
return <span className={cn(fieldDisplayTextClass(size), 'truncate', className)}>{displayCommitted}</span>
|
|
469
488
|
}
|
|
470
489
|
return (
|
|
471
490
|
<div
|
|
472
|
-
className={cn(fieldWrapperStyles({ mode: 'display', variant, size }), className)}
|
|
491
|
+
className={cn(fieldWrapperStyles({ mode: 'display', variant, width, size }), className)}
|
|
473
492
|
data-field-mode="display"
|
|
474
493
|
>
|
|
475
|
-
<span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value &&
|
|
476
|
-
{value ? displayCommitted :
|
|
494
|
+
<span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && fieldEmptyColorClass(resolvedMode))}>
|
|
495
|
+
{value ? displayCommitted : emptyDisplay}
|
|
477
496
|
</span>
|
|
478
497
|
<ItemSuffix className="pointer-events-none">
|
|
479
498
|
<CalendarIcon size={iconSize} className="text-fg-muted" aria-hidden />
|
|
@@ -486,7 +505,7 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
486
505
|
if (!isEditable) {
|
|
487
506
|
return (
|
|
488
507
|
<div
|
|
489
|
-
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}
|
|
508
|
+
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, width, size }), className)}
|
|
490
509
|
data-field-mode={resolvedMode}
|
|
491
510
|
aria-disabled={resolvedMode === 'disabled' ? true : undefined}
|
|
492
511
|
{...(props as React.HTMLAttributes<HTMLDivElement>)}
|
|
@@ -494,7 +513,7 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
494
513
|
<span className={cn('flex-1 min-w-0 truncate', resolvedMode === 'disabled' && 'text-fg-disabled')}>
|
|
495
514
|
{value
|
|
496
515
|
? displayCommitted
|
|
497
|
-
: <span className=
|
|
516
|
+
: <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>
|
|
498
517
|
}
|
|
499
518
|
</span>
|
|
500
519
|
{/* 2026-06-26 類型身份 indicator:edit 顯示 / readonly 不顯示(純值、不可開) / disabled 保留(fg-disabled,對齊原生 <select disabled>);
|
|
@@ -527,18 +546,22 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
527
546
|
<PopoverTrigger asChild>
|
|
528
547
|
<div
|
|
529
548
|
ref={ref}
|
|
530
|
-
|
|
531
|
-
role
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
aria-
|
|
538
|
-
aria-
|
|
539
|
-
aria-
|
|
540
|
-
aria-
|
|
541
|
-
aria-
|
|
549
|
+
// a11y(2026-07-14 dim-10 修):typeable 模式 combobox 語意(name / state / 鍵盤)
|
|
550
|
+
// 集中在內層 <input>(APG editable-combobox idiom)— 外層 div 移除 role / tabIndex
|
|
551
|
+
// / aria-*,否則形成「關掉鍵盤 handler 的假 combobox tab stop」+ 內層 input 變成
|
|
552
|
+
// 第二個未命名 tab stop(雙重焦點站)。非 typeable 維持原 div-as-combobox canonical。
|
|
553
|
+
id={typeable ? undefined : (idProp ?? fieldCtx?.id)}
|
|
554
|
+
role={typeable ? undefined : 'combobox'}
|
|
555
|
+
tabIndex={typeable ? undefined : (disabled ? -1 : 0)}
|
|
556
|
+
aria-disabled={typeable ? undefined : (disabled || undefined)}
|
|
557
|
+
aria-label={typeable ? undefined : accessibleName}
|
|
558
|
+
aria-labelledby={typeable ? undefined : (ariaLabelledByProp ?? fieldCtx?.labelId)}
|
|
559
|
+
aria-invalid={typeable ? undefined : (error || undefined)}
|
|
560
|
+
aria-required={typeable ? undefined : (fieldCtx?.required || undefined)}
|
|
561
|
+
aria-describedby={typeable ? undefined : (ariaDescribedByProp ?? fieldCtx?.descriptionId)}
|
|
562
|
+
aria-errormessage={typeable ? undefined : (ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined))}
|
|
563
|
+
aria-haspopup={typeable ? undefined : 'dialog'}
|
|
564
|
+
aria-expanded={typeable ? undefined : open}
|
|
542
565
|
data-field-mode="edit"
|
|
543
566
|
data-error={error ? '' : undefined}
|
|
544
567
|
// Radix PopoverTrigger 只 compose onClick(onOpenToggle),`<div>` trigger 無
|
|
@@ -551,7 +574,7 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
551
574
|
if (e.key === 'Escape') setOpen(false)
|
|
552
575
|
}}
|
|
553
576
|
className={cn(
|
|
554
|
-
fieldWrapperStyles({ mode: 'edit', variant: variant, size, error }),
|
|
577
|
+
fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }),
|
|
555
578
|
'text-left cursor-pointer',
|
|
556
579
|
'focus-visible:outline-none',
|
|
557
580
|
className,
|
|
@@ -562,8 +585,21 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
562
585
|
// Issue 10 typed input(2026-05-10):real `<input>` 接 user 鍵盤打字。
|
|
563
586
|
// Click 在 input 上不 propagate 給外層 popover trigger(避免每次打字都開 popover)。
|
|
564
587
|
// Calendar icon `<ItemSuffix>` 點才開 popover(Material/Ant typed-date idiom)。
|
|
588
|
+
// a11y(2026-07-14 dim-10 修):input 持完整 combobox 語意(id/name/state,APG
|
|
589
|
+
// editable-combobox)— 外層 div 已讓位(見上方 role/tabIndex 註解);ArrowDown
|
|
590
|
+
// 開 popover 補鍵盤開啟路徑(原僅 icon click 可開,鍵盤 user 無入口)。
|
|
565
591
|
<input
|
|
566
592
|
type="text"
|
|
593
|
+
id={idProp ?? fieldCtx?.id}
|
|
594
|
+
role="combobox"
|
|
595
|
+
aria-haspopup="dialog"
|
|
596
|
+
aria-expanded={open}
|
|
597
|
+
aria-label={accessibleName}
|
|
598
|
+
aria-labelledby={ariaLabelledByProp ?? fieldCtx?.labelId}
|
|
599
|
+
aria-required={fieldCtx?.required || undefined}
|
|
600
|
+
aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}
|
|
601
|
+
aria-errormessage={ariaErrorMessageProp ?? ((inputInvalid || error) ? fieldCtx?.errorId : undefined)}
|
|
602
|
+
disabled={disabled}
|
|
567
603
|
className={cn(bareInputStyles, 'truncate', !inputDraft && 'placeholder:text-fg-muted')}
|
|
568
604
|
value={inputDraft}
|
|
569
605
|
placeholder={resolvedPlaceholder}
|
|
@@ -575,6 +611,7 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
575
611
|
if (composingRef.current) return
|
|
576
612
|
if (e.key === 'Enter') { e.preventDefault(); handleInputCommit(inputDraft) }
|
|
577
613
|
if (e.key === 'Escape') { setInputDraft(displayLive); setInputInvalid(false); e.preventDefault() }
|
|
614
|
+
if (e.key === 'ArrowDown' && !open) { e.preventDefault(); setOpen(true) }
|
|
578
615
|
}}
|
|
579
616
|
onBlur={() => { if (!composingRef.current) handleInputCommit(inputDraft) }}
|
|
580
617
|
onClick={(e) => e.stopPropagation()}
|
|
@@ -607,12 +644,18 @@ const DatePicker = React.forwardRef<HTMLDivElement, DatePickerProps>(
|
|
|
607
644
|
</ItemSuffix>
|
|
608
645
|
</div>
|
|
609
646
|
</PopoverTrigger>
|
|
610
|
-
<PopoverContent
|
|
611
|
-
|
|
612
|
-
|
|
647
|
+
<PopoverContent
|
|
648
|
+
className="w-auto p-0"
|
|
649
|
+
align="start"
|
|
650
|
+
aria-label="日期選擇" // i18n-allow: DS default dialog label
|
|
651
|
+
>
|
|
652
|
+
{/* a11y(2026-07-14 dim-10 修):Radix PopoverContent 自帶 role="dialog"(popover.tsx:58)
|
|
653
|
+
— 內層 div 原本重複 role="dialog" 形成雙層 nested unnamed dialog,改為純 layout div,
|
|
654
|
+
accessible name 收斂到外層 PopoverContent aria-label(單一 dialog 層)。
|
|
655
|
+
2026-05-06 v9.1:`flex flex-col flex-1 min-h-0` 完成 M25 chain — viewport
|
|
613
656
|
壓縮時 dialog 縮 + 內 calendar/footer 排序;原無 chain 致 calendar 末行被
|
|
614
657
|
overflow-hidden 切掉、footer 推出 popover(user 報「位置改變就壞掉」根因)。 */}
|
|
615
|
-
<div
|
|
658
|
+
<div className="flex flex-col flex-1 min-h-0">
|
|
616
659
|
{/* Calendar 區包 overflow-y-auto:viewport 壓縮時 calendar 內滾(Material / Carbon
|
|
617
660
|
date picker idiom)。footer 永遠 in-view(SurfaceFooter shrink-0)。 */}
|
|
618
661
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
@@ -704,6 +747,9 @@ export interface DatePickerRangeProps
|
|
|
704
747
|
mode?: FieldMode
|
|
705
748
|
/** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */
|
|
706
749
|
variant?: FieldVariant
|
|
750
|
+
/** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮(value 寬 + slot 寬 + gap + 內 padding);
|
|
751
|
+
* chrome 與互動不變。SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */
|
|
752
|
+
width?: FieldWidth
|
|
707
753
|
error?: boolean
|
|
708
754
|
size?: 'sm' | 'md' | 'lg'
|
|
709
755
|
/** 區間值:[start ISO, end ISO]。任一 null 代表尚未選。 */
|
|
@@ -728,6 +774,7 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
728
774
|
{
|
|
729
775
|
mode,
|
|
730
776
|
variant: variantProp,
|
|
777
|
+
width,
|
|
731
778
|
error: errorProp = false,
|
|
732
779
|
size: sizeProp,
|
|
733
780
|
value,
|
|
@@ -756,7 +803,8 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
756
803
|
const disabled = useResolvedFieldDisabled(disabledProp)
|
|
757
804
|
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="display"> 漏 cascade
|
|
758
805
|
const resolvedMode = useResolvedFieldMode({ mode, disabled })
|
|
759
|
-
const
|
|
806
|
+
const emptyDisplay = useFieldEmptyDisplay()
|
|
807
|
+
const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
|
|
760
808
|
const isEditable = resolvedMode === 'edit'
|
|
761
809
|
// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
|
|
762
810
|
const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
|
|
@@ -778,12 +826,15 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
778
826
|
const endBtnRef = React.useRef<HTMLButtonElement>(null)
|
|
779
827
|
const hasInteractedOutsideRef = React.useRef(false)
|
|
780
828
|
|
|
781
|
-
//
|
|
782
|
-
//
|
|
783
|
-
//
|
|
829
|
+
// Draft sync canonical(2026-07-14 dim-26 V4 修,升級 2026-05-02 v3):
|
|
830
|
+
// - open=false(關閉期間):controlled value 變更**必**同步 draft — needConfirm 顯示層讀
|
|
831
|
+
// draft(startIso/endIso),不同步會讓 trigger 持續顯示 stale 舊區間(外部 controlled
|
|
832
|
+
// update 被凍結)。關閉期間無編輯進行,直接鏡射無 clobber 風險。
|
|
833
|
+
// - open=true(開啟期間):只在 false→true 轉換時 seed 一次;開啟中 value reference 變更
|
|
834
|
+
// 不覆寫,保護 user 尚未確認的 draft 編輯(原 v3 canonical 保留)。
|
|
784
835
|
const lastOpenRef = React.useRef(open)
|
|
785
836
|
React.useEffect(() => {
|
|
786
|
-
if (!lastOpenRef.current
|
|
837
|
+
if (!open || !lastOpenRef.current) setDraft(value ?? [null, null])
|
|
787
838
|
lastOpenRef.current = open
|
|
788
839
|
}, [open, value])
|
|
789
840
|
|
|
@@ -888,7 +939,7 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
888
939
|
// mode='display'(Phase B2 2026-05-05):純內容輸出 — 無 Field wrapper / 無 Calendar icon。
|
|
889
940
|
if (resolvedMode === 'display') {
|
|
890
941
|
const hasAny = !!(startIso || endIso)
|
|
891
|
-
if (!hasAny) return <span className={cn(
|
|
942
|
+
if (!hasAny) return <span className={cn(fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
|
|
892
943
|
return (
|
|
893
944
|
<span className={cn('inline-flex items-center min-w-0', nakedCellRowModeAlign, className)}>
|
|
894
945
|
<span className={cn('truncate', !startIso && 'text-fg-muted')}>
|
|
@@ -907,7 +958,7 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
907
958
|
return (
|
|
908
959
|
<div
|
|
909
960
|
ref={ref}
|
|
910
|
-
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, size }), className)}
|
|
961
|
+
className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: variant, width, size }), className)}
|
|
911
962
|
data-field-mode={resolvedMode}
|
|
912
963
|
aria-disabled={resolvedMode === 'disabled' ? true : undefined}
|
|
913
964
|
{...props}
|
|
@@ -943,7 +994,7 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
943
994
|
data-error={error ? '' : undefined}
|
|
944
995
|
data-state={open ? 'open' : 'closed'}
|
|
945
996
|
className={cn(
|
|
946
|
-
fieldWrapperStyles({ mode: 'edit', size, error }),
|
|
997
|
+
fieldWrapperStyles({ mode: 'edit', width, size, error }),
|
|
947
998
|
'cursor-text',
|
|
948
999
|
className,
|
|
949
1000
|
)}
|
|
@@ -1002,6 +1053,7 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
1002
1053
|
<PopoverContent
|
|
1003
1054
|
className="w-auto p-0"
|
|
1004
1055
|
align="start"
|
|
1056
|
+
aria-label="日期區間選擇" // i18n-allow: DS default dialog label
|
|
1005
1057
|
// 2026-07-05 D4 focus 回復(機制詳 :758 comment):outside-click 標記不搶焦(鏡射
|
|
1006
1058
|
// Radix non-modal 自家 hasInteractedOutside guard);其餘關閉路徑(Esc / 確定 /
|
|
1007
1059
|
// 選完自動關)preventDefault 掉內建 triggerRef.focus()(Anchor-only 恆 null no-op)
|
|
@@ -1015,8 +1067,10 @@ const DatePickerRange = React.forwardRef<HTMLDivElement, DatePickerRangeProps>(
|
|
|
1015
1067
|
hasInteractedOutsideRef.current = false
|
|
1016
1068
|
}}
|
|
1017
1069
|
>
|
|
1018
|
-
{/* 2026-
|
|
1019
|
-
|
|
1070
|
+
{/* a11y(2026-07-14 dim-10 修):accessible name 收斂到外層 PopoverContent(Radix 自帶
|
|
1071
|
+
role="dialog")— 原內層第二個 role="dialog" 移除,避免 nested dialog 且外層 dialog 無名。
|
|
1072
|
+
2026-05-06 v9.1 M25 chain — 同 single DatePicker 修法,viewport 壓縮 calendar 內滾 + footer 永遠 in-view */}
|
|
1073
|
+
<div className="flex flex-col flex-1 min-h-0">
|
|
1020
1074
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
1021
1075
|
<CalendarTimeContainer
|
|
1022
1076
|
showTime={showTime}
|
|
@@ -156,23 +156,23 @@ export const StateBehavior: Story = {
|
|
|
156
156
|
render: () => (
|
|
157
157
|
<div className="flex flex-col gap-10">
|
|
158
158
|
<div>
|
|
159
|
-
<H3>空值呈現 —
|
|
159
|
+
<H3>空值呈現 — 一律用半形 `-` 字元(hyphen)</H3>
|
|
160
160
|
<Desc>
|
|
161
|
-
DescriptionList 是唯讀資訊展示,空值不留空白(會讓使用者以為資料沒載入完)
|
|
162
|
-
(
|
|
161
|
+
DescriptionList 是唯讀資訊展示,空值不留空白(會讓使用者以為資料沒載入完)。一律用半形連字號
|
|
162
|
+
(`-`,對齊 Field `EMPTY_DISPLAY`)明確表達「有查過,但這個欄位目前沒值」;色同 value `text-foreground`。對齊 Atlassian / Polaris / GitHub 的資訊卡慣例。
|
|
163
163
|
</Desc>
|
|
164
164
|
<div className="border border-dashed border-divider rounded-md p-4 max-w-md">
|
|
165
165
|
<DescriptionList cols={2}>
|
|
166
166
|
<DescriptionItem label="姓名">Ada Chen</DescriptionItem>
|
|
167
|
-
<DescriptionItem label="職稱"><span className="text-
|
|
167
|
+
<DescriptionItem label="職稱"><span className="text-foreground">-</span></DescriptionItem>
|
|
168
168
|
<DescriptionItem label="Email">user@example.com</DescriptionItem>
|
|
169
|
-
<DescriptionItem label="電話"><span className="text-
|
|
169
|
+
<DescriptionItem label="電話"><span className="text-foreground">-</span></DescriptionItem>
|
|
170
170
|
<DescriptionItem label="團隊">Engineering</DescriptionItem>
|
|
171
|
-
<DescriptionItem label="直屬主管"><span className="text-
|
|
171
|
+
<DescriptionItem label="直屬主管"><span className="text-foreground">-</span></DescriptionItem>
|
|
172
172
|
</DescriptionList>
|
|
173
173
|
</div>
|
|
174
174
|
<p className="text-footnote text-fg-muted mt-3">
|
|
175
|
-
空值不應該用「N/A」/「暫無」等字串——不同 consumer
|
|
175
|
+
空值不應該用「N/A」/「暫無」等字串——不同 consumer 會選不同字,破壞視覺一致。一律半形連字號 `-`。
|
|
176
176
|
</p>
|
|
177
177
|
</div>
|
|
178
178
|
|
|
@@ -180,14 +180,16 @@ export const StateBehavior: Story = {
|
|
|
180
180
|
<H3>長 value — 自然換行,撐高該 grid cell</H3>
|
|
181
181
|
<Desc>
|
|
182
182
|
`value` 是自然流文字,超過欄寬自然換行(CSS grid 會讓該 row 的 cell 變高,其他 cell 保持 label
|
|
183
|
-
top-aligned)。不使用 truncate——value
|
|
183
|
+
top-aligned)。不使用 truncate——value 是被讀的內容,截斷會讓使用者漏資訊。帶空白的文字(如職稱)
|
|
184
|
+
自然斷行;無空白長字串(email / URL / token)需在該 item 加 `break-all` 才會斷(此範例 Email 欄已加;
|
|
185
|
+
vertical dd 預設不強制斷字,長字串由 consumer 自加 break-all)。
|
|
184
186
|
</Desc>
|
|
185
187
|
<div className="border border-dashed border-divider rounded-md p-4 max-w-md">
|
|
186
188
|
<DescriptionList cols={2}>
|
|
187
189
|
<DescriptionItem label="姓名">Ada Chen</DescriptionItem>
|
|
188
190
|
<DescriptionItem label="職稱">Senior Staff Principal Engineer, Design Systems</DescriptionItem>
|
|
189
191
|
<DescriptionItem label="辦公地點">Taipei, Taiwan</DescriptionItem>
|
|
190
|
-
<DescriptionItem label="Email">very.long.email.address@subdomain.example.com</DescriptionItem>
|
|
192
|
+
<DescriptionItem label="Email" className="min-w-0 break-all">very.long.email.address@subdomain.example.com</DescriptionItem>
|
|
191
193
|
</DescriptionList>
|
|
192
194
|
</div>
|
|
193
195
|
</div>
|
|
@@ -246,7 +248,7 @@ export const Accessibility = {
|
|
|
246
248
|
render: () => (
|
|
247
249
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
248
250
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
249
|
-
<p className="whitespace-pre-line">{"詳 `description-list.spec.md`「無障礙」段。摘要:\n\n- 語意 HTML:外層 <dl>,每組 <dt>(term)+ <dd>(description)— screen reader 讀「term X, description Y」配對敘事\n- DT/DD 配對:DescriptionItem 強制一組配對,不分開暴露 <dt>/<dd> primitive\n- 空值:consumer
|
|
251
|
+
<p className="whitespace-pre-line">{"詳 `description-list.spec.md`「無障礙」段。摘要:\n\n- 語意 HTML:外層 <dl>,每組 <dt>(term)+ <dd>(description)— screen reader 讀「term X, description Y」配對敘事\n- DT/DD 配對:DescriptionItem 強制一組配對,不分開暴露 <dt>/<dd> primitive\n- 空值:consumer 傳半形 - 占位(裸 - SR 敘事弱,宜補 sr-only「無資料」,比空 <dd> 明確)\n- 多欄 cols>1:視覺 grid、DOM 仍 item 順序,SR 依 DOM 敘事\n- 無互動:純唯讀呈現,無 keyboard / focus state(無 ARIA 補強需求,語意由原生 dl/dt/dd 承載)"}</p>
|
|
250
252
|
</div>
|
|
251
253
|
),
|
|
252
254
|
}
|
|
@@ -185,7 +185,7 @@ export const LayoutRule: Story = {
|
|
|
185
185
|
<DescriptionItem label="職稱">Senior Design Engineer</DescriptionItem>
|
|
186
186
|
</DescriptionList>
|
|
187
187
|
</Frame>
|
|
188
|
-
<Label warn>↑ 窄容器配 cols=2 → email
|
|
188
|
+
<Label warn>↑ 窄容器配 cols=2 → 職稱被迫斷行、email 擠壓貼邊,節奏亂、可讀性差</Label>
|
|
189
189
|
</Rule>
|
|
190
190
|
</div>
|
|
191
191
|
),
|
|
@@ -238,7 +238,7 @@ export const LabelAlignmentRule: Story = {
|
|
|
238
238
|
</div>
|
|
239
239
|
</Frame>
|
|
240
240
|
<Label warn>
|
|
241
|
-
↑ 這是自訂 layout 模擬 key-
|
|
241
|
+
↑ 這是自訂 layout 模擬 label 左 / value 右(key-left-value-right)→ 不是 DescriptionList,也無 dl/dt/dd 語義
|
|
242
242
|
</Label>
|
|
243
243
|
</Rule>
|
|
244
244
|
</div>
|
|
@@ -173,7 +173,7 @@ consumer 要在 DL 上方加 section heading(「基本資料」/「團隊資訊
|
|
|
173
173
|
|
|
174
174
|
- **語意 HTML**:外層 `<dl>`,每組內 `<dt>` 為 term、`<dd>` 為 description——screen reader 會讀成「term X, description Y」對話,明確表達屬性-值關係
|
|
175
175
|
- **DT / DD 配對**:每個 `<dt>` 必須有對應的 `<dd>`(不可孤立),否則 SR 敘事會中斷;元件內建一組 `DescriptionItem` 強制配對,不分開暴露 `<dt>` / `<dd>` primitive
|
|
176
|
-
- **空值呈現**:value 空時由 **consumer 自行傳入** `<span className="text-
|
|
176
|
+
- **空值呈現**:value 空時由 **consumer 自行傳入** `<span className="text-foreground">-</span>` 占位(半形 hyphen `-`,對齊 Field `EMPTY_DISPLAY` DS-wide 空值符號,2026-07-08 user 拍板「空值都用"-"⋯我從頭到尾哪裡有說要用全形的」;元件不自動 normalize——`<dd>` 直接 render `children`),`text-foreground`(同 value 色——「-」是不可編輯供檢視的值,非 placeholder 提示,2026-07-09 user 拍板)。**a11y known follow-up**:裸 `-` SR 敘事弱(半形連字號多被 SR 略過),宜補 `<span className="sr-only">無資料</span>` 或 `aria-label`,比空 `<dd>` 更明確
|
|
177
177
|
- **多欄 `cols > 1`**:視覺為 grid 欄位,但 DOM 順序為 item 順序——SR 仍依 DOM 敘事(term1 → desc1 → term2 → desc2),不依視覺欄位;設計時確保 DOM 順序符合語意分組
|
|
178
178
|
- **長值換行**:horizontal 模式的 value(`<dd>`)以 `break-all min-w-0` 處理,讓 URL / ID 等無空白長字串能斷行,避免撐破單列;vertical 模式 value 佔滿整欄寬,自然流文字依字詞換行(不強制單行 truncate,長內容保留可讀完整性)。若 vertical 模式需展示無空白長字串(連續英數 token),由 consumer 自行於該 value 加 `break-all`
|
|
179
179
|
- **列表識別**:預設 `<dl>` 有部分瀏覽器 SR 不視為 list,若需明確 list 語意,DL 根容器可搭配 `role="list"` + `<div role="listitem">`(目前預設不加,保留標準 `<dl>` 語意,consumer 可自行加 role 覆蓋)
|
|
@@ -188,7 +188,7 @@ DescriptionList 是**唯讀 label / value 資料呈現**(非互動 / 非 variant
|
|
|
188
188
|
- **無 ColorMatrix**:DL 固定 semantic token(label `text-fg-secondary` / value `text-foreground`),無自己的色彩變體,dark mode 由 semantic token 自動切換。加 color variant 不符語意(DL 是資訊展示,非狀態載體)。
|
|
189
189
|
- **無 SizeMatrix**:DL 無 size prop——垂直間距隨 `layout-space` token 感知 density(見「間距」段),但 label / value typography 走 reading mode 固定 tier,不提供 sm / md / lg 變體。不同 density 由 token 自動處理,非 prop 切換。
|
|
190
190
|
|
|
191
|
-
對應 anatomy story(實際 5 個,對齊 6-canonical 結構;ColorMatrix / SizeMatrix N/A):`Overview`(anatomy + typography + 間距) + `Inspector`(Controls 即時切 `cols` / `direction` / `divided`) + `ColsMatrix`(元件特有 1 / 2 / 3 欄對照) + `StateBehavior`(空值
|
|
191
|
+
對應 anatomy story(實際 5 個,對齊 6-canonical 結構;ColorMatrix / SizeMatrix N/A):`Overview`(anatomy + typography + 間距) + `Inspector`(Controls 即時切 `cols` / `direction` / `divided`) + `ColsMatrix`(元件特有 1 / 2 / 3 欄對照) + `StateBehavior`(空值 `-` / 長值 / 多行 / ReactNode value) + `Accessibility`(`dl/dt/dd` 語意 + 無互動說明)。
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
@@ -196,7 +196,7 @@ DescriptionList 是**唯讀 label / value 資料呈現**(非互動 / 非 variant
|
|
|
196
196
|
|
|
197
197
|
- **Disabled(action cell)**:DescriptionList 主體為唯讀資料呈現,本身無 disabled state。**dd 內互動內容 canonical(2026-07-04 Q9 拍板,三處立場收斂)**:操作型互動(Button / Input)**禁止**(見「禁止事項」— 需要動作 → Field read-only / inline-edit / action row / 卡片 header action);展示 / 導覽型 ReactNode(Tag / Badge / **Link**)**允許**,Link 自行 own disabled,DL 不干預。對齊 Polaris(ReactNode 型別 + 純敘述範例)/ Ant(action 放 extra 不放 dd)/ Carbon(read-only default)三家共識。
|
|
198
198
|
- **Loading**:DL 非 async surface,無 loading prop。若 page-level data 載入中,consumer 應在 DL 外層用 `<Skeleton>`(每組 dt/dd 對應一條 skeleton line)取代;DL 本體不渲染 loading state。
|
|
199
|
-
- **Empty(no items / empty value)**:no items → consumer 應 conditional 渲 `<Empty>` 取代 DL,不渲空 `<dl>`(SR 會讀「empty list」造成混淆);individual value 空 → consumer
|
|
199
|
+
- **Empty(no items / empty value)**:no items → consumer 應 conditional 渲 `<Empty>` 取代 DL,不渲空 `<dl>`(SR 會讀「empty list」造成混淆);individual value 空 → consumer 應自行傳入半形 `-`(hyphen,對齊 Field `EMPTY_DISPLAY`,2026-07-08 user 拍板;包 `text-foreground`(色同 value,2026-07-09);元件不自動 normalize,已在「無障礙」段 codify)。
|
|
200
200
|
- **長 label / 長值**:horizontal 模式 label(`dt`)`shrink-0` 不收縮、不截斷,value(`dd`)`break-all min-w-0` 斷行吸收擠壓;vertical 模式兩者佔滿欄寬自然換行。無空白長字串(URL / ID)詳「無障礙」段「長值換行」。
|
|
201
201
|
- **Dark mode**:走 semantic token(`text-fg-secondary` / `text-foreground`)自動 adapt。
|
|
202
202
|
- **Density**:垂直 gap 隨 `layout-space` token density-aware(見「間距」段),typography fixed reading mode tier 不變。
|
|
@@ -21,7 +21,7 @@ type Story = StoryObj<typeof DescriptionList>
|
|
|
21
21
|
export const UserProfile: Story = {
|
|
22
22
|
name: '使用者個資',
|
|
23
23
|
render: () => (
|
|
24
|
-
<div className="border border-border rounded-lg p-
|
|
24
|
+
<div className="border border-border rounded-lg p-[var(--layout-space-loose)] max-w-md">
|
|
25
25
|
<DescriptionList cols={1}>
|
|
26
26
|
<DescriptionItem label="姓名">Ada Chen</DescriptionItem>
|
|
27
27
|
<DescriptionItem label="Email">ada.chen@example.com</DescriptionItem>
|
|
@@ -37,7 +37,7 @@ export const UserProfile: Story = {
|
|
|
37
37
|
export const ProductSpec: Story = {
|
|
38
38
|
name: '產品規格',
|
|
39
39
|
render: () => (
|
|
40
|
-
<div className="border border-border rounded-lg p-
|
|
40
|
+
<div className="border border-border rounded-lg p-[var(--layout-space-loose)] max-w-2xl">
|
|
41
41
|
<DescriptionList cols={2}>
|
|
42
42
|
<DescriptionItem label="螢幕尺寸">6.7 吋 Super Retina XDR</DescriptionItem>
|
|
43
43
|
<DescriptionItem label="處理器">A18 Pro</DescriptionItem>
|
|
@@ -54,8 +54,9 @@ export const ProductSpec: Story = {
|
|
|
54
54
|
export const OrderSummary: Story = {
|
|
55
55
|
name: '訂單明細',
|
|
56
56
|
render: () => (
|
|
57
|
-
<div className="border border-border rounded-lg p-
|
|
58
|
-
|
|
57
|
+
<div className="border border-border rounded-lg p-[var(--layout-space-loose)] max-w-md">
|
|
58
|
+
{/* title 到第一個 item 的間距 = item 之間間距(Gestalt proximity canonical,見 spec;對齊 Horizontal story)*/}
|
|
59
|
+
<div className="text-body font-medium mb-[var(--layout-space-tight)]">訂單摘要</div>
|
|
59
60
|
<DescriptionList cols={1}>
|
|
60
61
|
<DescriptionItem label="訂單編號">#20260418-A241</DescriptionItem>
|
|
61
62
|
<DescriptionItem label="商品">Pro 年費方案 × 5 人</DescriptionItem>
|
|
@@ -75,7 +76,7 @@ export const OrderSummary: Story = {
|
|
|
75
76
|
export const DetailPanel: Story = {
|
|
76
77
|
name: '詳情面板',
|
|
77
78
|
render: () => (
|
|
78
|
-
<div className="border border-border rounded-lg p-
|
|
79
|
+
<div className="border border-border rounded-lg p-[var(--layout-space-loose)] max-w-3xl">
|
|
79
80
|
<DescriptionList cols={3}>
|
|
80
81
|
<DescriptionItem label="訂單狀態">已出貨</DescriptionItem>
|
|
81
82
|
<DescriptionItem label="建立時間">2026-04-18 10:35</DescriptionItem>
|
|
@@ -92,7 +93,7 @@ export const DetailPanel: Story = {
|
|
|
92
93
|
export const Horizontal: Story = {
|
|
93
94
|
name: '水平佈局',
|
|
94
95
|
render: () => (
|
|
95
|
-
<div className="border border-border rounded-lg p-
|
|
96
|
+
<div className="border border-border rounded-lg p-[var(--layout-space-loose)] max-w-md">
|
|
96
97
|
{/* title 到第一個 item 的間距 = item 之間間距(Gestalt proximity canonical,見 spec) */}
|
|
97
98
|
<div className="text-body font-medium mb-[var(--layout-space-tight)]">檔案資訊</div>
|
|
98
99
|
<DescriptionList direction="horizontal">
|
|
@@ -83,6 +83,7 @@ export const Overview: Story = {
|
|
|
83
83
|
{[
|
|
84
84
|
['autoHeight', 'boolean', 'false', 'true=隨內容 / false=填滿 viewport(body 捲動)'],
|
|
85
85
|
['maxWidth', 'string | number', "'512px'", 'Content 最大寬度(傳 number 視為 px,亦可傳 CSS 值如 32rem),受 viewport inset 限制'],
|
|
86
|
+
['actions(DialogHeader)', 'ReactNode', '—', 'Header 級操作 cluster(prev/next/⋮);DS 自動在 actions 與 Close X 間放 ButtonDivider(關閉誤觸保護,action-bar.spec.md:281)'],
|
|
86
87
|
].map(([p, t, d, desc]) => (
|
|
87
88
|
<tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
|
|
88
89
|
))}
|
|
@@ -105,6 +105,15 @@ Modal 與 viewport 四邊保持 `--layout-space-bottom`(48px)最小間距。
|
|
|
105
105
|
|
|
106
106
|
**Canonical 來源**:Dialog 是 overlay chrome,corner close X 屬 action group region,必用 Button(非 Inline Action / 非自刻 button)。詳見 `patterns/element-anatomy/inline-action.spec.md`「Dismiss canonical — X close only」+ `patterns/overlay-surface/overlay-surface.spec.md`「Chrome dismiss size canonical」。
|
|
107
107
|
|
|
108
|
+
### Header actions slot(2026-07-08)
|
|
109
|
+
|
|
110
|
+
Header 級操作(記錄 prev / next 導覽、header 級溢出選單 ⋮ 等「作用於整個 dialog 內容」的操作)走 `<DialogHeader actions={…}>` slot,**不**塞 children 自刻右側 cluster。
|
|
111
|
+
|
|
112
|
+
- **何時用**:操作對象是 dialog 承載的記錄本身(切換上下筆、複製連結、更多選單)。欄位級操作仍歸 body;confirm / cancel 歸 footer。
|
|
113
|
+
- **分隔線由 DS 自動放**:actions 與內建 Close X 之間 DS 渲 `<ButtonDivider>` — `action-bar.spec.md:281`「最右側為關閉 / 解除按鈕 → 分隔線必須(誤觸保護)」;幾何 = ButtonDivider `mx-1` 於 `gap-2` cluster → 兩側 12px 對稱(同 spec「分隔線幾何」段)。
|
|
114
|
+
- **按鈕形態**:`<Button variant="text" iconOnly …>`(text variant 自動 `data-unbounded`,不撐高 chrome header;對齊 action-bar「溢出按鈕一律最低視覺重量」)。
|
|
115
|
+
- ❌ **禁**:consumer 在 children 內自刻 cluster + divider(分隔線落點歸 DS,自刻 = 漏分隔線 / 幾何 drift 根因 — 2026-07-08 WM 詳情 header 錨例)。
|
|
116
|
+
|
|
108
117
|
## Title
|
|
109
118
|
|
|
110
119
|
`text-body-lg font-medium truncate`——單行截斷,不換行。
|