@qijenchen/design-system 0.1.0-beta.80 → 0.1.0-beta.82
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 +1 -1
- package/dist/components/Alert/alert.d.ts +5 -0
- package/dist/components/Alert/alert.d.ts.map +1 -1
- package/dist/components/Alert/alert.js +4 -1
- package/dist/components/Alert/alert.js.map +1 -1
- package/dist/components/AppShell/app-shell.d.ts +1 -1
- package/dist/components/AppShell/app-shell.js.map +1 -1
- package/dist/components/AspectRatio/aspect-ratio.d.ts +2 -1
- package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -1
- package/dist/components/AspectRatio/aspect-ratio.js +1 -1
- package/dist/components/AspectRatio/aspect-ratio.js.map +1 -1
- package/dist/components/Avatar/avatar.d.ts +3 -2
- package/dist/components/Avatar/avatar.d.ts.map +1 -1
- package/dist/components/Avatar/avatar.js +8 -3
- package/dist/components/Avatar/avatar.js.map +1 -1
- package/dist/components/Badge/badge.d.ts.map +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 +14 -1
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/Breadcrumb/breadcrumb.js +9 -3
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +4 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +2 -2
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/Button/button.d.ts +4 -4
- package/dist/components/Button/button.d.ts.map +1 -1
- package/dist/components/Button/button.js +73 -44
- package/dist/components/Button/button.js.map +1 -1
- package/dist/components/Button/index.d.ts +1 -0
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +3 -0
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Calendar/calendar.d.ts +3 -1
- package/dist/components/Calendar/calendar.d.ts.map +1 -1
- package/dist/components/Calendar/calendar.js +40 -17
- package/dist/components/Calendar/calendar.js.map +1 -1
- package/dist/components/Carousel/carousel.d.ts +1 -1
- package/dist/components/Carousel/carousel.d.ts.map +1 -1
- package/dist/components/Carousel/carousel.js +3 -1
- 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 -1
- package/dist/components/Chart/chart.js.map +1 -1
- package/dist/components/Checkbox/checkbox.d.ts +6 -3
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox/checkbox.js +26 -4
- package/dist/components/Checkbox/checkbox.js.map +1 -1
- package/dist/components/Checkbox/index.d.ts +1 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.js +3 -0
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/Chip/chip.d.ts +9 -3
- package/dist/components/Chip/chip.d.ts.map +1 -1
- package/dist/components/Chip/chip.js +46 -13
- package/dist/components/Chip/chip.js.map +1 -1
- package/dist/components/Coachmark/coachmark.d.ts +5 -3
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
- package/dist/components/Coachmark/coachmark.js +10 -7
- package/dist/components/Coachmark/coachmark.js.map +1 -1
- package/dist/components/Combobox/combobox.d.ts +3 -1
- package/dist/components/Combobox/combobox.d.ts.map +1 -1
- package/dist/components/Combobox/combobox.js +11 -7
- package/dist/components/Combobox/combobox.js.map +1 -1
- package/dist/components/Command/command.d.ts +2 -2
- package/dist/components/Command/command.d.ts.map +1 -1
- package/dist/components/Command/command.js +4 -2
- package/dist/components/Command/command.js.map +1 -1
- package/dist/components/DataTable/active-editor-controller.d.ts +4 -3
- package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
- package/dist/components/DataTable/cell-registry.js +3 -0
- package/dist/components/DataTable/cell-registry.js.map +1 -1
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +4 -3
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +38 -7
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +213 -63
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/dist/components/DataTable/filter-tree.d.ts +5 -0
- package/dist/components/DataTable/filter-tree.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.d.ts +3 -3
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
- package/dist/components/DateGrid/date-grid.js +52 -6
- package/dist/components/DateGrid/date-grid.js.map +1 -1
- package/dist/components/DatePicker/date-picker.d.ts +2 -8
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
- package/dist/components/DatePicker/date-picker.js +139 -109
- package/dist/components/DatePicker/date-picker.js.map +1 -1
- package/dist/components/DescriptionList/description-list.d.ts.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 +1 -1
- package/dist/components/Dialog/dialog.d.ts.map +1 -1
- package/dist/components/Dialog/dialog.js +2 -1
- package/dist/components/Dialog/dialog.js.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +4 -4
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/DropdownMenu/dropdown-menu.js +25 -8
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
- package/dist/components/Empty/empty.d.ts.map +1 -1
- package/dist/components/Empty/empty.js +1 -1
- package/dist/components/Empty/empty.js.map +1 -1
- package/dist/components/Field/field-wrapper.d.ts +1 -0
- package/dist/components/Field/field-wrapper.d.ts.map +1 -1
- package/dist/components/Field/field-wrapper.js +27 -7
- package/dist/components/Field/field-wrapper.js.map +1 -1
- package/dist/components/Field/field.d.ts +1 -1
- package/dist/components/Field/field.d.ts.map +1 -1
- package/dist/components/Field/field.js +2 -1
- package/dist/components/Field/field.js.map +1 -1
- package/dist/components/Field/use-form-validation.d.ts +5 -1
- package/dist/components/Field/use-form-validation.d.ts.map +1 -1
- package/dist/components/Field/use-form-validation.js +31 -21
- package/dist/components/Field/use-form-validation.js.map +1 -1
- package/dist/components/FieldControlGroup/field-control-group.d.ts +3 -3
- 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 +3 -2
- 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.d.ts.map +1 -1
- package/dist/components/FileUpload/file-upload.js +22 -10
- package/dist/components/FileUpload/file-upload.js.map +1 -1
- package/dist/components/FileViewer/can-render-image.d.ts +6 -0
- package/dist/components/FileViewer/can-render-image.d.ts.map +1 -0
- package/dist/components/FileViewer/can-render-image.js +11 -0
- package/dist/components/FileViewer/can-render-image.js.map +1 -0
- package/dist/components/FileViewer/file-viewer.d.ts +2 -2
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
- package/dist/components/FileViewer/file-viewer.js +24 -16
- package/dist/components/FileViewer/file-viewer.js.map +1 -1
- package/dist/components/FileViewer/image-renderer.d.ts +0 -5
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
- package/dist/components/FileViewer/image-renderer.js +1 -9
- 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 +3 -1
- package/dist/components/HoverCard/hover-card.js.map +1 -1
- package/dist/components/Input/input.d.ts +26 -3
- package/dist/components/Input/input.d.ts.map +1 -1
- package/dist/components/Input/input.js +12 -8
- package/dist/components/Input/input.js.map +1 -1
- package/dist/components/LinkInput/link-input.d.ts +3 -3
- package/dist/components/LinkInput/link-input.d.ts.map +1 -1
- package/dist/components/LinkInput/link-input.js +29 -28
- package/dist/components/LinkInput/link-input.js.map +1 -1
- package/dist/components/Menu/menu-item.d.ts.map +1 -1
- package/dist/components/Menu/menu-item.js +5 -4
- package/dist/components/Menu/menu-item.js.map +1 -1
- package/dist/components/Notice/notice.d.ts +5 -0
- package/dist/components/Notice/notice.d.ts.map +1 -1
- package/dist/components/Notice/notice.js +11 -5
- package/dist/components/Notice/notice.js.map +1 -1
- package/dist/components/NumberInput/number-input.d.ts +1 -1
- package/dist/components/NumberInput/number-input.d.ts.map +1 -1
- package/dist/components/NumberInput/number-input.js +17 -8
- package/dist/components/NumberInput/number-input.js.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js +2 -1
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
- package/dist/components/Pagination/index.d.ts +2 -0
- package/dist/components/Pagination/index.d.ts.map +1 -0
- package/dist/components/Pagination/index.js +6 -0
- package/dist/components/Pagination/index.js.map +1 -0
- package/dist/components/Pagination/pagination.d.ts +49 -0
- package/dist/components/Pagination/pagination.d.ts.map +1 -0
- package/dist/components/Pagination/pagination.js +182 -0
- package/dist/components/Pagination/pagination.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker.d.ts +3 -3
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
- package/dist/components/PeoplePicker/people-picker.js +38 -36
- package/dist/components/PeoplePicker/people-picker.js.map +1 -1
- package/dist/components/PeoplePicker/person-display.d.ts +4 -0
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
- package/dist/components/PeoplePicker/person-display.js +3 -3
- 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 +58 -32
- package/dist/components/Popover/popover.js.map +1 -1
- package/dist/components/ProfileCard/profile-card.d.ts +11 -3
- package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
- package/dist/components/ProfileCard/profile-card.js +14 -4
- package/dist/components/ProfileCard/profile-card.js.map +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts +1 -1
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
- package/dist/components/RadioGroup/radio-group.js +28 -3
- package/dist/components/RadioGroup/radio-group.js.map +1 -1
- package/dist/components/Rating/rating.js +3 -3
- package/dist/components/Rating/rating.js.map +1 -1
- package/dist/components/ScrollArea/scroll-area.d.ts +1 -1
- package/dist/components/ScrollArea/scroll-area.js +2 -2
- package/dist/components/ScrollArea/scroll-area.js.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.d.ts +2 -2
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
- package/dist/components/SegmentedControl/segmented-control.js +23 -10
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
- package/dist/components/Select/select.d.ts +10 -4
- package/dist/components/Select/select.d.ts.map +1 -1
- package/dist/components/Select/select.js +57 -14
- package/dist/components/Select/select.js.map +1 -1
- package/dist/components/SelectMenu/index.js +4 -2
- package/dist/components/SelectMenu/select-menu.d.ts +31 -6
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
- package/dist/components/SelectMenu/select-menu.js +169 -85
- package/dist/components/SelectMenu/select-menu.js.map +1 -1
- package/dist/components/Separator/separator.js +1 -1
- package/dist/components/Separator/separator.js.map +1 -1
- package/dist/components/Sheet/sheet.d.ts +1 -1
- package/dist/components/Sheet/sheet.d.ts.map +1 -1
- package/dist/components/Sheet/sheet.js +3 -2
- package/dist/components/Sheet/sheet.js.map +1 -1
- package/dist/components/Sidebar/sidebar.d.ts +2 -2
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
- package/dist/components/Sidebar/sidebar.js +28 -10
- 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 -2
- 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.map +1 -1
- package/dist/components/Steps/steps.js +6 -3
- package/dist/components/Steps/steps.js.map +1 -1
- package/dist/components/Switch/switch.d.ts +2 -2
- package/dist/components/Switch/switch.d.ts.map +1 -1
- package/dist/components/Switch/switch.js +47 -9
- package/dist/components/Switch/switch.js.map +1 -1
- package/dist/components/Tabs/tabs.d.ts +8 -5
- package/dist/components/Tabs/tabs.d.ts.map +1 -1
- package/dist/components/Tabs/tabs.js +45 -33
- package/dist/components/Tabs/tabs.js.map +1 -1
- package/dist/components/Tag/tag.d.ts.map +1 -1
- package/dist/components/Tag/tag.js +20 -4
- package/dist/components/Tag/tag.js.map +1 -1
- package/dist/components/Textarea/textarea.d.ts +2 -1
- package/dist/components/Textarea/textarea.d.ts.map +1 -1
- package/dist/components/Textarea/textarea.js +24 -13
- package/dist/components/Textarea/textarea.js.map +1 -1
- package/dist/components/TimePicker/time-picker.d.ts +2 -2
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
- package/dist/components/TimePicker/time-picker.js +23 -12
- package/dist/components/TimePicker/time-picker.js.map +1 -1
- package/dist/components/Toast/toast.d.ts +1 -1
- package/dist/components/Toast/toast.d.ts.map +1 -1
- package/dist/components/Toast/toast.js +7 -3
- package/dist/components/Toast/toast.js.map +1 -1
- package/dist/components/Tooltip/tooltip.js +1 -1
- package/dist/components/Tooltip/tooltip.js.map +1 -1
- package/dist/components/TreeView/tree-view.d.ts +1 -1
- package/dist/components/TreeView/tree-view.d.ts.map +1 -1
- package/dist/components/TreeView/tree-view.js +11 -5
- package/dist/components/TreeView/tree-view.js.map +1 -1
- package/dist/hooks/use-controllable.d.ts.map +1 -1
- package/dist/hooks/use-controllable.js +4 -2
- package/dist/hooks/use-controllable.js.map +1 -1
- package/dist/hooks/use-is-touch-device.d.ts.map +1 -1
- package/dist/hooks/use-is-touch-device.js +3 -1
- package/dist/hooks/use-is-touch-device.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -2
- 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/patterns/overlay-surface/overlay-surface.js.map +1 -1
- package/dist/tokens/categorical-color.d.ts +1 -1
- package/dist/tokens/categorical-color.js.map +1 -1
- package/dist/tokens/uiSize/icon-size.d.ts +2 -2
- package/ds-canonical/fork/governance.lock +1 -1
- package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +10 -1
- package/ds-canonical/hooks/check_audit_post_report_validator.sh +13 -0
- package/ds-canonical/hooks/check_full_story_visual_interaction_sweep.sh +4 -3
- package/ds-canonical/hooks/check_opacity_token_usage.sh +10 -1
- package/ds-canonical/hooks/check_plugin_fork_health.sh +30 -22
- package/ds-canonical/hooks/check_story_invariants.sh +17 -5
- package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +5 -2
- package/ds-canonical/references/principle-dim-map.json +100 -0
- package/ds-canonical/references/story-baseline-registry.json +4 -3
- package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +1 -1
- package/ds-canonical/skills/design-system-audit/SKILL.md +2 -2
- package/ds-story-manifest.json +41 -18
- package/llms-full.txt +11 -1
- package/llms.txt +3 -1
- package/package.json +1 -1
- package/src/components/Alert/alert.anatomy.stories.tsx +9 -6
- package/src/components/Alert/alert.spec.md +3 -3
- package/src/components/Alert/alert.tsx +9 -1
- package/src/components/AppShell/app-shell.anatomy.stories.tsx +3 -0
- package/src/components/AppShell/app-shell.spec.md +3 -2
- package/src/components/AppShell/app-shell.tsx +1 -1
- package/src/components/AspectRatio/aspect-ratio.spec.md +1 -2
- package/src/components/AspectRatio/aspect-ratio.tsx +3 -2
- package/src/components/Avatar/avatar.principles.stories.tsx +1 -1
- package/src/components/Avatar/avatar.spec.md +10 -30
- package/src/components/Avatar/avatar.stories.tsx +1 -1
- package/src/components/Avatar/avatar.tsx +30 -16
- package/src/components/Badge/badge.anatomy.stories.tsx +2 -2
- package/src/components/Badge/badge.spec.md +5 -4
- package/src/components/Badge/badge.tsx +4 -1
- package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +2 -2
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +15 -10
- package/src/components/Breadcrumb/breadcrumb.spec.md +5 -3
- package/src/components/Breadcrumb/breadcrumb.tsx +10 -4
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +3 -2
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -14
- package/src/components/BulkActionBar/bulk-action-bar.tsx +10 -4
- package/src/components/Button/button.anatomy.stories.tsx +6 -6
- package/src/components/Button/button.spec.md +3 -2
- package/src/components/Button/button.tsx +67 -27
- package/src/components/Button/index.ts +1 -0
- package/src/components/Calendar/calendar.anatomy.stories.tsx +5 -3
- package/src/components/Calendar/calendar.principles.stories.tsx +3 -1
- package/src/components/Calendar/calendar.spec.md +9 -2
- package/src/components/Calendar/calendar.stories.tsx +3 -1
- package/src/components/Calendar/calendar.tsx +53 -19
- package/src/components/Carousel/carousel.principles.stories.tsx +1 -1
- package/src/components/Carousel/carousel.tsx +4 -1
- package/src/components/Chart/chart.spec.md +1 -1
- package/src/components/Chart/chart.tsx +2 -1
- package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
- package/src/components/Checkbox/checkbox.spec.md +1 -1
- package/src/components/Checkbox/checkbox.tsx +41 -7
- package/src/components/Checkbox/index.ts +1 -0
- package/src/components/Chip/chip.anatomy.stories.tsx +9 -9
- package/src/components/Chip/chip.principles.stories.tsx +3 -3
- package/src/components/Chip/chip.spec.md +7 -4
- package/src/components/Chip/chip.tsx +60 -15
- package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +1 -1
- package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -5
- package/src/components/CircularProgress/circular-progress.spec.md +2 -0
- package/src/components/CircularProgress/circular-progress.stories.tsx +3 -11
- package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
- package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
- package/src/components/Coachmark/coachmark.spec.md +3 -3
- package/src/components/Coachmark/coachmark.tsx +23 -13
- package/src/components/Combobox/combobox.anatomy.stories.tsx +4 -4
- package/src/components/Combobox/combobox.spec.md +1 -1
- package/src/components/Combobox/combobox.tsx +30 -17
- package/src/components/Command/command.principles.stories.tsx +10 -12
- package/src/components/Command/command.spec.md +5 -5
- package/src/components/Command/command.stories.tsx +4 -4
- package/src/components/Command/command.tsx +3 -2
- package/src/components/DataTable/active-editor-controller.ts +4 -3
- package/src/components/DataTable/cell-registry.tsx +8 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +8 -2
- package/src/components/DataTable/data-table-interaction-layer.tsx +8 -7
- package/src/components/DataTable/data-table.anatomy.stories.tsx +4 -4
- package/src/components/DataTable/data-table.css +2 -2
- package/src/components/DataTable/data-table.spec.md +72 -115
- package/src/components/DataTable/data-table.stories.tsx +51 -3
- package/src/components/DataTable/data-table.tsx +348 -63
- package/src/components/DataTable/filter-operators.spec.md +4 -4
- package/src/components/DataTable/filter-tree.ts +192 -42
- package/src/components/DateGrid/date-grid.anatomy.stories.tsx +1 -1
- package/src/components/DateGrid/date-grid.spec.md +11 -8
- package/src/components/DateGrid/date-grid.tsx +63 -8
- package/src/components/DatePicker/date-picker.principles.stories.tsx +1 -1
- package/src/components/DatePicker/date-picker.spec.md +1 -0
- package/src/components/DatePicker/date-picker.stories.tsx +19 -0
- package/src/components/DatePicker/date-picker.tsx +52 -15
- package/src/components/DescriptionList/description-list.spec.md +1 -1
- package/src/components/DescriptionList/description-list.tsx +3 -1
- package/src/components/Dialog/dialog.spec.md +1 -1
- package/src/components/Dialog/dialog.tsx +2 -1
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +3 -1
- package/src/components/DropdownMenu/dropdown-menu.spec.md +8 -5
- package/src/components/DropdownMenu/dropdown-menu.tsx +33 -7
- package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
- package/src/components/Empty/empty.spec.md +2 -2
- package/src/components/Empty/empty.stories.tsx +4 -15
- package/src/components/Empty/empty.tsx +4 -1
- package/src/components/Field/field-controls.spec.md +2 -1
- package/src/components/Field/field-wrapper.tsx +28 -8
- package/src/components/Field/field.anatomy.stories.tsx +7 -7
- package/src/components/Field/field.principles.stories.tsx +1 -1
- package/src/components/Field/field.spec.md +9 -7
- package/src/components/Field/field.tsx +2 -1
- package/src/components/Field/form-validation.spec.md +6 -3
- package/src/components/Field/use-form-validation.ts +49 -21
- package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +11 -10
- package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
- package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
- package/src/components/FieldControlGroup/field-control-group.tsx +3 -3
- package/src/components/FileItem/file-item.anatomy.stories.tsx +6 -4
- package/src/components/FileItem/file-item.tsx +3 -2
- package/src/components/FileUpload/file-upload.anatomy.stories.tsx +1 -1
- package/src/components/FileUpload/file-upload.spec.md +4 -1
- package/src/components/FileUpload/file-upload.tsx +36 -10
- package/src/components/FileViewer/can-render-image.ts +15 -0
- package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +6 -4
- package/src/components/FileViewer/file-viewer.spec.md +2 -2
- package/src/components/FileViewer/file-viewer.tsx +47 -21
- package/src/components/FileViewer/image-renderer.tsx +3 -8
- package/src/components/HoverCard/hover-card.spec.md +1 -1
- package/src/components/HoverCard/hover-card.tsx +3 -1
- package/src/components/Input/input.anatomy.stories.tsx +4 -4
- package/src/components/Input/input.principles.stories.tsx +1 -1
- package/src/components/Input/input.spec.md +1 -1
- package/src/components/Input/input.stories.tsx +11 -5
- package/src/components/Input/input.tsx +11 -9
- package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -0
- package/src/components/LinkInput/link-input.tsx +49 -34
- package/src/components/Menu/menu-item.anatomy.stories.tsx +1 -1
- package/src/components/Menu/menu-item.spec.md +4 -3
- package/src/components/Menu/menu-item.tsx +15 -4
- package/src/components/Notice/notice.anatomy.stories.tsx +10 -5
- package/src/components/Notice/notice.spec.md +4 -3
- package/src/components/Notice/notice.tsx +22 -5
- package/src/components/NumberInput/number-input.anatomy.stories.tsx +5 -4
- package/src/components/NumberInput/number-input.principles.stories.tsx +2 -1
- package/src/components/NumberInput/number-input.spec.md +2 -1
- package/src/components/NumberInput/number-input.tsx +25 -9
- package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +3 -3
- package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
- package/src/components/OverflowIndicator/overflow-indicator.tsx +2 -1
- package/src/components/Pagination/index.ts +5 -0
- package/src/components/Pagination/pagination.anatomy.stories.tsx +143 -0
- package/src/components/Pagination/pagination.principles.stories.tsx +81 -0
- package/src/components/Pagination/pagination.spec.md +150 -0
- package/src/components/Pagination/pagination.stories.tsx +98 -0
- package/src/components/Pagination/pagination.tsx +263 -0
- package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.spec.md +4 -4
- package/src/components/PeoplePicker/people-picker.stories.tsx +1 -1
- package/src/components/PeoplePicker/people-picker.tsx +65 -55
- package/src/components/PeoplePicker/person-display.tsx +10 -4
- package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
- package/src/components/Popover/popover.spec.md +13 -14
- package/src/components/Popover/popover.tsx +88 -39
- package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +4 -4
- package/src/components/ProfileCard/profile-card.principles.stories.tsx +2 -2
- package/src/components/ProfileCard/profile-card.spec.md +1 -2
- package/src/components/ProfileCard/profile-card.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.tsx +29 -8
- package/src/components/RadioGroup/radio-group.principles.stories.tsx +1 -1
- package/src/components/RadioGroup/radio-group.spec.md +2 -2
- package/src/components/RadioGroup/radio-group.stories.tsx +3 -1
- package/src/components/RadioGroup/radio-group.tsx +37 -3
- package/src/components/Rating/rating.anatomy.stories.tsx +11 -8
- package/src/components/Rating/rating.principles.stories.tsx +1 -1
- package/src/components/Rating/rating.spec.md +2 -2
- package/src/components/Rating/rating.stories.tsx +1 -1
- package/src/components/Rating/rating.tsx +3 -3
- package/src/components/ScrollArea/scroll-area.spec.md +1 -0
- package/src/components/ScrollArea/scroll-area.tsx +1 -1
- package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +3 -3
- package/src/components/SegmentedControl/segmented-control.spec.md +7 -3
- package/src/components/SegmentedControl/segmented-control.tsx +29 -11
- package/src/components/Select/select.anatomy.stories.tsx +2 -2
- package/src/components/Select/select.spec.md +3 -2
- package/src/components/Select/select.tsx +62 -19
- package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +1 -1
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +1 -1
- package/src/components/SelectMenu/select-menu.spec.md +12 -8
- package/src/components/SelectMenu/select-menu.tsx +176 -20
- package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
- package/src/components/SelectionControl/selection-item.spec.md +2 -1
- package/src/components/SelectionControl/selection-item.stories.tsx +1 -1
- package/src/components/Separator/separator.anatomy.stories.tsx +2 -2
- package/src/components/Separator/separator.tsx +1 -1
- package/src/components/Sheet/sheet.spec.md +2 -1
- package/src/components/Sheet/sheet.tsx +4 -2
- package/src/components/Sidebar/sidebar.anatomy.stories.tsx +1 -1
- package/src/components/Sidebar/sidebar.spec.md +2 -1
- package/src/components/Sidebar/sidebar.stories.tsx +6 -4
- package/src/components/Sidebar/sidebar.tsx +41 -13
- package/src/components/Skeleton/skeleton.principles.stories.tsx +1 -1
- package/src/components/Skeleton/skeleton.spec.md +1 -2
- package/src/components/Skeleton/skeleton.tsx +1 -1
- package/src/components/Slider/slider.anatomy.stories.tsx +4 -4
- package/src/components/Slider/slider.spec.md +19 -85
- package/src/components/Slider/slider.tsx +13 -5
- package/src/components/Steps/steps.anatomy.stories.tsx +1 -1
- package/src/components/Steps/steps.spec.md +6 -4
- package/src/components/Steps/steps.tsx +11 -3
- package/src/components/Switch/switch.spec.md +4 -3
- package/src/components/Switch/switch.tsx +59 -10
- package/src/components/Tabs/tabs.anatomy.stories.tsx +7 -6
- package/src/components/Tabs/tabs.principles.stories.tsx +5 -3
- package/src/components/Tabs/tabs.spec.md +15 -48
- package/src/components/Tabs/tabs.tsx +70 -34
- package/src/components/Tag/tag.principles.stories.tsx +2 -2
- package/src/components/Tag/tag.spec.md +11 -43
- package/src/components/Tag/tag.tsx +30 -4
- package/src/components/Textarea/textarea.principles.stories.tsx +2 -1
- package/src/components/Textarea/textarea.spec.md +2 -1
- package/src/components/Textarea/textarea.tsx +20 -10
- package/src/components/TimePicker/time-picker.anatomy.stories.tsx +2 -1
- package/src/components/TimePicker/time-picker.spec.md +2 -2
- package/src/components/TimePicker/time-picker.tsx +35 -16
- package/src/components/Toast/toast.anatomy.stories.tsx +5 -6
- package/src/components/Toast/toast.principles.stories.tsx +10 -11
- package/src/components/Toast/toast.spec.md +5 -5
- package/src/components/Toast/toast.stories.tsx +5 -1
- package/src/components/Toast/toast.tsx +13 -7
- package/src/components/Tooltip/tooltip.spec.md +3 -3
- package/src/components/Tooltip/tooltip.tsx +1 -1
- package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -1
- package/src/components/TreeView/tree-view.principles.stories.tsx +2 -2
- package/src/components/TreeView/tree-view.spec.md +2 -2
- package/src/components/TreeView/tree-view.tsx +27 -5
- package/src/hooks/use-controllable.ts +7 -2
- package/src/hooks/use-is-touch-device.ts +8 -1
- package/src/index.ts +2 -1
- package/src/patterns/element-anatomy/element-anatomy.spec.md +3 -3
- package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
- package/src/patterns/element-anatomy/item-anatomy.spec.md +5 -14
- package/src/patterns/element-anatomy/item-anatomy.stories.tsx +1 -0
- package/src/patterns/element-anatomy/item-anatomy.tsx +5 -6
- package/src/patterns/header-canonical/header-canonical.css +1 -2
- package/src/patterns/header-canonical/header-canonical.spec.md +5 -5
- package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +5 -4
- package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +137 -0
- package/src/patterns/overlay-surface/overlay-surface.spec.md +8 -7
- package/src/patterns/overlay-surface/overlay-surface.stories.tsx +116 -0
- package/src/patterns/overlay-surface/overlay-surface.tsx +5 -5
- package/src/patterns/resize-handle/resize-handle.spec.md +1 -1
- package/src/tokens/categorical-color.ts +1 -1
- package/src/tokens/color/color.spec.md +11 -13
- package/src/tokens/color/color.stories.tsx +1 -1
- package/src/tokens/color/primitives.css +7 -5
- package/src/tokens/color/semantic.css +8 -2
- package/src/tokens/density/density.spec.md +2 -0
- package/src/tokens/elevation/elevation.spec.md +1 -1
- package/src/tokens/layoutSpace/layoutSpace.spec.md +2 -1
- package/src/tokens/layoutSpace/layoutSpace.stories.tsx +3 -3
- package/src/tokens/motion/motion.spec.md +1 -1
- package/src/tokens/motion/motion.stories.tsx +142 -0
- package/src/tokens/opacity/opacity.spec.md +1 -1
- package/src/tokens/opacity/opacity.stories.tsx +7 -11
- package/src/tokens/radius/radius.spec.md +1 -1
- package/src/tokens/typography/typography.css +1 -1
- package/src/tokens/typography/typography.spec.md +1 -1
- package/src/tokens/uiSize/icon-size.ts +2 -2
- package/src/tokens/uiSize/uiSize.spec.md +12 -11
- package/src/tokens/uiSize/uiSize.stories.tsx +103 -0
- package/src/tokens/utility-registry.json +5 -4
- package/dist/node_modules/react-hook-form/dist/index.esm.js +0 -1950
- package/dist/node_modules/react-hook-form/dist/index.esm.js.map +0 -1
|
@@ -150,6 +150,7 @@ Menu 的設計目的是「**快速掃視多個選項挑一個**」。垂直空
|
|
|
150
150
|
| default | transparent | foreground | — |
|
|
151
151
|
| hover | `--neutral-hover` | foreground | 滑鼠 hover |
|
|
152
152
|
| selected(單選) | `--neutral-selected` | foreground | bg 高亮(不用 ✓ 勾號,避免影響 prefix 對齊) |
|
|
153
|
+
| **selected × hover(疊加)** | `--neutral-selected`(**selected 勝**) | foreground | 2026-07-04 Q2 拍板 M5 明文:bg 是唯一選中指示器,hover 不得洗掉。code = selected 時關 hover bg(menu-item.tsx)。對齊 Ant Menu `:not(-item-selected)` / VS Code list `:hover:not(.selected)`;消費者(DropdownMenu highlighted)同規則 |
|
|
153
154
|
| selected(多選) | transparent | foreground | checkbox 勾選 |
|
|
154
155
|
| disabled | transparent | `--fg-disabled` | disabled prop |
|
|
155
156
|
|
|
@@ -223,7 +224,7 @@ Menu item 的 prefix icon 跟 label 同色(foreground),不是 fg-muted。P
|
|
|
223
224
|
| 建立操作選單(複製 / 刪除 / 分享)| 用 `DropdownMenu` + `DropdownMenuItem`(內部消費 MenuItem)|
|
|
224
225
|
| 建立選值下拉(選項 + 搜尋)| 用 `SelectMenu`(內部消費 MenuItem)|
|
|
225
226
|
| 建立右鍵選單 | 用未來的 `ContextMenu`(待開發)|
|
|
226
|
-
| 直接在 JSX 中用 `<MenuItem>` | ❌ **禁止**——會失去 menu 外層的 Radix 無障礙 / 鍵盤 /
|
|
227
|
+
| 直接在 JSX 中用 `<MenuItem>` | ❌ **禁止**——會失去 menu 外層的 Radix 無障礙 / 鍵盤 / 焦點管理。唯一例外:本元件**自身 stories** 的 internal 展示(demo 容器以 `role="listbox"` 滿足 a11y parent 要求,見 `menu-item.stories.tsx`),產品 code 無豁免 |
|
|
227
228
|
|
|
228
229
|
### 消費者
|
|
229
230
|
|
|
@@ -259,7 +260,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
|
|
|
259
260
|
|
|
260
261
|
## 邊界案例
|
|
261
262
|
|
|
262
|
-
- **Disabled**:`disabled` prop 由 MenuItem primitive own;視覺 `text-fg-disabled`(neutral-6,M24 state>emphasis)、無 hover bg、`aria-disabled="true"
|
|
263
|
+
- **Disabled**:`disabled` prop 由 MenuItem primitive own;視覺 `text-fg-disabled`(neutral-6,M24 state>emphasis)、無 hover bg、`aria-disabled="true"`(巢狀 `role="presentation"` 用法時抑制、由外層 primitive 宣告,見「A11y 預設」)、Enter / click 不觸發 onSelect、鍵盤導覽自動 skip(由 consumer SelectMenu / DropdownMenu / cmdk 處理)。已在「選擇 / 狀態視覺規則」段 codify。
|
|
263
264
|
- **Loading**:MenuItem 為單一 row primitive 非 async surface,本身不擁有 loading prop。Async option list 的 loading 由 consumer(SelectMenu / Combobox / DropdownMenu)在 list body 替換為 `<Empty icon={<CircularProgress/>}/>`(SelectMenu SSOT)。
|
|
264
265
|
- **Empty(label-only / icon-only)**:label 為必傳;若無 prefix icon / avatar / checkbox,layout 自動收斂為 `[label] [suffix?]`;若無 suffix(shortcut / endAction / chevron),收斂為純 `[label]`。
|
|
265
266
|
- **極長 label / description**:預設各 clamp 1 行 truncate(見「Clamp 政策」),row 高度恆為兩種之一不被撐高。
|
|
@@ -278,7 +279,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
|
|
|
278
279
|
|
|
279
280
|
## A11y 預設
|
|
280
281
|
|
|
281
|
-
**ARIA / Pattern**:對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern
|
|
282
|
+
**ARIA / Pattern**:對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。直接使用時 MenuItem 預設渲染 `role="option"` + `aria-selected` / `aria-disabled`;consumer 把 MenuItem 巢狀在 Radix / cmdk 互動節點內時傳 `role="presentation"`,MenuItem 同步抑制 `aria-selected` / `aria-disabled`(presentation 節點不得掛 ARIA state;ARIA 單一 owner = 外層 primitive),僅保留 `data-selected` / `data-disabled` 供樣式。
|
|
282
283
|
|
|
283
284
|
**Keyboard 行為**(由外層選單元件提供,MenuItem 本身不實作任何 key handler,只渲染 row 視覺):
|
|
284
285
|
|
|
@@ -185,12 +185,21 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
185
185
|
)
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// ── ARIA 單一 owner gate(2026-07-05)──
|
|
189
|
+
// consumer(DropdownMenu 各 item / SelectMenu option row)把 MenuItem 巢狀在 Radix / cmdk
|
|
190
|
+
// 互動節點內時傳 role="presentation":外層 primitive 是唯一 ARIA owner(aria-checked /
|
|
191
|
+
// aria-disabled 由外層宣告)。presentation 節點不得掛 ARIA state(axe aria-prohibited-attr
|
|
192
|
+
// + 內外雙重宣告)→ 同步抑制 role="option" 與 aria-selected / aria-disabled 預設;
|
|
193
|
+
// data-selected / data-disabled 保留(純樣式 hook,非 ARIA)。正規 listbox option 用法
|
|
194
|
+
//(不傳 role)與 select-all row(role="checkbox")不受影響。
|
|
195
|
+
const isPresentation = props.role === 'presentation'
|
|
196
|
+
|
|
188
197
|
return (
|
|
189
198
|
<div
|
|
190
199
|
ref={ref}
|
|
191
|
-
role=
|
|
192
|
-
aria-selected={selected || (checked === true) || undefined}
|
|
193
|
-
aria-disabled={disabled || undefined}
|
|
200
|
+
role={isPresentation ? 'presentation' : 'option'}
|
|
201
|
+
aria-selected={isPresentation ? undefined : selected || (checked === true) || undefined}
|
|
202
|
+
aria-disabled={isPresentation ? undefined : disabled || undefined}
|
|
194
203
|
data-selected={selected ? '' : undefined}
|
|
195
204
|
data-disabled={disabled ? '' : undefined}
|
|
196
205
|
className={cn(
|
|
@@ -202,9 +211,11 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
|
202
211
|
disabled && 'text-fg-disabled cursor-not-allowed',
|
|
203
212
|
className,
|
|
204
213
|
)}
|
|
214
|
+
// 2026-07-04 robustness:先 spread 其餘 props、後放 guarded handlers — 消除
|
|
215
|
+
// 「handler 置前 + 後方 runtime filter 同名 key」對屬性順序的隱性依賴,行為不變
|
|
216
|
+
{...Object.fromEntries(Object.entries(props).filter(([k]) => k !== 'onClick' && k !== 'onKeyDown'))}
|
|
205
217
|
onClick={disabled ? undefined : props.onClick}
|
|
206
218
|
onKeyDown={disabled ? undefined : props.onKeyDown}
|
|
207
|
-
{...Object.fromEntries(Object.entries(props).filter(([k]) => k !== 'onClick' && k !== 'onKeyDown'))}
|
|
208
219
|
>
|
|
209
220
|
{/* Prefix 對齊容器 */}
|
|
210
221
|
{hasPrefix && (
|
|
@@ -96,6 +96,7 @@ export const Overview: Story = {
|
|
|
96
96
|
升級方案
|
|
97
97
|
</Button>
|
|
98
98
|
}
|
|
99
|
+
onDismiss={() => {}} // anatomy 4-slot 展示含 dismiss X(2026-07-05 D4:X 僅在傳 onDismiss 時渲染)
|
|
99
100
|
/>
|
|
100
101
|
</SubtleShell>
|
|
101
102
|
</div>
|
|
@@ -189,13 +190,13 @@ export const Overview: Story = {
|
|
|
189
190
|
<Td mono>dismissible</Td>
|
|
190
191
|
<Td mono>boolean</Td>
|
|
191
192
|
<Td mono>true</Td>
|
|
192
|
-
<Td
|
|
193
|
+
<Td>搭配 onDismiss 顯示關閉按鈕(兩者同時成立才渲染 X)</Td>
|
|
193
194
|
</tr>
|
|
194
195
|
<tr>
|
|
195
196
|
<Td mono>onDismiss</Td>
|
|
196
197
|
<Td mono>() => void</Td>
|
|
197
198
|
<Td mono>undefined</Td>
|
|
198
|
-
<Td>關閉按鈕 callback</Td>
|
|
199
|
+
<Td>關閉按鈕 callback;未傳則不渲染 X(2026-07-05 D4)</Td>
|
|
199
200
|
</tr>
|
|
200
201
|
<tr>
|
|
201
202
|
<Td mono>iconClassName</Td>
|
|
@@ -248,6 +249,7 @@ function NoticeInspector() {
|
|
|
248
249
|
) : undefined
|
|
249
250
|
}
|
|
250
251
|
dismissible={dismissible}
|
|
252
|
+
onDismiss={() => {}} // 2026-07-05 D4:X 僅在傳 onDismiss 時渲染,Inspector 切 dismissible 才看得到 X
|
|
251
253
|
/>
|
|
252
254
|
</SubtleShell>
|
|
253
255
|
</div>
|
|
@@ -481,19 +483,22 @@ export const StateBehavior: Story = {
|
|
|
481
483
|
<div>
|
|
482
484
|
<H3>Dismissible 行為</H3>
|
|
483
485
|
<Desc>
|
|
484
|
-
Alert 預設可 dismiss(持久通知,使用者需主動關);Toast 通常不 dismiss(計時器自動關)。兩者共用 Notice
|
|
486
|
+
Alert 預設可 dismiss(持久通知,使用者需主動關);Toast 通常不 dismiss(計時器自動關)。兩者共用 Notice,透過
|
|
485
487
|
<code className="font-mono text-footnote mx-1">dismissible</code>
|
|
486
|
-
|
|
488
|
+
+
|
|
489
|
+
<code className="font-mono text-footnote mx-1">onDismiss</code>
|
|
490
|
+
控制(X 僅在兩者同時成立時渲染——未接 handler 的 X 是死按鈕,2026-07-05 D4)。
|
|
487
491
|
</Desc>
|
|
488
492
|
<div className="grid grid-cols-2 gap-3 max-w-3xl">
|
|
489
493
|
<div>
|
|
490
|
-
<p className="text-caption text-fg-muted mb-2">dismissible
|
|
494
|
+
<p className="text-caption text-fg-muted mb-2">dismissible + onDismiss</p>
|
|
491
495
|
<SubtleShell variant="info">
|
|
492
496
|
<Notice
|
|
493
497
|
variant="info"
|
|
494
498
|
iconClassName={SUBTLE_ICON_COLOR.info}
|
|
495
499
|
title="Audit log 僅限 Business 方案"
|
|
496
500
|
dismissible
|
|
501
|
+
onDismiss={() => {}}
|
|
497
502
|
/>
|
|
498
503
|
</SubtleShell>
|
|
499
504
|
</div>
|
|
@@ -57,7 +57,7 @@ item-layout 4-slot:
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
- Icon: 16px,`h-[1lh]` inline 對齊 first line
|
|
60
|
-
- Dismiss X: `<Button iconOnly dismiss size="xs" />` — chrome corner action group region(Cat 3)。xs 是 **Notification banner family canonical**(Notice / Alert / Toast inherit):ephemeral banner `px-4 py-3` 固定不隨 density,dismiss 邊角小 affordance 輕量不搶眼。詳見 `patterns/overlay-surface/overlay-surface.spec.md`「Chrome dismiss size canonical」(overlay header 走 sm native + 負 margin trick;只有 notification banner family 用 xs)+ `patterns/element-anatomy/
|
|
60
|
+
- Dismiss X: `<Button iconOnly dismiss size="xs" />` — chrome corner action group region(Cat 3)。xs 是 **Notification banner family canonical**(Notice / Alert / Toast inherit):ephemeral banner `px-4 py-3` 固定不隨 density,dismiss 邊角小 affordance 輕量不搶眼。詳見 `patterns/overlay-surface/overlay-surface.spec.md`「Chrome dismiss size canonical」(overlay header 走 sm native + 負 margin trick;只有 notification banner family 用 xs)+ `patterns/element-anatomy/inline-action.spec.md`「Dismiss canonical — X close only」
|
|
61
61
|
- endContent: 通常放 `<Button variant="tertiary" size="xs">`
|
|
62
62
|
|
|
63
63
|
## Variant
|
|
@@ -121,6 +121,7 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
|
|
|
121
121
|
- **Loading**:Notice 非 async surface,無 loading state。Body 內若 consumer 注入 CTA Button,該 Button 自行處理 loading。
|
|
122
122
|
- **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。
|
|
123
123
|
- **Icon-only / variant=neutral**:`neutral` variant 不渲 status icon,layout 自動收斂為 `[title + description?] [endContent?] [dismiss X?]` 三 slot。
|
|
124
|
+
- **`dismissible` 無 `onDismiss`**(2026-07-05 D4):X 渲染條件 = `dismissible`(預設 true)**且**有傳 `onDismiss`——Notice / Alert 為 controlled-only(不自我移除),無 handler 的 X 是可 focus、SR 播報「關閉通知」但按下零反應的死按鈕(假 affordance)。對齊 Polaris Banner(`onDismiss` 存在才顯示 X)/ Ant Alert(`closable` 預設 false)。顯式傳 `dismissible={true}` 卻缺 `onDismiss` 時 dev-only `console.warn` 提示(預設未傳不吵)。
|
|
124
125
|
|
|
125
126
|
---
|
|
126
127
|
|
|
@@ -138,12 +139,12 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
|
|
|
138
139
|
|
|
139
140
|
**Keyboard 行為**:
|
|
140
141
|
|
|
141
|
-
- Tab — focus dismiss button(若 dismissible)
|
|
142
|
+
- Tab — focus dismiss button(若 dismissible 且有傳 `onDismiss`——X 僅在兩者同時成立時渲染,見「邊界案例」,2026-07-05 D4;consumer 經 `endContent` 注入互動元素時,其 DOM 順序在 dismiss 之前,Tab 先落 endContent)
|
|
142
143
|
- Enter / Space — 觸發 focus 中的 dismiss button(原生 button 行為,呼叫 `onDismiss`)
|
|
143
144
|
|
|
144
145
|
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)決定。
|
|
145
146
|
|
|
146
|
-
**Focus
|
|
147
|
+
**Focus**:Notice 自身渲染的唯一 focusable 元素是 dismiss `<Button>`(consumer 經 `endContent` 注入的互動元素——如上方建議的 tertiary Button——由 consumer 自管 a11y),focus indicator 走 Button canonical(`focus-visible:ring-2 ring-ring`,box-shadow ring 非 CSS `outline`);Notice 本身無 focus management(dismiss 後焦點處置見上段,由 consumer 決定)。
|
|
147
148
|
|
|
148
149
|
**驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
|
|
149
150
|
|
|
@@ -6,7 +6,7 @@ import * as React from 'react'
|
|
|
6
6
|
import { X as XIcon, Info, CircleCheck, TriangleAlert, XCircle, type LucideIcon } from 'lucide-react'
|
|
7
7
|
import { cn } from '@/lib/utils'
|
|
8
8
|
import { Button } from '@/design-system/components/Button/button'
|
|
9
|
-
import { ItemContent, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
9
|
+
import { ICON_SIZE, ItemContent, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Notice — Toast / Alert 共用的視覺佈局層
|
|
@@ -75,6 +75,11 @@ export interface NoticeProps
|
|
|
75
75
|
title: React.ReactNode
|
|
76
76
|
description?: React.ReactNode
|
|
77
77
|
endContent?: React.ReactNode
|
|
78
|
+
/**
|
|
79
|
+
* 顯示關閉鈕(預設 true)。**需同時傳 `onDismiss` 才會渲染 X** — Notice 是 controlled-only
|
|
80
|
+
* (不自我移除),無 handler 的 X 是可 focus、SR 播報「關閉通知」但按下零反應的死按鈕
|
|
81
|
+
* (2026-07-05 D4;對齊 Polaris Banner `onDismiss` 存在才顯示 X / Ant Alert `closable` 預設 false)。
|
|
82
|
+
*/
|
|
78
83
|
dismissible?: boolean
|
|
79
84
|
onDismiss?: () => void
|
|
80
85
|
/** ARIA label for the dismiss button. Override for i18n. Default: "關閉通知" */
|
|
@@ -99,7 +104,9 @@ const Notice = React.forwardRef<HTMLDivElement, NoticeProps>(
|
|
|
99
104
|
title,
|
|
100
105
|
description,
|
|
101
106
|
endContent,
|
|
102
|
-
|
|
107
|
+
// 不 destructure-default(保留「顯式傳 true」的可辨識性給下方 dev-warn);等效預設 true 由
|
|
108
|
+
// showDismiss 的 `!== false` 承擔。
|
|
109
|
+
dismissible,
|
|
103
110
|
onDismiss,
|
|
104
111
|
dismissAriaLabel = '關閉通知', // i18n-allow: DS default; consumer override via dismissAriaLabel prop
|
|
105
112
|
iconClassName,
|
|
@@ -110,6 +117,16 @@ const Notice = React.forwardRef<HTMLDivElement, NoticeProps>(
|
|
|
110
117
|
) => {
|
|
111
118
|
const StatusIcon = VARIANT_ICON[variant]
|
|
112
119
|
|
|
120
|
+
// 2026-07-05 D4:X 渲染條件 = dismissible(預設 true)**且**有傳 onDismiss — 原 `dismissible &&`
|
|
121
|
+
// 單獨判斷讓預設用法 <Alert title="…"/> 渲染一顆死 X(controlled-only 不自我移除,onClick=undefined
|
|
122
|
+
// 零反應;keyboard / SR 使用者按 Enter 零回饋 = 假 affordance)。對齊 Polaris Banner(onDismiss
|
|
123
|
+
// 存在才顯示 X)/ Ant Alert(closable 預設 false)。
|
|
124
|
+
const showDismiss = dismissible !== false && onDismiss != null
|
|
125
|
+
if (process.env.NODE_ENV !== 'production' && dismissible === true && onDismiss == null) {
|
|
126
|
+
// 只在「顯式傳 dismissible={true} 卻沒接 onDismiss」的消費端矛盾時提示(預設 undefined 不吵)
|
|
127
|
+
console.warn('[Notice] dismissible=true 但未傳 onDismiss,關閉鈕不會渲染(需同時提供 onDismiss)。')
|
|
128
|
+
}
|
|
129
|
+
|
|
113
130
|
return (
|
|
114
131
|
<div
|
|
115
132
|
ref={ref}
|
|
@@ -118,7 +135,7 @@ const Notice = React.forwardRef<HTMLDivElement, NoticeProps>(
|
|
|
118
135
|
>
|
|
119
136
|
{StatusIcon && (
|
|
120
137
|
<ItemPrefix>
|
|
121
|
-
<StatusIcon size={
|
|
138
|
+
<StatusIcon size={ICON_SIZE.md} className={cn('shrink-0', iconClassName)} aria-hidden />
|
|
122
139
|
</ItemPrefix>
|
|
123
140
|
)}
|
|
124
141
|
|
|
@@ -130,7 +147,7 @@ const Notice = React.forwardRef<HTMLDivElement, NoticeProps>(
|
|
|
130
147
|
labelClassName={description ? 'font-medium' : undefined}
|
|
131
148
|
/>
|
|
132
149
|
|
|
133
|
-
{(endContent ||
|
|
150
|
+
{(endContent || showDismiss) && (
|
|
134
151
|
// 2026-06-15 user 拍板:消費 ItemSuffix primitive(原手刻 div + @row-slot-handcraft-allow
|
|
135
152
|
// 已移除)。item-anatomy.spec.md 把 Notice 的 action/dismiss 對應到 suffix slot;ItemSuffix
|
|
136
153
|
// base geometry(h-[1lh] shrink-0 ml-auto flex items-center gap-2)正是此處所需,hoverReveal
|
|
@@ -138,7 +155,7 @@ const Notice = React.forwardRef<HTMLDivElement, NoticeProps>(
|
|
|
138
155
|
// family canonical,overlay-surface.spec.md「Chrome dismiss size canonical」)。
|
|
139
156
|
<ItemSuffix>
|
|
140
157
|
{endContent}
|
|
141
|
-
{
|
|
158
|
+
{showDismiss && (
|
|
142
159
|
<Button
|
|
143
160
|
data-dismiss
|
|
144
161
|
iconOnly
|
|
@@ -178,7 +178,7 @@ export const Overview = {
|
|
|
178
178
|
<div className="flex flex-col gap-2 items-start">
|
|
179
179
|
<span className="text-[11px] text-fg-muted font-medium">edit</span>
|
|
180
180
|
<div className="inline-flex items-center border-2 border-dashed border-primary/30 rounded-md px-3 py-2.5 gap-2">
|
|
181
|
-
{[{ name: 'wrapper', color: 'info' }, { name: '
|
|
181
|
+
{[{ name: 'wrapper', color: 'info' }, { name: 'input', color: 'success' }, { name: 'endAction', color: 'warning' }].map((s) => (
|
|
182
182
|
<span key={s.name} className="rounded px-2 py-1 text-[11px] font-mono border border-dashed"
|
|
183
183
|
style={{ borderColor: `var(--${s.color})`, backgroundColor: `var(--${s.color}-subtle)`, color: `var(--${s.color})` }}>{s.name}</span>
|
|
184
184
|
))}
|
|
@@ -189,7 +189,7 @@ export const Overview = {
|
|
|
189
189
|
<div className="flex flex-col gap-2 items-start">
|
|
190
190
|
<span className="text-[11px] text-fg-muted font-medium">readonly / disabled</span>
|
|
191
191
|
<div className="inline-flex items-center border-2 border-dashed border-primary/30 rounded-md px-3 py-2.5 gap-2">
|
|
192
|
-
{[{ name: 'wrapper', color: 'info' }, { name: '
|
|
192
|
+
{[{ name: 'wrapper', color: 'info' }, { name: 'formatted span', color: 'success' }].map((s) => (
|
|
193
193
|
<span key={s.name} className="rounded px-2 py-1 text-[11px] font-mono border border-dashed"
|
|
194
194
|
style={{ borderColor: `var(--${s.color})`, backgroundColor: `var(--${s.color}-subtle)`, color: `var(--${s.color})` }}>{s.name}</span>
|
|
195
195
|
))}
|
|
@@ -255,6 +255,7 @@ export const Overview = {
|
|
|
255
255
|
['precision', 'number', '—', '小數位數'],
|
|
256
256
|
['locale', 'string', "'en-US'", '數字格式 locale'],
|
|
257
257
|
['endAction', 'InlineActionConfig', '—', '右側 inline action(宣告式 API)'],
|
|
258
|
+
['endSlot', 'ReactNode', '—', '右側自訂 slot(escape hatch,僅 edit 渲染);與 endAction 互斥,同時傳時 endSlot 優先'],
|
|
258
259
|
['disabled', 'boolean', 'false', '原生屬性;mode 未顯式指定時解析為 disabled(顯式 mode prop 永遠最優先,useResolvedFieldMode SSOT)'],
|
|
259
260
|
['readOnly', 'boolean', 'false', '原生屬性;mode 未顯式指定且無 Field context mode 時解析為 readonly(優先序 mode > 有效 disabled > fieldCtx.mode > readOnly)'],
|
|
260
261
|
].map(([p, t, d, desc]) => (
|
|
@@ -744,7 +745,7 @@ export const StateBehavior = {
|
|
|
744
745
|
<div key={m} className="flex flex-col gap-1 items-start">
|
|
745
746
|
<span className="text-[11px] text-fg-muted font-mono">{m}</span>
|
|
746
747
|
<div className="w-[160px]"><NumberInput mode={m} value={null} prefix="$" /></div>
|
|
747
|
-
<span className="text-[10px] text-fg-muted">{m === 'edit' ? '空白 input' : 'em dash — + fg-muted'}</span>
|
|
748
|
+
<span className="text-[10px] text-fg-muted">{m === 'edit' ? '空白 input' : m === 'disabled' ? 'em dash — + fg-disabled(M24 state > emphasis)' : 'em dash — + fg-muted'}</span>
|
|
748
749
|
</div>
|
|
749
750
|
))}
|
|
750
751
|
</div>
|
|
@@ -781,7 +782,7 @@ export const Accessibility = {
|
|
|
781
782
|
render: () => (
|
|
782
783
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
783
784
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
784
|
-
<p className="whitespace-pre-line">{"ARIA :使用原生 <input type=\"text\" inputMode=\"decimal\"> ;外層 Field 自動補上標籤、錯誤狀態與描述的關聯。 inputMode=\"decimal\" 讓行動裝置彈出數字鍵盤。\n\n 鍵盤行為 :\n\n- Tab — 移入欄位\n- 數字鍵 — 輸入數值\n\n 焦點 :原生 input
|
|
785
|
+
<p className="whitespace-pre-line">{"ARIA :使用原生 <input type=\"text\" inputMode=\"decimal\"> ;外層 Field 自動補上標籤、錯誤狀態與描述的關聯。 inputMode=\"decimal\" 讓行動裝置彈出數字鍵盤。\n\n 鍵盤行為 :\n\n- Tab — 移入欄位\n- 數字鍵 — 輸入數值\n\n 焦點 :原生 input 以 outline-none 移除預設焦點外框;聚焦時由元件自身 wrapper 的 focus-within 將邊框轉為主色(border-primary)。\n\n 驗證 :Storybook 無障礙檢查面板應為 0 項嚴重問題;不靠滑鼠也能完整操作。文字對比度至少 4.5:1、介面元件至少 3:1(WCAG AA)。"}</p>
|
|
785
786
|
</div>
|
|
786
787
|
),
|
|
787
788
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @principles-rationale: UsageGuidance merges WhenToUse + WhenNotToUse into single 使用指引 story per refactor task (2026-04-26)
|
|
2
|
+
// @story-baseline: packages/design-system/src/components/DataTable/data-table.stories.tsx#NumberAlignment
|
|
2
3
|
import React from 'react'
|
|
3
4
|
import LinkTo from '@storybook/addon-links/react'
|
|
4
5
|
import type { Meta, StoryObj } from '@storybook/react'
|
|
@@ -35,7 +36,7 @@ const Label = ({ children, warn }: { children: React.ReactNode; warn?: boolean }
|
|
|
35
36
|
|
|
36
37
|
const Section = ({ title, children }: { title: string; children: React.ReactNode }) => (
|
|
37
38
|
<section className="mb-12">
|
|
38
|
-
<h2 className="text-
|
|
39
|
+
<h2 className="text-h3 font-bold text-foreground mb-4 pb-2 border-b border-border">{title}</h2>
|
|
39
40
|
{children}
|
|
40
41
|
</section>
|
|
41
42
|
)
|
|
@@ -106,7 +106,8 @@ col.accessor('price', {
|
|
|
106
106
|
- **Disabled**:由 Field SSOT own(`Field/field-controls.spec.md` State machine 段)。視覺:wrapper bg → `bg-disabled`(neutral-2,`semantic.css` `--bg-disabled`)、formatted text → `text-fg-disabled`(M24 state>emphasis)。Display mode + disabled 維持格式化輸出但 token 切 disabled。
|
|
107
107
|
- **Loading**:NumberInput 不提供 loading state(`NumberInputProps` 無 `loading` prop、無 `CircularProgress` / `aria-busy` 邏輯)。數值輸入為同步操作,無 async fetch 語意;若需 async 場景(如遠端校驗)請走外層 Field validation + `endSlot` 自訂 spinner。
|
|
108
108
|
- **Empty(null / undefined / 空字串)**:Display mode 渲 `—`(em dash + `text-fg-muted`);Edit mode placeholder 走 default placeholder color。
|
|
109
|
-
- **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + `
|
|
109
|
+
- **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + wrapper `border-error`(hover 時 `border-error-hover`)+ 下方 error message)。
|
|
110
|
+
- **輸入中間態**(`-`、`1.`、`0.0` 等 parse 後 lossy 的 raw 字串,2026-07-05 D4 codify):edit mode 以 internal draft string 承載——輸入期間 DOM 顯示 draft 原字串(負號、尾點不被 controlled 回寫吃掉),parse 成功即時同步 `onChange(parsed)`;blur / Enter commit(清 draft、顯示回 committed value,不合法殘字自然還原)、Escape 棄 draft(對齊 form-validation 規則 4)。value 面語意不變:`''` / `'-'` 視為 `null`。對齊 Ant InputNumber / Adobe Spectrum NumberField internal draft canonical。 <!-- @benchmark-unverified -->
|
|
110
111
|
- **負數 / 超大數字**:`toLocaleString(locale)` 自動處理負號與千分位分組,無特殊 prop。
|
|
111
112
|
- **科學記號輸入**(`1e5`):`Number(raw)` parse 為 `100000`,非 NaN 即觸發 `onChange`(`number-input.tsx:136-138`)。
|
|
112
113
|
- **精度上限**:`precision` > 6 為禁止事項(浮點精度雜訊),極端精度走 `Input` + 自驗證。
|
|
@@ -89,6 +89,8 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
89
89
|
disabled: disabledProp,
|
|
90
90
|
readOnly,
|
|
91
91
|
id: idProp,
|
|
92
|
+
onBlur: onBlurProp,
|
|
93
|
+
onKeyDown: onKeyDownProp,
|
|
92
94
|
'aria-describedby': ariaDescribedByProp,
|
|
93
95
|
'aria-errormessage': ariaErrorMessageProp,
|
|
94
96
|
...props
|
|
@@ -104,6 +106,15 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
104
106
|
// 2026-06-08 SSOT:mode 經 useResolvedFieldMode 統一解析(prop > 有效 disabled > fieldCtx.mode > readOnly > 'edit')
|
|
105
107
|
const resolvedMode: FieldMode = useResolvedFieldMode({ mode: modeProp, disabled, readOnly })
|
|
106
108
|
|
|
109
|
+
// 2026-07-05 D4 draft state:controlled value 回寫會吃掉輸入中間態('-'、'1.'、'0.0' 等
|
|
110
|
+
// parse 後 lossy 的 raw 字串)— 例:已有值 5 全選打「-」→ onChange(null) 回寫把 DOM 重設
|
|
111
|
+
// 為空,負號被吃、無法打出 -5。修法對齊 Ant InputNumber / Adobe Spectrum NumberField 的
|
|
112
|
+
// internal draft string canonical:輸入期間 DOM 顯示以 local draft 優先,parse 成功即時同步
|
|
113
|
+
// onChange(parsed);blur / Enter commit 清 draft 回 value 顯示;Escape 一併棄 draft(對齊
|
|
114
|
+
// form-validation 規則 4 回復原值)。宣告於 non-edit early return 之前(Rules-of-Hooks,
|
|
115
|
+
// 同 LinkInput 2026-07-04 修法)。
|
|
116
|
+
const [draft, setDraft] = React.useState<string | null>(null)
|
|
117
|
+
|
|
107
118
|
// display / readonly / disabled 都顯示格式化值(span 取代 input)
|
|
108
119
|
if (resolvedMode !== 'edit') {
|
|
109
120
|
return (
|
|
@@ -125,10 +136,11 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
125
136
|
)
|
|
126
137
|
}
|
|
127
138
|
|
|
128
|
-
// edit
|
|
139
|
+
// edit 模式:raw 數值輸入(draft 承載中間態;value 面語意不變 — ''/'-' 視為空、NaN 忽略)
|
|
129
140
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
130
|
-
if (!onChange) return
|
|
131
141
|
const raw = e.target.value
|
|
142
|
+
setDraft(raw)
|
|
143
|
+
if (!onChange) return
|
|
132
144
|
if (raw === '' || raw === '-') {
|
|
133
145
|
onChange(null)
|
|
134
146
|
return
|
|
@@ -142,11 +154,7 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
142
154
|
return (
|
|
143
155
|
<div
|
|
144
156
|
className={cn(
|
|
145
|
-
fieldWrapperStyles({ mode: 'edit', variant: variant, size }),
|
|
146
|
-
error && [
|
|
147
|
-
'border-error hover:border-error-hover',
|
|
148
|
-
'focus-within:border-error focus-within:hover:border-error',
|
|
149
|
-
],
|
|
157
|
+
fieldWrapperStyles({ mode: 'edit', variant: variant, size, error }),
|
|
150
158
|
className,
|
|
151
159
|
)}
|
|
152
160
|
data-field-mode="edit"
|
|
@@ -157,8 +165,15 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
|
|
|
157
165
|
type="text"
|
|
158
166
|
inputMode="decimal"
|
|
159
167
|
id={idProp ?? fieldCtx?.id}
|
|
160
|
-
value
|
|
168
|
+
// 輸入期間 draft(raw 字串)優先;非輸入期間才從 value prop 同步顯示(2026-07-05 D4)
|
|
169
|
+
value={draft ?? (value != null ? String(value) : '')}
|
|
161
170
|
onChange={handleChange}
|
|
171
|
+
// blur / Enter = commit(清 draft,顯示回 committed value);Escape 棄 draft
|
|
172
|
+
onBlur={(e) => { setDraft(null); onBlurProp?.(e) }}
|
|
173
|
+
onKeyDown={(e) => {
|
|
174
|
+
if (e.key === 'Enter' || e.key === 'Escape') setDraft(null)
|
|
175
|
+
onKeyDownProp?.(e)
|
|
176
|
+
}}
|
|
162
177
|
aria-invalid={error || undefined}
|
|
163
178
|
aria-required={fieldCtx?.required || undefined}
|
|
164
179
|
aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}
|
|
@@ -190,7 +205,8 @@ export const numberInputMeta = {
|
|
|
190
205
|
sizes: {
|
|
191
206
|
|
|
192
207
|
},
|
|
193
|
-
|
|
208
|
+
// 'active' 移除 — Field chrome 無按壓態;stepper 按壓屬內嵌 ItemInlineActionButton(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。
|
|
209
|
+
states: ['default', 'hover', 'focus-visible', 'disabled'],
|
|
194
210
|
tokens: {
|
|
195
211
|
bg: [],
|
|
196
212
|
fg: ['text-fg-disabled', 'text-fg-muted'],
|
|
@@ -46,8 +46,8 @@ type ShapeKey = 'circle' | 'tag'
|
|
|
46
46
|
const SIZES: SizeKey[] = ['sm', 'md', 'lg']
|
|
47
47
|
const SHAPES: ShapeKey[] = ['circle', 'tag']
|
|
48
48
|
|
|
49
|
-
// font-size 依 shape 分流(re-verified 2026-
|
|
50
|
-
// map(overflow-indicator.tsx:
|
|
49
|
+
// font-size 依 shape 分流(re-verified 2026-07-04):circle shape 走元件內建 triggerText
|
|
50
|
+
// map(overflow-indicator.tsx:28-32),tag shape 走 tagVariants({ size })(tag.tsx:40-44)。
|
|
51
51
|
// circleText / tagText 兩欄分別對應,避免把 circle-only 字級當成兩 shape 通用。
|
|
52
52
|
const SIZE_SPECS: Record<
|
|
53
53
|
SizeKey,
|
|
@@ -467,7 +467,7 @@ export const SizeMatrix: Story = {
|
|
|
467
467
|
<code className="font-mono">tag</code> 走 <code className="font-mono">tagVariants</code>(對齊 Tag 字級)。
|
|
468
468
|
circle shape 的 <code className="font-mono">sm</code> 用
|
|
469
469
|
<code className="font-mono mx-1">text-[10px]</code>
|
|
470
|
-
的理由見 spec
|
|
470
|
+
的理由見 spec「尺寸」段——與 Badge 共享 micro-indicator typography tier 的特殊例外(10px)。
|
|
471
471
|
</p>
|
|
472
472
|
</div>
|
|
473
473
|
|
|
@@ -63,7 +63,7 @@ sm / md 跟 Tag 同階(20/24px),lg 對齊 md(尺寸需求一致,不需
|
|
|
63
63
|
|
|
64
64
|
**字級依 shape 分流**:`circle` shape 走元件內建的 `triggerText` map(sm 10px / md·lg 12px);`tag` shape 直接套 `tagVariants({ size })`(sm 12px / md·lg 14px,見 `tag.spec.md`),刻意對齊 Tag 視覺一致(見上方「trigger 不用 Tag 元件」段)。下方「sm 用 `text-[10px]`」的理由僅適用於 circle shape。
|
|
65
65
|
|
|
66
|
-
**sm 用 `text-[10px]` 的理由**:
|
|
66
|
+
**sm 用 `text-[10px]` 的理由**:micro-indicator 特殊例外(10px,與 `--font-footnote` 同值但不消費其 utility——lh 1.3 vs 需要的緊湊行高),與 Badge 共享「micro-indicator typography」tier——trigger 數字是次要輔助 indicator(非主訊息),在 20px 小容器內 caption 12px 會擠。完整理由與 pattern-family 說明詳見 `badge.spec.md`「字體例外:`text-[10px]`」。若未來 OverflowIndicator / Badge 以外的元件也需要這個 10px micro-indicator 尺寸,先依 `badge.spec.md`「其他元件不得比照」歸同一 family 討論,確立第三個消費者才升 typography token,而非直接抄 arbitrary value。
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -158,7 +158,8 @@ export const overflowIndicatorMeta = {
|
|
|
158
158
|
sizes: {
|
|
159
159
|
|
|
160
160
|
},
|
|
161
|
-
|
|
161
|
+
// 2026-07-04 audit 對齊(spec:95「本身無 hover / active / disabled / selected 變化」;code 有 focus-visible ring tsx:106/121)
|
|
162
|
+
states: ['default', 'focus-visible'],
|
|
162
163
|
tokens: {
|
|
163
164
|
bg: ['bg-muted'],
|
|
164
165
|
fg: ['text-foreground'],
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/gen-component-indexes.mjs — DO NOT EDIT MANUALLY.
|
|
2
|
+
// Re-export pattern enables package.json exports map subpath:
|
|
3
|
+
// import { ... } from '@qijenchen/design-system/{components,patterns}/<Dir>'
|
|
4
|
+
// Regenerate: node scripts/gen-component-indexes.mjs
|
|
5
|
+
export * from './pagination'
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// @anatomy-exempt: anatomy specs / token 對照表格用 raw <table>,非業務資料表。業務資料表才用 <DataTable>。
|
|
2
|
+
// SizeMatrix N/A — 無 size 軸(按鈕固定 size="sm",chrome 級導覽不隨密度縮放;詳 pagination.spec.md「SizeMatrix N/A rationale」)
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
5
|
+
import { Pagination } from './pagination'
|
|
6
|
+
import { H3, Desc, Td, Th, TokenCell } from '@/design-system/stories-helpers/anatomy/anatomy-utils'
|
|
7
|
+
|
|
8
|
+
type InspectorArgs = {
|
|
9
|
+
page: number
|
|
10
|
+
total: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const meta: Meta = {
|
|
14
|
+
title: 'Design System/Components/Pagination/設計規格',
|
|
15
|
+
parameters: { layout: 'padded' },
|
|
16
|
+
}
|
|
17
|
+
export default meta
|
|
18
|
+
type Story = StoryObj
|
|
19
|
+
type InspectorStory = StoryObj<InspectorArgs>
|
|
20
|
+
|
|
21
|
+
export const Overview: Story = {
|
|
22
|
+
name: '元件總覽',
|
|
23
|
+
render: () => {
|
|
24
|
+
const [page, setPage] = React.useState(5)
|
|
25
|
+
return (
|
|
26
|
+
<div className="flex flex-col gap-10">
|
|
27
|
+
<div>
|
|
28
|
+
<H3>Anatomy</H3>
|
|
29
|
+
<Desc>
|
|
30
|
+
{'nav[aria-label="Pagination"] > ul > li(shadcn 骨架);上下頁 = Button text sm iconOnly,'}
|
|
31
|
+
{'未選數字 = Button text sm、當前頁 = Button secondary(等寬 min-w = field-height-sm,方形節奏對齊 Ant);'}
|
|
32
|
+
{'當前頁 aria-current="page" + 選中 canonical(主色描邊+染字、不染底,semantic.css SSOT);'}
|
|
33
|
+
{'… = MoreHorizontal 純指示(aria-hidden,不可點)。格位恆 ≤ 7(boundary/sibling = 1/1)。'}
|
|
34
|
+
</Desc>
|
|
35
|
+
<Pagination total={240} page={page} onPageChange={setPage} />
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const Inspector: InspectorStory = {
|
|
43
|
+
name: '互動檢視',
|
|
44
|
+
args: { page: 5, total: 240 },
|
|
45
|
+
argTypes: {
|
|
46
|
+
page: { control: { type: 'number', min: 1, max: 500 } },
|
|
47
|
+
total: { control: { type: 'number', min: 0, max: 10000 } },
|
|
48
|
+
},
|
|
49
|
+
render: (args) => (
|
|
50
|
+
<div className="flex flex-col gap-3">
|
|
51
|
+
<Desc>調 page / total 觀察摺疊行為(總頁數 = ceil(total / 20)):≤ 7 頁不摺疊;超過後依當前頁位置單側或雙側摺疊。</Desc>
|
|
52
|
+
<Pagination total={args.total} page={args.page} onPageChange={() => {}} />
|
|
53
|
+
</div>
|
|
54
|
+
),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const ColorMatrix: Story = {
|
|
58
|
+
name: '色彩對照',
|
|
59
|
+
render: () => (
|
|
60
|
+
<div className="flex flex-col gap-6">
|
|
61
|
+
<Desc>
|
|
62
|
+
數字鈕四態的 token 對照。default / hover / disabled 全數繼承 Button text variant;
|
|
63
|
+
selected(當前頁)消費 DS「持續選中」canonical —— 主色 base 同時染邊框與文字、底色維持
|
|
64
|
+
surface 不染(semantic.css「選中狀態」段 SSOT;與 Chip / SegmentedControl 選中同族)。
|
|
65
|
+
</Desc>
|
|
66
|
+
<table className="text-body">
|
|
67
|
+
<thead>
|
|
68
|
+
<tr><Th>State</Th><Th>text</Th><Th>border</Th><Th>bg</Th></tr>
|
|
69
|
+
</thead>
|
|
70
|
+
<tbody>
|
|
71
|
+
<tr>
|
|
72
|
+
<Td>default</Td>
|
|
73
|
+
<Td><TokenCell token="--fg" display="text-foreground" /></Td>
|
|
74
|
+
<Td mono>transparent(佔位防選中位移)</Td>
|
|
75
|
+
<Td mono>transparent</Td>
|
|
76
|
+
</tr>
|
|
77
|
+
<tr>
|
|
78
|
+
<Td>hover</Td>
|
|
79
|
+
<Td><TokenCell token="--fg" display="text-foreground" /></Td>
|
|
80
|
+
<Td mono>transparent</Td>
|
|
81
|
+
<Td><TokenCell token="--neutral-hover" display="bg-neutral-hover" /></Td>
|
|
82
|
+
</tr>
|
|
83
|
+
<tr>
|
|
84
|
+
<Td>selected(當前頁 = Button secondary)</Td>
|
|
85
|
+
<Td><TokenCell token="--primary" display="text-primary" /></Td>
|
|
86
|
+
<Td><TokenCell token="--primary" display="border-primary" /></Td>
|
|
87
|
+
<Td><TokenCell token="--surface" display="bg-surface(不染底,同 Chip selected)" /></Td>
|
|
88
|
+
</tr>
|
|
89
|
+
<tr>
|
|
90
|
+
<Td>disabled(上下頁邊界)</Td>
|
|
91
|
+
<Td><TokenCell token="--fg-disabled" display="text-fg-disabled" /></Td>
|
|
92
|
+
<Td mono>transparent</Td>
|
|
93
|
+
<Td mono>transparent</Td>
|
|
94
|
+
</tr>
|
|
95
|
+
</tbody>
|
|
96
|
+
</table>
|
|
97
|
+
<div className="flex flex-col gap-2">
|
|
98
|
+
<p className="text-caption text-fg-muted">實例對照(第 1 頁:上一頁 disabled + 當前頁選中):</p>
|
|
99
|
+
<Pagination total={100} page={1} onPageChange={() => {}} />
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
),
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const StateBehavior: Story = {
|
|
106
|
+
name: '狀態行為',
|
|
107
|
+
render: () => {
|
|
108
|
+
const [page, setPage] = React.useState(2)
|
|
109
|
+
return (
|
|
110
|
+
<div className="flex flex-col gap-6">
|
|
111
|
+
<Desc>
|
|
112
|
+
hover / active / focus-visible 全數繼承 Button:未選數字與上下頁 = text variant(hover 淡灰底、
|
|
113
|
+
active 深一階);當前頁 = secondary variant(hover 升 primary-hover 階、按壓 primary-active,
|
|
114
|
+
無灰底 —— 選中之上的互動 = 同色相升降階)。當前頁是位置指示非 toggle —— 點擊當前頁
|
|
115
|
+
fire onPageChange(同頁),不會「取消選中」。第一頁 / 最後一頁時對應箭頭 disabled
|
|
116
|
+
(focus 掉落行為對齊 Ant / MUI,不做 focus 轉移)。
|
|
117
|
+
</Desc>
|
|
118
|
+
<Pagination total={100} page={page} onPageChange={setPage} />
|
|
119
|
+
<p className="text-caption text-fg-muted">目前在第 {page} 頁 —— 點數字 / 箭頭觀察 controlled 行為。</p>
|
|
120
|
+
</div>
|
|
121
|
+
)
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const Accessibility: Story = {
|
|
126
|
+
name: '無障礙',
|
|
127
|
+
render: () => (
|
|
128
|
+
<div className="flex flex-col gap-4 max-w-[720px]">
|
|
129
|
+
<H3>A11y 預設</H3>
|
|
130
|
+
<p className="text-body leading-relaxed whitespace-pre-line">
|
|
131
|
+
{'ARIA:WAI-ARIA 無專門 pagination pattern,公認做法(shadcn / MUI / Atlassian 一致)=\n' +
|
|
132
|
+
'- root <nav aria-label="Pagination">(landmark;英文 pattern 名,follow Breadcrumb 慣例)\n' +
|
|
133
|
+
'- 當前頁 aria-current="page"(不用 aria-pressed —— pressed 是可取消 toggle,當前頁不可取消)\n' +
|
|
134
|
+
'- ellipsis aria-hidden(純視覺指示)\n' +
|
|
135
|
+
'- 上下頁 iconOnly 帶 aria-label(預設「上一頁」/「下一頁」,props 可覆寫)\n\n' +
|
|
136
|
+
'鍵盤:Tab 逐鈕(原生 button 序)、Enter / Space 觸發 —— 全繼承 Button 原生語意,' +
|
|
137
|
+
'不做 roving tabindex(nav landmark 內獨立按鈕群,非 composite widget)。\n\n' +
|
|
138
|
+
'驗證:Storybook a11y 面板 0 critical violation;純鍵盤可完成翻頁與跳頁。'}
|
|
139
|
+
</p>
|
|
140
|
+
<Pagination total={180} page={3} onPageChange={() => {}} />
|
|
141
|
+
</div>
|
|
142
|
+
),
|
|
143
|
+
}
|