@qijenchen/design-system 0.1.0-beta.61 → 0.1.0-beta.63
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 +6 -6
- package/dist/components/Accordion/accordion.d.ts +1 -1
- package/dist/components/Accordion/accordion.js +1 -1
- package/dist/components/Accordion/accordion.js.map +1 -1
- package/dist/components/Alert/alert.d.ts +2 -2
- package/dist/components/Alert/alert.js +4 -3
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts.map +1 -1
- package/dist/components/AppShell/app-shell.js +4 -3
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts +1 -1
- package/dist/components/Avatar/avatar.js +2 -1
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Badge/badge.d.ts +1 -1
- package/dist/components/Badge/badge.js +2 -1
- package/dist/components/Badge/badge.js.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button.d.ts +5 -5
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +4 -3
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +1 -1
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +80 -69
- 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 +5 -3
- package/dist/components/Carousel/carousel.js.map +1 -1
- package/dist/components/Checkbox/checkbox-group.d.ts +2 -1
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox-group.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +9 -3
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +8 -3
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +2 -2
- package/dist/components/Chip/chip.js +3 -2
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/CircularProgress/circular-progress.d.ts +1 -1
- package/dist/components/CircularProgress/circular-progress.js +2 -1
- package/dist/components/CircularProgress/circular-progress.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +4 -4
- package/dist/components/Coachmark/coachmark.js +2 -1
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +17 -13
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts +4 -0
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DateGrid/date-grid.d.ts +8 -4
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +2 -2
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +6 -4
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.js +1 -1
- package/dist/components/DescriptionList/description-list.js.map +1 -1
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +0 -1
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Empty/empty.d.ts +1 -1
- package/dist/components/Empty/empty.js.map +1 -1
- package/dist/components/Field/field-wrapper.js +1 -1
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +1 -0
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js +1 -1
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
- package/dist/components/FileUpload/file-upload.d.ts +8 -1
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +7 -3
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts +1 -1
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +25 -14
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/HoverCard/hover-card.d.ts +5 -1
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
- package/dist/components/HoverCard/hover-card.js +2 -1
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts +6 -2
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +5 -1
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +2 -1
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +4 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -2
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +6 -2
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/Popover/popover.d.ts +1 -1
- package/dist/components/Popover/popover.js +2 -1
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +9 -4
- package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +6 -0
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +4 -0
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.js +1 -1
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +14 -4
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/select-menu.d.ts +4 -0
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +6 -3
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/SelectionControl/selection-item.d.ts +5 -1
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
- package/dist/components/SelectionControl/selection-item.js +3 -1
- package/dist/components/SelectionControl/selection-item.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +6 -5
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +1 -1
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +3 -2
- package/dist/components/Sidebar/sidebar.js.map +1 -1
- package/dist/components/Skeleton/skeleton.d.ts +1 -1
- package/dist/components/Skeleton/skeleton.js +2 -1
- package/dist/components/Skeleton/skeleton.js.map +1 -1
- package/dist/components/Slider/slider.d.ts +1 -1
- package/dist/components/Slider/slider.d.ts.map +1 -1
- package/dist/components/Slider/slider.js +7 -3
- package/dist/components/Slider/slider.js.map +1 -1
- package/dist/components/Steps/steps.d.ts +1 -1
- package/dist/components/Steps/steps.d.ts.map +1 -1
- package/dist/components/Steps/steps.js +9 -6
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +5 -5
- package/dist/components/Switch/switch.js +3 -3
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.js +1 -1
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Textarea/textarea.js +1 -1
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-columns.js +1 -1
- 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 +2 -1
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Toast/toast.js.map +1 -1
- package/dist/components/Tooltip/tooltip.d.ts +1 -1
- package/dist/components/Tooltip/tooltip.js +2 -1
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +4 -4
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +3 -3
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +3 -3
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
- package/dist/patterns/header-canonical/chrome-header.d.ts +3 -2
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -1
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +3 -2
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
- package/ds-canonical/hooks/_log-fire.sh +3 -1
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +21 -1
- package/ds-canonical/hooks/check_audit_sample_escape.sh +6 -3
- package/ds-canonical/hooks/check_chrome_header_avatar_canonical.sh +8 -0
- package/ds-canonical/hooks/check_consumer_app_invariants.sh +321 -0
- package/ds-canonical/hooks/check_datatable_invariants.sh +75 -12
- package/ds-canonical/hooks/check_escape_marker_abuse.sh +15 -1
- package/ds-canonical/hooks/check_field_family_invariants.sh +12 -2
- package/ds-canonical/hooks/check_plugin_fork_health.sh +137 -0
- package/ds-canonical/hooks/check_propose_discipline.sh +147 -0
- package/ds-canonical/hooks/check_solo_workflow.sh +11 -1
- package/ds-canonical/hooks/check_story_invariants.sh +63 -9
- package/ds-canonical/hooks/check_storybook_addon_packaging.sh +151 -0
- package/ds-canonical/hooks/check_tailwind_wildcard_in_docs.sh +8 -2
- package/ds-canonical/hooks/lib/_overlay_handcraft.sh +25 -4
- package/ds-canonical/hooks/lib/_token_hygiene.sh +9 -1
- package/ds-canonical/hooks/session_start_governance_check.sh +7 -2
- package/ds-canonical/hooks/stop_self_audit.sh +2 -2
- package/ds-canonical/hooks/tests/test_check_addon_subdir_ship.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +12 -0
- package/ds-canonical/hooks/tests/test_check_consumer_app_story_title.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +6 -4
- package/ds-canonical/hooks/tests/test_check_consumer_no_ds_catalog.sh +7 -4
- package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +6 -4
- package/ds-canonical/hooks/tests/test_check_data_table_size_num_to_meta_width.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_fork_user_plugin_install.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +9 -0
- package/ds-canonical/hooks/tests/test_check_propose_cite_required.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +10 -0
- package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +3 -2
- package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +10 -0
- package/ds-canonical/hooks/tests/test_check_storybook_addon_preset_cjs.sh +3 -2
- package/ds-canonical/references/build-ui-canonicals.md +2 -2
- package/ds-canonical/references/composition-fidelity.md +3 -3
- package/ds-canonical/references/naming-conventions.md +1 -0
- package/ds-canonical/references/ssot-consultation.md +1 -1
- package/ds-canonical/references/ssot-index.md +7 -7
- package/ds-canonical/rules/meta-patterns.md +5 -5
- package/ds-canonical/rules/self-verify.md +1 -1
- package/ds-canonical/rules/story-rules.md +2 -0
- package/ds-canonical/rules/ui-development.md +1 -1
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +11 -2
- package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +15 -15
- package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +4 -3
- package/ds-story-manifest.json +15 -21
- package/llms-full.txt +9 -5
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
- package/src/components/Accordion/accordion.spec.md +22 -5
- package/src/components/Accordion/accordion.tsx +1 -1
- package/src/components/Alert/alert.anatomy.stories.tsx +4 -4
- package/src/components/Alert/alert.principles.stories.tsx +5 -5
- package/src/components/Alert/alert.spec.md +16 -11
- package/src/components/Alert/alert.stories.tsx +5 -5
- package/src/components/Alert/alert.tsx +2 -2
- package/src/components/AppShell/app-shell.principles.stories.tsx +68 -21
- package/src/components/AppShell/app-shell.spec.md +17 -24
- package/src/components/AppShell/app-shell.tsx +4 -3
- package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +3 -3
- package/src/components/AspectRatio/aspect-ratio.spec.md +15 -1
- package/src/components/Avatar/avatar.anatomy.stories.tsx +1 -1
- package/src/components/Avatar/avatar.principles.stories.tsx +8 -8
- package/src/components/Avatar/avatar.spec.md +25 -54
- package/src/components/Avatar/avatar.tsx +2 -2
- package/src/components/Badge/badge.principles.stories.tsx +2 -2
- package/src/components/Badge/badge.spec.md +22 -13
- package/src/components/Badge/badge.tsx +1 -1
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +5 -2
- package/src/components/Breadcrumb/breadcrumb.spec.md +25 -25
- package/src/components/Breadcrumb/breadcrumb.stories.tsx +7 -32
- package/src/components/Breadcrumb/breadcrumb.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +2 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +20 -6
- package/src/components/BulkActionBar/bulk-action-bar.tsx +2 -2
- package/src/components/Button/button.anatomy.stories.tsx +2 -2
- package/src/components/Button/button.spec.md +19 -17
- package/src/components/Button/button.stories.tsx +1 -1
- package/src/components/Button/button.tsx +10 -9
- package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
- package/src/components/Calendar/calendar.spec.md +37 -17
- package/src/components/Calendar/calendar.tsx +26 -22
- package/src/components/Carousel/carousel.anatomy.stories.tsx +6 -6
- package/src/components/Carousel/carousel.principles.stories.tsx +1 -1
- package/src/components/Carousel/carousel.spec.md +23 -3
- package/src/components/Carousel/carousel.tsx +19 -4
- package/src/components/Chart/chart.anatomy.stories.tsx +1 -1
- package/src/components/Chart/chart.spec.md +20 -1
- package/src/components/Checkbox/checkbox-group.tsx +2 -1
- package/src/components/Checkbox/checkbox.anatomy.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.principles.stories.tsx +2 -2
- package/src/components/Checkbox/checkbox.spec.md +35 -15
- package/src/components/Checkbox/checkbox.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.tsx +14 -3
- package/src/components/Chip/chip.anatomy.stories.tsx +5 -5
- package/src/components/Chip/chip.principles.stories.tsx +9 -3
- package/src/components/Chip/chip.spec.md +8 -9
- package/src/components/Chip/chip.tsx +2 -2
- package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +6 -6
- package/src/components/CircularProgress/circular-progress.spec.md +10 -11
- package/src/components/CircularProgress/circular-progress.stories.tsx +36 -43
- package/src/components/CircularProgress/circular-progress.tsx +1 -1
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +1 -1
- package/src/components/Coachmark/coachmark.principles.stories.tsx +14 -29
- package/src/components/Coachmark/coachmark.spec.md +21 -13
- package/src/components/Coachmark/coachmark.tsx +4 -4
- package/src/components/Combobox/combobox.anatomy.stories.tsx +28 -28
- package/src/components/Combobox/combobox.principles.stories.tsx +1 -1
- package/src/components/Combobox/combobox.spec.md +25 -7
- package/src/components/Combobox/combobox.tsx +12 -3
- package/src/components/Command/command.anatomy.stories.tsx +1 -1
- package/src/components/Command/command.principles.stories.tsx +8 -8
- package/src/components/Command/command.spec.md +18 -8
- package/src/components/Command/command.tsx +8 -3
- package/src/components/DataTable/data-table-sort-manager.tsx +1 -1
- package/src/components/DataTable/data-table.anatomy.stories.tsx +9 -7
- package/src/components/DataTable/data-table.principles.stories.tsx +3 -3
- package/src/components/DataTable/data-table.spec.md +15 -11
- package/src/components/DataTable/data-table.stories.tsx +58 -13
- package/src/components/DataTable/data-table.tsx +13 -0
- package/src/components/DataTable/filter-operators.spec.md +19 -27
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +8 -8
- package/src/components/DateGrid/date-grid.principles.stories.tsx +7 -7
- package/src/components/DateGrid/date-grid.spec.md +17 -14
- package/src/components/DateGrid/date-grid.tsx +8 -4
- package/src/components/DatePicker/date-picker.anatomy.stories.tsx +11 -15
- package/src/components/DatePicker/date-picker.principles.stories.tsx +8 -8
- package/src/components/DatePicker/date-picker.spec.md +40 -36
- package/src/components/DatePicker/date-picker.stories.tsx +23 -53
- package/src/components/DatePicker/date-picker.tsx +12 -6
- package/src/components/DescriptionList/description-list.anatomy.stories.tsx +2 -2
- package/src/components/DescriptionList/description-list.principles.stories.tsx +4 -18
- package/src/components/DescriptionList/description-list.spec.md +9 -3
- package/src/components/DescriptionList/description-list.stories.tsx +2 -18
- package/src/components/DescriptionList/description-list.tsx +1 -1
- package/src/components/Dialog/dialog.principles.stories.tsx +1 -1
- package/src/components/Dialog/dialog.spec.md +26 -11
- package/src/components/Dialog/dialog.stories.tsx +159 -184
- package/src/components/Dialog/dialog.tsx +2 -1
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +2 -2
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +16 -17
- package/src/components/DropdownMenu/dropdown-menu.spec.md +10 -15
- package/src/components/DropdownMenu/dropdown-menu.stories.tsx +13 -15
- package/src/components/DropdownMenu/dropdown-menu.tsx +12 -2
- package/src/components/Empty/empty.spec.md +19 -18
- package/src/components/Empty/empty.tsx +1 -1
- package/src/components/Field/field-controls.spec.md +52 -41
- package/src/components/Field/field-wrapper.tsx +2 -2
- package/src/components/Field/field.anatomy.stories.tsx +6 -5
- package/src/components/Field/field.principles.stories.tsx +8 -7
- package/src/components/Field/field.spec.md +42 -20
- package/src/components/Field/field.stories.tsx +9 -7
- package/src/components/Field/field.tsx +6 -3
- package/src/components/Field/form-validation.spec.md +20 -19
- package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +16 -15
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +5 -1
- package/src/components/FieldControlGroup/field-control-group.spec.md +17 -1
- package/src/components/FieldControlGroup/field-control-group.stories.tsx +9 -9
- package/src/components/FieldControlGroup/field-control-group.tsx +4 -3
- package/src/components/FileItem/file-item.anatomy.stories.tsx +7 -17
- package/src/components/FileItem/file-item.principles.stories.tsx +7 -7
- package/src/components/FileItem/file-item.spec.md +24 -24
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +4 -2
- package/src/components/FileUpload/file-upload.principles.stories.tsx +10 -12
- package/src/components/FileUpload/file-upload.spec.md +37 -8
- package/src/components/FileUpload/file-upload.tsx +5 -3
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +16 -11
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +4 -4
- package/src/components/FileViewer/file-viewer.spec.md +7 -19
- package/src/components/FileViewer/file-viewer.stories.tsx +3 -3
- package/src/components/FileViewer/file-viewer.tsx +42 -16
- package/src/components/HoverCard/hover-card.spec.md +20 -10
- package/src/components/HoverCard/hover-card.stories.tsx +1 -1
- package/src/components/HoverCard/hover-card.tsx +12 -1
- package/src/components/Input/input.anatomy.stories.tsx +4 -4
- package/src/components/Input/input.principles.stories.tsx +4 -31
- package/src/components/Input/input.spec.md +16 -4
- 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.spec.md +14 -1
- package/src/components/Menu/menu-item.principles.stories.tsx +5 -5
- package/src/components/Menu/menu-item.spec.md +24 -12
- package/src/components/Menu/menu-item.tsx +7 -3
- package/src/components/Notice/notice.principles.stories.tsx +7 -7
- package/src/components/Notice/notice.spec.md +7 -5
- package/src/components/Notice/notice.tsx +5 -1
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +4 -4
- package/src/components/NumberInput/number-input.principles.stories.tsx +13 -35
- package/src/components/NumberInput/number-input.spec.md +19 -0
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +4 -3
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +2 -5
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +9 -1
- package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -42
- package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -3
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +11 -2
- package/src/components/PeoplePicker/people-picker.spec.md +26 -12
- package/src/components/PeoplePicker/people-picker.stories.tsx +14 -15
- package/src/components/PeoplePicker/people-picker.tsx +12 -4
- package/src/components/Popover/popover.spec.md +20 -11
- package/src/components/Popover/popover.tsx +2 -2
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.principles.stories.tsx +29 -25
- package/src/components/ProfileCard/profile-card.spec.md +30 -10
- package/src/components/ProfileCard/profile-card.tsx +12 -7
- package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +7 -5
- package/src/components/ProgressBar/progress-bar.spec.md +9 -1
- package/src/components/ProgressBar/progress-bar.stories.tsx +1 -1
- package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +6 -3
- package/src/components/RadioGroup/radio-group.principles.stories.tsx +6 -13
- package/src/components/RadioGroup/radio-group.spec.md +7 -1
- package/src/components/RadioGroup/radio-group.tsx +10 -0
- package/src/components/Rating/rating.anatomy.stories.tsx +1 -0
- package/src/components/Rating/rating.principles.stories.tsx +9 -6
- package/src/components/Rating/rating.spec.md +13 -7
- package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +44 -24
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +51 -57
- package/src/components/ScrollArea/scroll-area.spec.md +5 -7
- package/src/components/ScrollArea/scroll-area.stories.tsx +110 -60
- package/src/components/ScrollArea/scroll-area.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.spec.md +15 -14
- package/src/components/SegmentedControl/segmented-control.stories.tsx +1 -1
- package/src/components/Select/select.anatomy.stories.tsx +12 -11
- package/src/components/Select/select.principles.stories.tsx +3 -3
- package/src/components/Select/select.spec.md +34 -8
- package/src/components/Select/select.stories.tsx +2 -2
- package/src/components/Select/select.tsx +18 -3
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +2 -2
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +5 -5
- package/src/components/SelectMenu/select-menu.spec.md +19 -12
- package/src/components/SelectMenu/select-menu.stories.tsx +34 -27
- package/src/components/SelectMenu/select-menu.tsx +14 -3
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.spec.md +13 -2
- package/src/components/SelectionControl/selection-item.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.tsx +8 -2
- package/src/components/Separator/separator.principles.stories.tsx +2 -2
- package/src/components/Separator/separator.spec.md +11 -5
- package/src/components/Sheet/sheet.anatomy.stories.tsx +7 -6
- package/src/components/Sheet/sheet.principles.stories.tsx +18 -38
- package/src/components/Sheet/sheet.spec.md +9 -11
- package/src/components/Sheet/sheet.stories.tsx +2 -2
- package/src/components/Sheet/sheet.tsx +6 -5
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +42 -33
- package/src/components/Sidebar/sidebar.principles.stories.tsx +4 -4
- package/src/components/Sidebar/sidebar.spec.md +22 -17
- package/src/components/Sidebar/sidebar.stories.tsx +16 -0
- package/src/components/Sidebar/sidebar.tsx +15 -7
- package/src/components/Skeleton/skeleton.anatomy.stories.tsx +2 -2
- package/src/components/Skeleton/skeleton.principles.stories.tsx +20 -7
- package/src/components/Skeleton/skeleton.spec.md +6 -4
- package/src/components/Skeleton/skeleton.stories.tsx +34 -26
- package/src/components/Skeleton/skeleton.tsx +1 -1
- package/src/components/Slider/slider.principles.stories.tsx +3 -3
- package/src/components/Slider/slider.spec.md +16 -12
- package/src/components/Slider/slider.stories.tsx +2 -18
- package/src/components/Slider/slider.tsx +6 -2
- package/src/components/Steps/steps.anatomy.stories.tsx +3 -3
- package/src/components/Steps/steps.principles.stories.tsx +9 -12
- package/src/components/Steps/steps.spec.md +31 -25
- package/src/components/Steps/steps.stories.tsx +5 -40
- package/src/components/Steps/steps.tsx +17 -12
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Switch/switch.spec.md +13 -0
- package/src/components/Switch/switch.tsx +3 -3
- package/src/components/Tabs/tabs.anatomy.stories.tsx +4 -4
- package/src/components/Tabs/tabs.principles.stories.tsx +1 -1
- package/src/components/Tabs/tabs.spec.md +13 -6
- package/src/components/Tabs/tabs.stories.tsx +3 -3
- package/src/components/Tabs/tabs.tsx +2 -2
- package/src/components/Tag/tag.anatomy.stories.tsx +15 -15
- package/src/components/Tag/tag.principles.stories.tsx +1 -1
- package/src/components/Tag/tag.spec.md +25 -5
- package/src/components/Textarea/textarea.anatomy.stories.tsx +3 -3
- package/src/components/Textarea/textarea.principles.stories.tsx +7 -7
- package/src/components/Textarea/textarea.spec.md +15 -3
- package/src/components/Textarea/textarea.tsx +1 -1
- package/src/components/TimePicker/time-columns.tsx +1 -1
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +8 -2
- package/src/components/TimePicker/time-picker.spec.md +23 -3
- package/src/components/TimePicker/time-picker.tsx +5 -3
- package/src/components/Toast/toast.anatomy.stories.tsx +1 -1
- package/src/components/Toast/toast.spec.md +7 -4
- package/src/components/Toast/toast.stories.tsx +12 -6
- package/src/components/Toast/toast.tsx +1 -1
- package/src/components/Tooltip/tooltip.anatomy.stories.tsx +1 -1
- package/src/components/Tooltip/tooltip.spec.md +11 -8
- package/src/components/Tooltip/tooltip.tsx +1 -1
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +25 -9
- package/src/components/TreeView/tree-view.principles.stories.tsx +5 -5
- package/src/components/TreeView/tree-view.spec.md +11 -9
- package/src/components/TreeView/tree-view.stories.tsx +5 -3
- package/src/components/TreeView/tree-view.tsx +8 -5
- package/src/patterns/action-bar/action-bar.spec.md +11 -4
- package/src/patterns/element-anatomy/element-anatomy.spec.md +8 -6
- package/src/patterns/element-anatomy/inline-action.spec.md +18 -18
- package/src/patterns/element-anatomy/item-anatomy.spec.md +47 -42
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -6
- package/src/patterns/element-anatomy/item-anatomy.tsx +3 -3
- package/src/patterns/header-canonical/chrome-header.tsx +3 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +24 -11
- package/src/patterns/header-canonical/header-canonical.stories.tsx +9 -9
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +22 -12
- package/src/patterns/overlay-surface/overlay-surface.spec.md +43 -39
- package/src/patterns/overlay-surface/overlay-surface.tsx +3 -2
- package/src/patterns/resize-handle/resize-handle.spec.md +10 -1
- package/src/patterns/resize-handle/resize-handle.stories.tsx +7 -7
- package/src/tokens/README.md +5 -2
- package/src/tokens/color/color.spec.md +17 -10
- package/src/tokens/color/semantic.css +2 -0
- package/src/tokens/density/density.spec.md +4 -14
- package/src/tokens/elevation/elevation.spec.md +7 -8
- package/src/tokens/layoutSpace/layoutSpace.spec.md +20 -27
- package/src/tokens/motion/motion.spec.md +15 -7
- package/src/tokens/opacity/opacity.spec.md +15 -26
- package/src/tokens/orphan-tokens.spec.md +14 -3
- package/src/tokens/radius/radius.spec.md +13 -15
- package/src/tokens/token-system.spec.md +10 -13
- package/src/tokens/typography/typography.spec.md +8 -12
- package/src/tokens/uiSize/uiSize.spec.md +28 -16
- /package/ds-canonical/hooks/{check_addon_subdir_ship.sh → retired/2026-06-11-prune-merge/check_addon_subdir_ship.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_app_story_title.sh → retired/2026-06-11-prune-merge/check_consumer_app_story_title.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_ds_primitive_misuse.sh → retired/2026-06-11-prune-merge/check_consumer_ds_primitive_misuse.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_no_ds_catalog.sh → retired/2026-06-11-prune-merge/check_consumer_no_ds_catalog.sh} +0 -0
- /package/ds-canonical/hooks/{check_consumer_story_baseline.sh → retired/2026-06-11-prune-merge/check_consumer_story_baseline.sh} +0 -0
- /package/ds-canonical/hooks/{check_data_table_size_num_to_meta_width.sh → retired/2026-06-11-prune-merge/check_data_table_size_num_to_meta_width.sh} +0 -0
- /package/ds-canonical/hooks/{check_fork_user_plugin_install.sh → retired/2026-06-11-prune-merge/check_fork_user_plugin_install.sh} +0 -0
- /package/ds-canonical/hooks/{check_plugin_freshness.sh → retired/2026-06-11-prune-merge/check_plugin_freshness.sh} +0 -0
- /package/ds-canonical/hooks/{check_propose_cite_required.sh → retired/2026-06-11-prune-merge/check_propose_cite_required.sh} +0 -0
- /package/ds-canonical/hooks/{check_propose_plain_chinese.sh → retired/2026-06-11-prune-merge/check_propose_plain_chinese.sh} +0 -0
- /package/ds-canonical/hooks/{check_storybook_addon_preset_cjs.sh → retired/2026-06-11-prune-merge/check_storybook_addon_preset_cjs.sh} +0 -0
|
@@ -44,12 +44,12 @@ prefix icon 跟 label 同色(foreground),不是 fg-muted。詳見 item-ana
|
|
|
44
44
|
|
|
45
45
|
所有 prefix 元素(checkbox、icon、avatar)共享同一個對齊容器。容器高度決定對齊行為:
|
|
46
46
|
|
|
47
|
-
| prefix 最大高度 |
|
|
47
|
+
| prefix 最大高度 | 容器高度(原則) | 對齊目標 |
|
|
48
48
|
|---|---|---|
|
|
49
|
-
| ≤ 24px |
|
|
50
|
-
| > 24px |
|
|
49
|
+
| ≤ 24px | 一行 label 高(inline) | 第一行 label 的垂直中心 |
|
|
50
|
+
| > 24px | label + gap + 一行 description 的文字塊高(block) | 文字塊的垂直中心 |
|
|
51
51
|
|
|
52
|
-
**SSOT
|
|
52
|
+
**SSOT**:對齊公式(CSS calc 細節)封裝於 `patterns/element-anatomy/item-anatomy.tsx` 的 `itemPrefixAlignVariants`(2026-04-23 重構),spec 不重述公式。MenuItem 消費此 primitive,不自建對齊邏輯;改 gap token(`--item-gap-label-desc-scanning[-lg]`;bare token 已不存在,4 變體見 `layoutSpace.css`)或 font-size token 一處 → MenuItem 自動同步。
|
|
53
53
|
|
|
54
54
|
**24px 是物理限制**——16px icon 在 24px 圓內仍可辨識(內部 icon 下限 12px),但在更小的容器中 icon 會低於可讀閾值。
|
|
55
55
|
|
|
@@ -183,7 +183,7 @@ Menu item 的 prefix icon 跟 label 同色(foreground),不是 fg-muted。P
|
|
|
183
183
|
|
|
184
184
|
## Group
|
|
185
185
|
|
|
186
|
-
群組由 `MenuGroup`
|
|
186
|
+
群組由 `MenuGroup` 包裹,`py-2`(8px)上下內距。群組緊鄰群組無額外 margin——相鄰群組由 `[&+&]:border-t border-divider` 自動分隔(上下 py-2 合計 16px 視覺間距;Pattern A,SSOT 見 `item-anatomy.spec.md`「Group auto-separation」)。
|
|
187
187
|
|
|
188
188
|
### Group Header
|
|
189
189
|
|
|
@@ -231,6 +231,20 @@ Menu item 的 prefix icon 跟 label 同色(foreground),不是 fg-muted。P
|
|
|
231
231
|
- `../DropdownMenu/dropdown-menu.tsx` — 操作選單
|
|
232
232
|
- 未來:ContextMenu、CommandPalette
|
|
233
233
|
|
|
234
|
+
### 近親分界
|
|
235
|
+
|
|
236
|
+
| | MenuItem(Family 1) | SelectionItem | List item(Family 2) |
|
|
237
|
+
|---|---|---|---|
|
|
238
|
+
| 場景 | 浮層選單 row,掃視挑一個 | form 內 Checkbox / Radio 的 label 佈局 | 內容列表 row,閱讀 |
|
|
239
|
+
| Clamp 預設 | label / desc 各 1 行 | `'none'` 完整閱讀(SSOT 對照表見 `../Checkbox/checkbox.spec.md`「為什麼不像 MenuItem 強制截斷?」) | 依元件(如 FileItem) |
|
|
240
|
+
| SSOT | `item-anatomy.spec.md`「Menu item layout」 | `../SelectionControl/selection-item.spec.md` | `item-anatomy.spec.md`「List item layout」 |
|
|
241
|
+
|
|
242
|
+
### 常見誤解
|
|
243
|
+
|
|
244
|
+
- 直接 `<MenuItem>` 進 JSX → ❌(失去外層 Radix / cmdk a11y,見上表)
|
|
245
|
+
- 單選選中要加 ✓ 勾號 → ❌,DS 用 `bg-neutral-selected` 高亮(勾號影響 prefix 對齊,見「選中指示器」)
|
|
246
|
+
- suffix 可塞大塊內容 → ❌,實作寫死 inline 對齊只支援 ≤24px(見「Suffix 對齊(實作限制)」)
|
|
247
|
+
|
|
234
248
|
---
|
|
235
249
|
|
|
236
250
|
## 為何無獨立 StateBehavior story
|
|
@@ -239,7 +253,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
|
|
|
239
253
|
|
|
240
254
|
獨立 StateBehavior story 會複製 ColorMatrix 內容——MenuItem 的 state 本身就是色彩表達,無額外「時序 / 動畫」可獨立呈現(不像 Accordion 有 expand/collapse 行為)。Inspector 已互動式展示 selected / disabled 單一 variant 的切換。
|
|
241
255
|
|
|
242
|
-
對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix`(含完整狀態色矩陣) + `
|
|
256
|
+
對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix`(含完整狀態色矩陣)+ `SizeMatrix` + `Accessibility`。
|
|
243
257
|
|
|
244
258
|
---
|
|
245
259
|
|
|
@@ -248,6 +262,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
|
|
|
248
262
|
- **Disabled**:`disabled` prop 由 MenuItem primitive own;視覺 `text-fg-disabled`(neutral-6,M24 state>emphasis)、無 hover bg、`aria-disabled="true"`、Enter / click 不觸發 onSelect、鍵盤導覽自動 skip(由 consumer SelectMenu / DropdownMenu / cmdk 處理)。已在「選擇 / 狀態視覺規則」段 codify。
|
|
249
263
|
- **Loading**:MenuItem 為單一 row primitive 非 async surface,本身不擁有 loading prop。Async option list 的 loading 由 consumer(SelectMenu / Combobox / DropdownMenu)在 list body 替換為 `<Empty icon={<CircularProgress/>}/>`(SelectMenu SSOT)。
|
|
250
264
|
- **Empty(label-only / icon-only)**:label 為必傳;若無 prefix icon / avatar / checkbox,layout 自動收斂為 `[label] [suffix?]`;若無 suffix(shortcut / endAction / chevron),收斂為純 `[label]`。
|
|
265
|
+
- **極長 label / description**:預設各 clamp 1 行 truncate(見「Clamp 政策」),row 高度恆為兩種之一不被撐高。
|
|
251
266
|
- **Dark mode**:走 semantic token 自動 adapt。
|
|
252
267
|
- **Density**:`size` 由 consumer menu(`Menu` block-tier `compact` / `reading`)決定 row height + padding,MenuItem 自身不持 density state。
|
|
253
268
|
|
|
@@ -282,11 +297,8 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
|
|
|
282
297
|
|
|
283
298
|
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
284
299
|
|
|
285
|
-
- `
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
290
|
-
|
|
300
|
+
- `dropdown-menu.spec.md`
|
|
301
|
+
- `item-anatomy.spec.md`
|
|
302
|
+
- `select-menu.spec.md`
|
|
291
303
|
- `selection-item.spec.md`
|
|
292
304
|
- `sidebar.spec.md`
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
|
|
3
|
+
* 不進 root barrel front-door;由 DropdownMenu / SelectMenu 等 menu 類 DS 元件 wrap 消費,end-user app 請用 wrapper 元件。
|
|
4
|
+
*/
|
|
1
5
|
// @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
6
|
import * as React from 'react'
|
|
3
7
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
@@ -20,7 +24,7 @@ import { ICON_SIZE, AVATAR_SIZE, ItemContent, itemPrefixAlignVariants, ROW_PADDI
|
|
|
20
24
|
*
|
|
21
25
|
* ── Prefix 對齊規則(24px 閾值)──
|
|
22
26
|
* prefix ≤ 24px → h-[1lh],對齊第一行 label
|
|
23
|
-
* prefix > 24px → h-[calc(1lh+var(--item-gap-label-desc)+desc_1lh)],對齊文字區塊
|
|
27
|
+
* prefix > 24px → h-[calc(1lh+var(--item-gap-label-desc-scanning)+desc_1lh)](size-aware -scanning[-lg] 變體),對齊文字區塊
|
|
24
28
|
* 無 description → prefix 上限 24px
|
|
25
29
|
*
|
|
26
30
|
* ── Size ──
|
|
@@ -86,7 +90,7 @@ export interface MenuItemProps
|
|
|
86
90
|
* Label 最大行數(line-clamp 截斷,超過顯示 ellipsis)。
|
|
87
91
|
*
|
|
88
92
|
* - `undefined`(預設 prop 值未傳)→ 套用元件預設 `1`(單行截斷,符合選單快速掃視需求)
|
|
89
|
-
* - 數字 →
|
|
93
|
+
* - 數字(1-6)→ 截斷到該行數;>6 超出 line-clamp utility 支援範圍 → 不截斷(同 'none',見 lineClampClass)
|
|
90
94
|
* - `'none'` → **明確**不截斷,自然 wrap 任意行數
|
|
91
95
|
*
|
|
92
96
|
* 為什麼用 `'none'` 而不是 `undefined` 表達不截斷?React props 的 destructure default
|
|
@@ -98,7 +102,7 @@ export interface MenuItemProps
|
|
|
98
102
|
* Description 最大行數。
|
|
99
103
|
*
|
|
100
104
|
* - `undefined`(預設 prop 值未傳)→ 套用元件預設 `1`(跟 label 對稱,維持掃視節奏)
|
|
101
|
-
* - 數字 →
|
|
105
|
+
* - 數字(1-6)→ 截斷到該行數;>6 超出 line-clamp utility 支援範圍 → 不截斷(同 'none',見 lineClampClass)
|
|
102
106
|
* - `'none'` → 明確不截斷
|
|
103
107
|
*
|
|
104
108
|
* 為什麼預設 1?Menu 的設計目的是「快速掃視多個選項挑一個」,垂直空間是
|
|
@@ -26,19 +26,19 @@ export const UsageGuidance: Story = {
|
|
|
26
26
|
<p>適合 Notice 的真實業務場景(點擊跳轉「展示」頁範例):</p>
|
|
27
27
|
<ul className="space-y-1">
|
|
28
28
|
<li>
|
|
29
|
-
<LinkTo kind="Design System/Internal/Notice/展示" name="部署成功 橫幅"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
29
|
+
<LinkTo kind="Design System/Internal/Notice/展示" name="部署成功 橫幅"><span className="text-primary hover:underline font-medium cursor-pointer">CI/CD 部署成功橫幅 — 附「查看部署紀錄」動作</span></LinkTo>
|
|
30
30
|
</li>
|
|
31
31
|
<li>
|
|
32
|
-
<LinkTo kind="Design System/Internal/Notice/展示" name="工作區付款失敗"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
32
|
+
<LinkTo kind="Design System/Internal/Notice/展示" name="工作區付款失敗"><span className="text-primary hover:underline font-medium cursor-pointer">工作區付款失敗 — 附「更新付款方式」補救動作</span></LinkTo>
|
|
33
33
|
</li>
|
|
34
34
|
<li>
|
|
35
|
-
<LinkTo kind="Design System/Internal/Notice/展示" name="行內通知變體對照"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
35
|
+
<LinkTo kind="Design System/Internal/Notice/展示" name="行內通知變體對照"><span className="text-primary hover:underline font-medium cursor-pointer">方案限制 / 空間不足 / 連線失敗等行內提示(五種語意變體)</span></LinkTo>
|
|
36
36
|
</li>
|
|
37
37
|
<li>
|
|
38
|
-
<LinkTo kind="Design System/Internal/Notice/展示" name="Toast 樣式"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
38
|
+
<LinkTo kind="Design System/Internal/Notice/展示" name="Toast 樣式"><span className="text-primary hover:underline font-medium cursor-pointer">「變更已儲存」「已複製連結」Toast 短暫提示</span></LinkTo>
|
|
39
39
|
</li>
|
|
40
40
|
<li>
|
|
41
|
-
<LinkTo kind="Design System/Internal/Notice/展示" name="中性 純文字"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
41
|
+
<LinkTo kind="Design System/Internal/Notice/展示" name="中性 純文字"><span className="text-primary hover:underline font-medium cursor-pointer">成員邀請待加入提醒 — 中性純文字</span></LinkTo>
|
|
42
42
|
</li>
|
|
43
43
|
</ul>
|
|
44
44
|
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見下方 vs 近親段落)。</p>
|
|
@@ -47,7 +47,7 @@ export const UsageGuidance: Story = {
|
|
|
47
47
|
<Section title="何時不用 + 替代">
|
|
48
48
|
<p>Notice 是 internal primitive,自身有 dismiss 按鈕 + <code>onDismiss</code> callback,但不管 dismiss 後的 mount / unmount 生命週期,也無 auto-dismiss 計時——需要這些行為改用以下 consumer:</p>
|
|
49
49
|
<ul>
|
|
50
|
-
<li><strong>需要管理 dismiss 後移除(永久 inline)</strong> → 用 <code>Alert</code>(內部消費 Notice + 處理 unmount + role="alert")</li>
|
|
50
|
+
<li><strong>需要管理 dismiss 後移除(永久 inline)</strong> → 用 <code>Alert</code>(內部消費 Notice + 處理 unmount + live region:error/warning role="alert"、其餘 role="status")</li>
|
|
51
51
|
<li><strong>需要 auto-dismiss(短暫 toast)</strong> → 用 <code>Toast</code></li>
|
|
52
52
|
<li><strong>表單欄位錯誤訊息</strong> → 用 <code>Field</code> 內建 errorText,不用 Notice</li>
|
|
53
53
|
</ul>
|
|
@@ -74,7 +74,7 @@ export const CompositionRules: Story = {
|
|
|
74
74
|
<div>
|
|
75
75
|
<Section title="Pattern 1 — Alert(persistent inline announcement)">
|
|
76
76
|
<div className="prose prose-sm max-w-prose">
|
|
77
|
-
<p>需要「持續顯示直到 user 主動 dismiss」→ <LinkTo kind="Design System/Components/Alert/展示" name="
|
|
77
|
+
<p>需要「持續顯示直到 user 主動 dismiss」→ <LinkTo kind="Design System/Components/Alert/展示" name="低調單行"><span className="text-primary hover:underline font-medium cursor-pointer">Alert 低調單行</span></LinkTo>。Alert 內部消費 Notice + 加上 dismiss button + live region ARIA(error/warning → role="alert" assertive;info/success/neutral → role="status" polite)。</p>
|
|
78
78
|
<ul>
|
|
79
79
|
<li>典型場景:付款失敗 banner / workspace 警告 / 重要通知 user 必看</li>
|
|
80
80
|
<li>對齊世界級:Polaris <code>Banner</code> / Material <code>Banner</code> / Atlassian <code>InlineMessage</code> — 共識用「persistent + dismissible」</li>
|
|
@@ -25,7 +25,7 @@ Notice 是純視覺 primitive,不是獨立使用的元件。消費者:
|
|
|
25
25
|
|
|
26
26
|
**Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。Notice 語意為 notification(非 row collection),但視覺排版遵循 Family 2 確保跨元件視覺一致。
|
|
27
27
|
|
|
28
|
-
**尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size
|
|
28
|
+
**尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size**——不實作 Family 2 baseline 的 sm/md/lg,padding 也不隨 density 變(`px-4 py-3` 固定)。通知用單一 prominent size 強化「搶注意」的目的性,對齊世界級共識(Material Banner/Snackbar、Polaris Banner、Atlassian InlineMessage、GitHub Flash)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
|
|
29
29
|
|
|
30
30
|
## Typography
|
|
31
31
|
|
|
@@ -107,7 +107,7 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
|
|
|
107
107
|
- **無 SizeMatrix**:Notice / Alert / Toast **單一固定 size**(見本 spec「尺寸偏離」段),不實作 Family 2 baseline 的 sm/md/lg——通知的使命是「搶注意」而非「在密度選擇裡協調」。padding 固定 `px-4 py-3`,typography 固定 md tier(14px),不隨 density 變。
|
|
108
108
|
- **無 ColorMatrix**:Notice 本身**不設 bg / text color**(見本 spec「Theme 策略」段),色彩完全由 consumer(Alert / Toast)透過 `data-theme` + `text-foreground` 控制。Notice 層級的色彩矩陣沒有意義——視覺對照屬於 consumer 的職責,應查 `alert.anatomy.stories.tsx` 與 `toast.anatomy.stories.tsx` 的 ColorMatrix。
|
|
109
109
|
|
|
110
|
-
對應 anatomy story:保留 `Overview` / `Inspector` / `StateBehavior`,額外追加元件特有的 `VariantIconMap`(展示 5 種 variant 對應的 status icon + 語意)。
|
|
110
|
+
對應 anatomy story:保留 `Overview` / `Inspector` / `StateBehavior` / `Accessibility`,額外追加元件特有的 `VariantIconMap`(展示 5 種 variant 對應的 status icon + 語意)。
|
|
111
111
|
|
|
112
112
|
---
|
|
113
113
|
|
|
@@ -115,7 +115,7 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
|
|
|
115
115
|
|
|
116
116
|
- **Disabled(dismiss button)**:Notice 本身不擁有 disabled state(internal primitive,無互動);內嵌的 `<Button iconOnly dismiss size="xs" />` 在 disabled context 內會自動繼承 Button disabled 視覺(`text-fg-disabled` + `cursor-not-allowed`)。Notice **不提供 disable dismiss 的 API**——`...props` 只 spread 到 root `<div>`,dismiss `<Button>` 不接收 / 不 forward 任何 consumer disabled prop,無 consumer-level prop pass-through 可停用 dismiss。對齊消費者 canonical(`../Alert/alert.spec.md`「Disabled(dismiss button)」:banner dismiss 恆可用,對齊 Polaris / Material Banner「通知關閉鈕應永遠可按」);若需防止 close action(API in-flight)被雙擊,consumer 在 `onDismiss` 內自行 debounce / 加上層鎖,不在 UI 層暴露 disabled 透傳。
|
|
117
117
|
- **Loading**:Notice 非 async surface,無 loading state。Body 內若 consumer 注入 CTA Button,該 Button 自行處理 loading。
|
|
118
|
-
- **Empty**:Notice 的 `title` 為必填(
|
|
118
|
+
- **Empty**:Notice 的 `title` 為必填(TypeScript required prop,消費合約),`description` 選填;layout 至少 1 行 title 內容。誤傳空字串時照常 render(無 runtime warn / throw),空 title 的內容責任在 consumer(Alert / Toast)。`neutral` variant 不渲 status icon 時即為 title-only icon-less 形態(見 `NeutralTitleOnly` story),仍合法 render。
|
|
119
119
|
- **Icon-only / variant=neutral**:`neutral` variant 不渲 status icon,layout 自動收斂為 `[title + description?] [endContent?] [dismiss X?]` 三 slot。
|
|
120
120
|
|
|
121
121
|
---
|
|
@@ -137,9 +137,9 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
|
|
|
137
137
|
- Tab — focus dismiss button(若 dismissible)
|
|
138
138
|
- Enter / Space — 觸發 focus 中的 dismiss button(原生 button 行為,呼叫 `onDismiss`)
|
|
139
139
|
|
|
140
|
-
Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dismiss 純粹由 dismiss button 的 `onClick={onDismiss}` 觸發。若 consumer(Alert / Toast)需要 Esc 關閉,於 consumer 層自行掛 keydown。
|
|
140
|
+
Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dismiss 純粹由 dismiss button 的 `onClick={onDismiss}` 觸發。若 consumer(Alert / Toast)需要 Esc 關閉,於 consumer 層自行掛 keydown。Dismiss 後的焦點處置 Notice 同樣不管理(無 focus restoration 邏輯)——節點移除後焦點落點由 consumer(Alert / Toast host)決定。
|
|
141
141
|
|
|
142
|
-
**Focus
|
|
142
|
+
**Focus**:唯一 focusable 元素是 dismiss `<Button>`,focus indicator 走 Button canonical(`focus-visible:ring-2 ring-ring`,box-shadow ring 非 CSS `outline`);Notice 本身無 focus management(dismiss 後焦點處置見上段,由 consumer 決定)。
|
|
143
143
|
|
|
144
144
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
145
145
|
|
|
@@ -147,5 +147,7 @@ Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dis
|
|
|
147
147
|
|
|
148
148
|
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
149
149
|
|
|
150
|
+
- `alert.spec.md`
|
|
150
151
|
- `bulk-action-bar.spec.md`
|
|
151
152
|
- `coachmark.spec.md`
|
|
153
|
+
- `toast.spec.md`
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
|
|
3
|
+
* 不進 root barrel front-door;由 Alert / Toast wrap 消費,end-user app 請用 wrapper 元件。
|
|
4
|
+
*/
|
|
1
5
|
import * as React from 'react'
|
|
2
6
|
import { X as XIcon, Info, CircleCheck, TriangleAlert, XCircle, type LucideIcon } from 'lucide-react'
|
|
3
7
|
import { cn } from '@/lib/utils'
|
|
@@ -186,7 +190,7 @@ export const noticeMeta = {
|
|
|
186
190
|
sizes: {
|
|
187
191
|
|
|
188
192
|
},
|
|
189
|
-
states: ['default',
|
|
193
|
+
states: ['default'], // 無互動 layout primitive(spec「邊界案例」:不擁有 disabled;hover / focus 屬內嵌 dismiss Button)
|
|
190
194
|
tokens: {
|
|
191
195
|
bg: [],
|
|
192
196
|
fg: ['text-error-text', 'text-fg-muted', 'text-fg-secondary', 'text-info-text', 'text-success-text', 'text-warning-text'],
|
|
@@ -45,7 +45,7 @@ const TOKEN_MAP: Record<ModeKey, Record<StateKey, ColorSpec>> = {
|
|
|
45
45
|
disabled: { bg: 'transparent', text: '--fg-disabled', border: 'transparent' },
|
|
46
46
|
},
|
|
47
47
|
readonly: {
|
|
48
|
-
default: { bg: '--bg-
|
|
48
|
+
default: { bg: '--bg-readonly', text: '--foreground', border: 'transparent' },
|
|
49
49
|
hover: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
|
|
50
50
|
focus: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
|
|
51
51
|
error: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
|
|
@@ -254,8 +254,8 @@ export const Overview = {
|
|
|
254
254
|
['precision', 'number', '—', '小數位數'],
|
|
255
255
|
['locale', 'string', "'en-US'", '數字格式 locale'],
|
|
256
256
|
['endAction', 'InlineActionConfig', '—', '右側 inline action(宣告式 API)'],
|
|
257
|
-
['disabled', 'boolean', 'false', '
|
|
258
|
-
['readOnly', 'boolean', 'false', '
|
|
257
|
+
['disabled', 'boolean', 'false', '原生屬性;mode 未顯式指定時解析為 disabled(顯式 mode prop 永遠最優先,useResolvedFieldMode SSOT)'],
|
|
258
|
+
['readOnly', 'boolean', 'false', '原生屬性;mode 未顯式指定且無 Field context mode 時解析為 readonly(優先序 mode > 有效 disabled > fieldCtx.mode > readOnly)'],
|
|
259
259
|
].map(([p, t, d, desc]) => (
|
|
260
260
|
<tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
|
|
261
261
|
))}
|
|
@@ -760,7 +760,7 @@ export const StateBehavior = {
|
|
|
760
760
|
['type="text" inputMode="decimal"', '用 text 而非 number,避免瀏覽器 spinner 干擾'],
|
|
761
761
|
['空字串 / "-" → onChange(null)', '清空或只剩負號時回傳 null'],
|
|
762
762
|
['NaN 忽略', '非數字輸入不觸發 onChange'],
|
|
763
|
-
['disabled / readOnly
|
|
763
|
+
['disabled / readOnly 參與 mode 推導', 'mode 未顯式指定時:有效 disabled → "disabled";readOnly 排在 Field context mode 之後 → "readonly"(顯式 mode prop 永遠最優先,useResolvedFieldMode)'],
|
|
764
764
|
].map(([rule, desc]) => (
|
|
765
765
|
<tr key={rule}><Td mono>{rule}</Td><Td>{desc}</Td></tr>
|
|
766
766
|
))}
|
|
@@ -71,7 +71,7 @@ export const UsageGuidance: Story = {
|
|
|
71
71
|
<Section title="vs 近親元件">
|
|
72
72
|
<Rule
|
|
73
73
|
title="❌ 不用 NumberInput 做電話號碼或郵遞區號 → Input"
|
|
74
|
-
note="
|
|
74
|
+
note="電話、郵遞區號、身分證字號、產品代碼都「長得像數字」但不是算術型 value——不做加減、不做千分位、不做 step。改用 Input + type='tel' / pattern(Stripe 的電話欄用 Input)。用 NumberInput 會錯誤套用千分位、吃掉前導零,且誤導 mobile 彈出數字鍵盤"
|
|
75
75
|
>
|
|
76
76
|
<NumberInput mode="readonly" value={912345678} />
|
|
77
77
|
<Label warn>↑ 電話 0912-345-678 被當數值,顯示時加上千分位 912,345,678 → 數字意義錯誤(前導零也被吃掉)</Label>
|
|
@@ -94,6 +94,14 @@ export const UsageGuidance: Story = {
|
|
|
94
94
|
<NumberInput mode="readonly" value={85.5} suffix="%" precision={1} />
|
|
95
95
|
<NumberInput mode="readonly" value={12500} />
|
|
96
96
|
</Rule>
|
|
97
|
+
|
|
98
|
+
<Rule
|
|
99
|
+
title="❌ 不用 Input 顯示數字"
|
|
100
|
+
note="即使值看起來「就是數字字串」,缺少格式化會讓大數字不可讀(1234567 vs 1,234,567)。Edit 與 Display 分離是 Field 設計的基本前提——用 NumberInput 兩者都得到"
|
|
101
|
+
>
|
|
102
|
+
<Input defaultValue="1234567" />
|
|
103
|
+
<Label warn>↑ 1234567 難讀、無貨幣前綴、無 locale、無右對齊</Label>
|
|
104
|
+
</Rule>
|
|
97
105
|
</Section>
|
|
98
106
|
</div>
|
|
99
107
|
),
|
|
@@ -153,7 +161,7 @@ export const FormatOptionsRule: Story = {
|
|
|
153
161
|
<div>
|
|
154
162
|
<Rule
|
|
155
163
|
title="prefix — 置於數字前的符號(貨幣是最常見場景)"
|
|
156
|
-
note="prefix
|
|
164
|
+
note="prefix 出現在 readonly / display / disabled 與 DataTable cell 的格式化值;edit 模式輸入 raw 純數字、不渲染 prefix——使用者不需要自己輸入 $"
|
|
157
165
|
>
|
|
158
166
|
<NumberInput mode="readonly" value={2490} prefix="$" />
|
|
159
167
|
<NumberInput mode="readonly" value={12500} prefix="NT$" precision={0} />
|
|
@@ -186,36 +194,6 @@ export const FormatOptionsRule: Story = {
|
|
|
186
194
|
),
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<div>
|
|
193
|
-
<Rule
|
|
194
|
-
title="所有數值資料都用 NumberInput——不用 Input type=number"
|
|
195
|
-
note="NumberInput 提供:千分位格式化、locale 切換、prefix/suffix、precision、edit 左 / table 右 對齊、DataTable 自動整合。原生 input type=number 這些都沒有"
|
|
196
|
-
>
|
|
197
|
-
<NumberInput mode="readonly" value={1234567} prefix="$" />
|
|
198
|
-
<NumberInput mode="readonly" value={85.5} suffix="%" precision={1} />
|
|
199
|
-
<NumberInput mode="readonly" value={12500} />
|
|
200
|
-
</Rule>
|
|
201
|
-
|
|
202
|
-
<Rule
|
|
203
|
-
title="❌ 不用 Input 顯示數字"
|
|
204
|
-
note="即使值看起來「就是數字字串」,缺少格式化會讓大數字不可讀(1234567 vs 1,234,567)。Edit 與 Display 分離是 Field 設計的基本前提——用 NumberInput 兩者都得到"
|
|
205
|
-
>
|
|
206
|
-
<Input defaultValue="1234567" />
|
|
207
|
-
<Label warn>↑ 1234567 難讀、無貨幣前綴、無 locale、無右對齊</Label>
|
|
208
|
-
</Rule>
|
|
209
|
-
|
|
210
|
-
<Rule
|
|
211
|
-
title="❌ 看起來像數字但不是算術型的資料:用 Input"
|
|
212
|
-
note="電話、郵遞區號、身分證字號、產品代碼都「長得像數字」但不是算術型 value——不做加減、不做千分位、不做 step。用 NumberInput 會錯誤套用千分位(0912-345-678 變成「912,345,678」)、誤導 mobile 彈出數字鍵盤且關閉符號輸入"
|
|
213
|
-
>
|
|
214
|
-
<NumberInput mode="readonly" value={912345678} />
|
|
215
|
-
<Label warn>↑ 電話 0912-345-678 被當數值,顯示時加上千分位 912,345,678 → 數字意義錯誤(前導零也被吃掉)</Label>
|
|
216
|
-
<Input defaultValue="0912-345-678" />
|
|
217
|
-
<Label>↑ 電話用 Input(可自訂 type=tel 或 pattern),保留 dash / 前導零</Label>
|
|
218
|
-
</Rule>
|
|
219
|
-
</div>
|
|
220
|
-
),
|
|
221
|
-
}
|
|
197
|
+
// @story-trait-rationale: DataTypeMatchRule(數字一律用 NumberInput)retired 2026-06-11 per audit Dim 24/25 —
|
|
198
|
+
// 與 UsageGuidance「vs 近親元件」段完整重複(✅ NumberInput-over-Input / ❌ 電話號碼非算術型);
|
|
199
|
+
// 唯一未覆蓋的「❌ 不用 Input 顯示數字」與「非算術型資料」完整 note 已折入 UsageGuidance。
|
|
@@ -19,6 +19,10 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
|
|
|
19
19
|
|
|
20
20
|
共用規則見 `../Field/field-controls.spec.md`。本文件只記錄 NumberInput 特有的原則。
|
|
21
21
|
|
|
22
|
+
## Controlled-only rationale(Dim 26)
|
|
23
|
+
|
|
24
|
+
本元件採 **controlled-only**:`value` + `onChange`,不支援 `defaultValue` uncontrolled fallback(value pair V1)。對齊 Field 家族 canonical(Combobox / DatePicker / TimePicker / SelectMenu 同,rationale 見各 spec 同名段);NumberInput 另因 raw 輸入 ↔ 格式化值的 parse pipeline 以 `null` 為空值 sentinel,dual-mode 會複製 parse 狀態。未來要改 dual-mode 需 `useControllableState` helper,屬 major API 擴充。
|
|
25
|
+
|
|
22
26
|
**Layout Family**:CLAUDE.md 4-Family Model **Family 4(Field control layout)** 消費者。結構繼承 `components/Field/field-controls.spec.md` 的 `fieldWrapperStyles + [startIcon?] [<editable>] [endAction?]` 規格,視覺對齊 Family 1(Menu item)讓 SelectMenu trigger + options 連續一致。
|
|
23
27
|
|
|
24
28
|
---
|
|
@@ -39,6 +43,8 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
|
|
|
39
43
|
| 視覺調整數值(音量、亮度、滑動調整)| `Slider` | 使用者目標是「感受」而非「輸入精確值」 |
|
|
40
44
|
| 大量帶小數的科學計算 | `Input` + 自訂驗證 | 極端精度需求超出 NumberInput 格式化能力 |
|
|
41
45
|
|
|
46
|
+
**常見誤解**:(1)「看起來像數字」≠ 數值——電話 / 郵遞區號 / 身分證號用 `Input`(見上表);(2)百分比 value 直接存 `85` 非 `0.85`,`suffix='%'` 純顯示;(3)NumberInput **無** step ↑↓ stepper——純值輸入,加減互動走 `endSlot`(見禁止事項)。
|
|
47
|
+
|
|
42
48
|
---
|
|
43
49
|
|
|
44
50
|
## 格式化選項
|
|
@@ -50,6 +56,8 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
|
|
|
50
56
|
| `precision` | 小數位數 | `85.50` |
|
|
51
57
|
| `locale` | 數字格式 locale | 預設 `en-US` |
|
|
52
58
|
|
|
59
|
+
千分位**無獨立 prop**——由 `toLocaleString(locale)` 自動產生(含負號與超大數字分組)。「何時用」列的四種格式化(千分位 / 前綴 / 後綴 / 精度)= 上表 3 個 prop + 此預設行為的映射。
|
|
60
|
+
|
|
53
61
|
## 對齊
|
|
54
62
|
|
|
55
63
|
- **Edit 模式(input)**:靠左——input 內打字是左到右
|
|
@@ -99,6 +107,10 @@ col.accessor('price', {
|
|
|
99
107
|
- **Loading**:NumberInput 不提供 loading state(`NumberInputProps` 無 `loading` prop、無 `CircularProgress` / `aria-busy` 邏輯)。數值輸入為同步操作,無 async fetch 語意;若需 async 場景(如遠端校驗)請走外層 Field validation + `endSlot` 自訂 spinner。
|
|
100
108
|
- **Empty(null / undefined / 空字串)**:Display mode 渲 `—`(em dash + `text-fg-muted`);Edit mode placeholder 走 default placeholder color。
|
|
101
109
|
- **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + `text-fg-error` border + 下方 error message)。
|
|
110
|
+
- **負數 / 超大數字**:`toLocaleString(locale)` 自動處理負號與千分位分組,無特殊 prop。
|
|
111
|
+
- **科學記號輸入**(`1e5`):`Number(raw)` parse 為 `100000`,非 NaN 即觸發 `onChange`(`number-input.tsx:136-138`)。
|
|
112
|
+
- **精度上限**:`precision` > 6 為禁止事項(浮點精度雜訊),極端精度走 `Input` + 自驗證。
|
|
113
|
+
- **RTL**:未實作方向鏡像(edit 靠左 / table cell 靠右皆以 LTR 設計);RTL 屬 DS-wide 決策,未定(與 Chip / Breadcrumb 同口徑)。
|
|
102
114
|
- **Dark mode / density**:走 Field SSOT,不獨立 own。
|
|
103
115
|
|
|
104
116
|
---
|
|
@@ -123,3 +135,10 @@ col.accessor('price', {
|
|
|
123
135
|
|
|
124
136
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
125
137
|
|
|
138
|
+
## 被引用(auto-maintained,Dim 3 reciprocal audit)
|
|
139
|
+
|
|
140
|
+
> 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
|
|
141
|
+
|
|
142
|
+
- `date-picker.spec.md`
|
|
143
|
+
- `input.spec.md`
|
|
144
|
+
- `slider.spec.md`
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// ShapeMatrix(3.)已對照 shape × 色彩 token + consumer 場景。HoverCard
|
|
5
5
|
// content 走深色 tooltip,色彩繼承 tooltip token。
|
|
6
6
|
// StateBehavior N/A — Trigger pill 本身無 hover 視覺(hover 觸發 HoverCard
|
|
7
|
-
// 展開即是 state 表達);無
|
|
7
|
+
// 展開即是 state 表達);無 active / disabled;focus-visible ring 屬 a11y
|
|
8
|
+
// focusable 修正(2026-06-01 #13,見 Accessibility story)非獨立視覺軸。openDelay /
|
|
8
9
|
// closeDelay 等行為已於 Inspector 展示。HoverCard 內容互動由消費的內容
|
|
9
10
|
// 元件(Avatar / Tag)各自負責。
|
|
10
11
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
@@ -321,7 +322,7 @@ function OverflowInspector() {
|
|
|
321
322
|
</tr>
|
|
322
323
|
<tr>
|
|
323
324
|
<Td mono>openDelay</Td>
|
|
324
|
-
<Td mono>
|
|
325
|
+
<Td mono>500ms(HOVER_DELAY_PLAIN_MS)</Td>
|
|
325
326
|
</tr>
|
|
326
327
|
<tr>
|
|
327
328
|
<Td mono>closeDelay</Td>
|
|
@@ -542,7 +543,7 @@ export const Accessibility = {
|
|
|
542
543
|
render: () => (
|
|
543
544
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
544
545
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
545
|
-
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是
|
|
546
|
+
<p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0 + role=\"button\" + aria-haspopup=\"dialog\";2026-06-01 #13 由純 passive 改 focusable,修 WCAG 2.1.1 違反)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger 是 tab stop(focus-visible ring,鍵盤使用者可 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(人員 tag / ProfileCard)由各自內容元件負責 focus 管理。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。"}</p>
|
|
546
547
|
</div>
|
|
547
548
|
),
|
|
548
549
|
}
|
|
@@ -27,10 +27,7 @@ export const UsageGuidance: Story = {
|
|
|
27
27
|
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="Combobox 標籤溢出"><span className="text-primary hover:underline font-medium cursor-pointer">Combobox 標籤溢出</span></LinkTo>
|
|
28
28
|
</li>
|
|
29
29
|
<li>
|
|
30
|
-
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="人員頭像 疊合 +N"><span className="text-primary hover:underline font-medium cursor-pointer"
|
|
31
|
-
</li>
|
|
32
|
-
<li>
|
|
33
|
-
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="形狀對照"><span className="text-primary hover:underline font-medium cursor-pointer">形狀對照</span></LinkTo>
|
|
30
|
+
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="人員頭像 疊合 +N"><span className="text-primary hover:underline font-medium cursor-pointer">PR reviewer 頭像疊合 +N(只顯前 3 位)</span></LinkTo>
|
|
34
31
|
</li>
|
|
35
32
|
<li>
|
|
36
33
|
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="Breadcrumb 中段收合"><span className="text-primary hover:underline font-medium cursor-pointer">Breadcrumb 中段收合</span></LinkTo>
|
|
@@ -39,7 +36,7 @@ export const UsageGuidance: Story = {
|
|
|
39
36
|
<LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="DataTable 人員欄位"><span className="text-primary hover:underline font-medium cursor-pointer">DataTable 人員欄位</span></LinkTo>
|
|
40
37
|
</li>
|
|
41
38
|
</ul>
|
|
42
|
-
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(
|
|
39
|
+
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見下方 vs 近親段落)。</p>
|
|
43
40
|
</div>
|
|
44
41
|
|
|
45
42
|
{/* vs 近親 — VsScrollAreaRule — 原 VsScrollAreaRule */}
|
|
@@ -67,6 +67,15 @@ sm / md 跟 Tag 同階(20/24px),lg 對齊 md(尺寸需求一致,不需
|
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
70
|
+
## 邊界案例
|
|
71
|
+
|
|
72
|
+
- **count ≤ 0**:元件自行不渲染(return `null`)——「無溢出」時 consumer 不需條件渲染
|
|
73
|
+
- **大數值**:`+N` 原樣顯示(無 `99+` 縮寫),trigger `min-w` 起步、隨位數自然加寬
|
|
74
|
+
- **極窄容器 / 貼 viewport 邊**:浮層定位與翻邊由 HoverCard(Radix collision)處理,見 `hover-card.spec.md`
|
|
75
|
+
- **已展開時項目變動**:children 變動觸發浮層寬度重新量測(shrink-wrap re-measure)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
70
79
|
## 禁止事項
|
|
71
80
|
|
|
72
81
|
- ❌ 用 Tooltip 取代 HoverCard——溢出內容可能需要互動
|
|
@@ -116,4 +125,3 @@ OverflowIndicator 是 **composite**(HoverCard trigger + tag-styled `+N` span + H
|
|
|
116
125
|
**Focus**:trigger 是 tab stop(keyboard 可達 + focus-visible ring,讓鍵盤使用者也能 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(如人員 tag / ProfileCard)由各自的內容元件負責 focus 管理。
|
|
117
126
|
|
|
118
127
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
119
|
-
|
|
@@ -120,49 +120,13 @@ export const AvatarStackOverflow: Story = {
|
|
|
120
120
|
),
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
export const Shapes: Story = {
|
|
128
|
-
name: '形狀對照',
|
|
129
|
-
render: () => (
|
|
130
|
-
<div className="flex flex-col gap-6">
|
|
131
|
-
<div className="flex flex-col gap-2">
|
|
132
|
-
<span className="text-caption text-fg-muted">shape="circle" — 搭配 Avatar stack 用,圓形 pill</span>
|
|
133
|
-
<div className="flex items-center gap-3">
|
|
134
|
-
<OverflowIndicator count={3} shape="circle" size="sm">
|
|
135
|
-
<div className="text-caption">sm 20px</div>
|
|
136
|
-
</OverflowIndicator>
|
|
137
|
-
<OverflowIndicator count={12} shape="circle" size="md">
|
|
138
|
-
<div className="text-caption">md 24px</div>
|
|
139
|
-
</OverflowIndicator>
|
|
140
|
-
<OverflowIndicator count={99} shape="circle" size="lg">
|
|
141
|
-
<div className="text-caption">lg 24px</div>
|
|
142
|
-
</OverflowIndicator>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
|
-
<div className="flex flex-col gap-2">
|
|
147
|
-
<span className="text-caption text-fg-muted">shape="tag" — 搭配 Tag 組溢出,rounded-md rectangle</span>
|
|
148
|
-
<div className="flex items-center gap-3">
|
|
149
|
-
<OverflowIndicator count={3} shape="tag" size="sm">
|
|
150
|
-
<div className="text-caption">sm Tag 樣式</div>
|
|
151
|
-
</OverflowIndicator>
|
|
152
|
-
<OverflowIndicator count={12} shape="tag" size="md">
|
|
153
|
-
<div className="text-caption">md Tag 樣式</div>
|
|
154
|
-
</OverflowIndicator>
|
|
155
|
-
<OverflowIndicator count={99} shape="tag" size="lg">
|
|
156
|
-
<div className="text-caption">lg Tag 樣式</div>
|
|
157
|
-
</OverflowIndicator>
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
),
|
|
162
|
-
}
|
|
123
|
+
// @story-trait-rationale: Shapes(形狀對照)retired 2026-06-11 per audit Dim 24/25 —
|
|
124
|
+
// shape × size 全矩陣已由 anatomy ShapeMatrix「Shape × Size 視覺矩陣」+ SizeMatrix
|
|
125
|
+
// (overflow-indicator.anatomy.stories.tsx)完整覆蓋,展示層只留真實業務場景;
|
|
126
|
+
// principles UsageGuidance 對應 LinkTo 已同步移除。
|
|
163
127
|
|
|
164
128
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
165
|
-
Story
|
|
129
|
+
Story 3:Breadcrumb 中段收合(+N 顯示隱藏路徑)
|
|
166
130
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
167
131
|
|
|
168
132
|
export const BreadcrumbCollapse: Story = {
|
|
@@ -192,7 +156,7 @@ export const BreadcrumbCollapse: Story = {
|
|
|
192
156
|
}
|
|
193
157
|
|
|
194
158
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
195
|
-
Story
|
|
159
|
+
Story 4:DataTable row 的指派人員溢出
|
|
196
160
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
197
161
|
|
|
198
162
|
const rows = [
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
|
|
3
|
+
* 不進 root barrel front-door;由 Combobox / PeoplePicker 等 DS 元件 wrap 消費,end-user app 請用 wrapper 元件。
|
|
4
|
+
*/
|
|
1
5
|
import * as React from 'react'
|
|
2
6
|
import { cn } from '@/lib/utils'
|
|
3
7
|
import { HoverCard, HoverCardTrigger, HoverCardContent } from '@/design-system/components/HoverCard/hover-card'
|
|
4
8
|
import { tagVariants } from '@/design-system/components/Tag/tag'
|
|
5
|
-
import {
|
|
9
|
+
import { HOVER_DELAY_PLAIN_MS, HOVER_DELAY_CLOSE_MS } from '@/design-system/tokens/motion/motion'
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* OverflowIndicator — +N 觸發器 + HoverCard 顯示溢出內容
|
|
@@ -126,9 +130,11 @@ const OverflowIndicator = React.forwardRef<HTMLSpanElement, OverflowIndicatorPro
|
|
|
126
130
|
)
|
|
127
131
|
|
|
128
132
|
// 2026-05-18 fix(per user audit「所有 hovercard 應消費 hover delay token」+ motion.spec.md SSOT):
|
|
129
|
-
//
|
|
133
|
+
// plain tier(純列表展開、無 fetch)= HOVER_DELAY_PLAIN_MS,per motion.spec.md 對照表 row;
|
|
134
|
+
// close = HOVER_DELAY_CLOSE_MS。2026-06-11 修:2026-05-18 token 遷移誤挑 rich(原 hardcode 200/300
|
|
135
|
+
// 兩 tier 皆非,遷移未對照 spec 表)— popup 可互動性由 close 緩衝保障,與 open tier 無關。
|
|
130
136
|
return (
|
|
131
|
-
<HoverCard openDelay={
|
|
137
|
+
<HoverCard openDelay={HOVER_DELAY_PLAIN_MS} closeDelay={HOVER_DELAY_CLOSE_MS}>
|
|
132
138
|
<HoverCardTrigger asChild>
|
|
133
139
|
{trigger}
|
|
134
140
|
</HoverCardTrigger>
|
|
@@ -97,12 +97,14 @@ export const Overview: Story = {
|
|
|
97
97
|
export const Inspector: Story = {
|
|
98
98
|
name: '元件檢閱器',
|
|
99
99
|
parameters: {
|
|
100
|
-
docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit / display / readonly / disabled 視覺差異,切 `size` 對照 field-height tier
|
|
100
|
+
docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit / display / readonly / disabled 視覺差異,切 `size` 對照 field-height tier,切 `variant` 看 default / bare / naked chrome 差異。' } },
|
|
101
101
|
},
|
|
102
102
|
args: {
|
|
103
103
|
mode: 'edit',
|
|
104
|
+
variant: 'default',
|
|
104
105
|
size: 'md',
|
|
105
106
|
disabled: false,
|
|
107
|
+
showDisplayEndIcon: false,
|
|
106
108
|
value: SAMPLE_PEOPLE[0],
|
|
107
109
|
people: SAMPLE_PEOPLE,
|
|
108
110
|
searchPlaceholder: '搜尋指派對象…',
|
|
@@ -110,8 +112,10 @@ export const Inspector: Story = {
|
|
|
110
112
|
},
|
|
111
113
|
argTypes: {
|
|
112
114
|
mode: { control: 'radio', options: ['edit', 'display', 'readonly', 'disabled'] },
|
|
115
|
+
variant: { control: 'radio', options: ['default', 'bare', 'naked'] },
|
|
113
116
|
size: { control: 'radio', options: ['sm', 'md', 'lg'] },
|
|
114
117
|
disabled: { control: 'boolean' },
|
|
118
|
+
showDisplayEndIcon: { control: 'boolean' },
|
|
115
119
|
searchPlaceholder: { control: 'text' },
|
|
116
120
|
emptyText: { control: 'text' },
|
|
117
121
|
},
|
|
@@ -131,6 +135,11 @@ export const ModeMatrix: Story = {
|
|
|
131
135
|
<Desc>Field 樣式 + 展開觸發 Popover + Command 搜尋。</Desc>
|
|
132
136
|
<PeoplePicker people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} onChange={() => {}} />
|
|
133
137
|
</div>
|
|
138
|
+
<div>
|
|
139
|
+
<H3>display</H3>
|
|
140
|
+
<Desc>裸 PersonDisplay(Avatar + Name),無 field chrome——DataTable cell / detail panel 純顯示。</Desc>
|
|
141
|
+
<PeoplePicker mode="display" people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} />
|
|
142
|
+
</div>
|
|
134
143
|
<div>
|
|
135
144
|
<H3>readonly</H3>
|
|
136
145
|
<Desc>顯示選中人員(Avatar + Name),無 dropdown trigger、無搜尋。</Desc>
|
|
@@ -236,7 +245,7 @@ export const ColorMatrix: Story = {
|
|
|
236
245
|
</tr>
|
|
237
246
|
<tr>
|
|
238
247
|
<Td mono>readonly</Td>
|
|
239
|
-
<Td><TokenCell token="--bg-
|
|
248
|
+
<Td><TokenCell token="--bg-readonly" display="bg-readonly(鎖定底)" /></Td>
|
|
240
249
|
<Td>—(no border)</Td>
|
|
241
250
|
<Td><TokenCell token="--foreground" /></Td>
|
|
242
251
|
</tr>
|