@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
|
@@ -193,6 +193,8 @@ const buttonVariants = cva(
|
|
|
193
193
|
// aria-pressed fallback(Radix overlay trigger override data-state 時仍生效)
|
|
194
194
|
'aria-pressed:bg-primary-subtle aria-pressed:text-primary aria-pressed:border-transparent',
|
|
195
195
|
'aria-pressed:hover:text-primary-hover',
|
|
196
|
+
// 2026-07-07 補齊第三階:fallback 分支與 data-[state=on] 分支同拼寫(選中之上按壓 = active 階)
|
|
197
|
+
'aria-pressed:active:text-primary-active',
|
|
196
198
|
],
|
|
197
199
|
},
|
|
198
200
|
// neutral tone:灰底(neutral-selected family)— sidebar/contextual nav pressed
|
|
@@ -212,7 +214,7 @@ const buttonVariants = cva(
|
|
|
212
214
|
],
|
|
213
215
|
defaultVariants: {
|
|
214
216
|
// labeled 預設 = tertiary(2026-06-06 從 primary 改;iconOnly 預設 = text,由 resolvedVariant 注入)。
|
|
215
|
-
//
|
|
217
|
+
// 真正預設邏輯在元件內 resolvedVariant(相對指法,免行號漂移);此 cva default 供直接 buttonVariants() 呼叫者一致。
|
|
216
218
|
variant: 'tertiary',
|
|
217
219
|
size: 'md',
|
|
218
220
|
pressedTone: 'emphasis',
|
|
@@ -303,7 +305,7 @@ export interface ButtonProps
|
|
|
303
305
|
* - Clear → 欄位清空,用 Inline Action
|
|
304
306
|
* - Remove → collection 移除,用一般 Button / Inline Action
|
|
305
307
|
*
|
|
306
|
-
* 詳見 button.spec.md「Dismiss 視覺類」段 + patterns/element-anatomy/
|
|
308
|
+
* 詳見 button.spec.md「Dismiss 視覺類」段 + patterns/element-anatomy/inline-action.spec.md
|
|
307
309
|
* 「Dismiss canonical — X close only」段。
|
|
308
310
|
*/
|
|
309
311
|
dismiss?: boolean
|
|
@@ -370,7 +372,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
370
372
|
|
|
371
373
|
// 2026-05-23 deep-audit Phase A.4 Decision 1(user verbatim「決策ㄧ照你建議做」):dev-warn `iconOnly + (endIcon|badge)` 並用。
|
|
372
374
|
// Spec SSOT:button.spec.md「iconOnly 嚴格定義為『只有一個 icon,正方形』,不可與 endIcon 或 badge 並用」。
|
|
373
|
-
// 例外:overlayBadge 跟 iconOnly 並用 canonical(
|
|
375
|
+
// 例外:overlayBadge 跟 iconOnly 並用 canonical(上方 overlayBadge 反向 warn 已 cover;相對指法,免行號漂移)。
|
|
374
376
|
// 不擋 image canonical「icon + 下拉指示 = 不加 iconOnly + startIcon + endIcon + aria-label」(那 case iconOnly=false 不 trigger)。
|
|
375
377
|
if (process.env.NODE_ENV !== 'production' && iconOnly && (EndIcon !== undefined || badge != null)) {
|
|
376
378
|
// eslint-disable-next-line no-console
|
|
@@ -426,27 +428,13 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
426
428
|
const unboundedAttr =
|
|
427
429
|
resolvedVariant === 'text' || dismiss ? { 'data-unbounded': 'true' } : {}
|
|
428
430
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// Dismiss 視覺弱化:override Button text variant 預設 foreground 為 fg-muted → hover foreground
|
|
437
|
-
// 跟 Inline Action dismiss 視覺一致(cross-implementation dimming canonical)
|
|
438
|
-
dismiss && 'text-fg-muted hover:text-foreground',
|
|
439
|
-
resolvedFullWidth && 'w-full',
|
|
440
|
-
)}
|
|
441
|
-
ref={ref}
|
|
442
|
-
type="button"
|
|
443
|
-
disabled={disabled || loading}
|
|
444
|
-
aria-busy={loading || undefined}
|
|
445
|
-
aria-label={ariaLabel}
|
|
446
|
-
{...toggleAttrs}
|
|
447
|
-
{...unboundedAttr}
|
|
448
|
-
{...restProps}
|
|
449
|
-
>
|
|
431
|
+
// Native path 內部結構:[loading spinner | startIcon(+overlayBadge)] [label] [badge + endIcon]。
|
|
432
|
+
// asChild 時**不渲染**(2026-07-04 fix):Radix Slot 規範 children 必為單一 element
|
|
433
|
+
// (React.Children.only)— 內部多 expression children 變 array 必 runtime throw;
|
|
434
|
+
// asChild 分支只 render consumer child,內容由 consumer 自帶。
|
|
435
|
+
// 詳 CLAUDE.md 失敗記憶索引「asChild ? Slot : Native 內部 JSX 仍渲染多 children」條。
|
|
436
|
+
const nativeChildren = (
|
|
437
|
+
<>
|
|
450
438
|
{loading ? (
|
|
451
439
|
<CircularProgress size={iconSize} className="text-current" />
|
|
452
440
|
) : StartIcon ? (
|
|
@@ -478,6 +466,55 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
478
466
|
{EndIcon && <EndIcon size={iconSize} aria-hidden />}
|
|
479
467
|
</span>
|
|
480
468
|
)}
|
|
469
|
+
</>
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
const sharedClassName = cn(
|
|
473
|
+
buttonVariants({ variant: resolvedVariant, danger: resolvedDanger, size: resolvedSize, pressedTone, className }),
|
|
474
|
+
// iconOnly 鐵律:padding-free + aspect-square + flex-center (Polaris idiom)
|
|
475
|
+
// 0 magic-number 0 公式自動正方形。詳 ICON_ONLY_BASE rationale。
|
|
476
|
+
resolvedIconOnly && ICON_ONLY_BASE,
|
|
477
|
+
// Dismiss 視覺弱化:override Button text variant 預設 foreground 為 fg-muted → hover foreground
|
|
478
|
+
// 跟 Inline Action dismiss 視覺一致(cross-implementation dimming canonical)
|
|
479
|
+
dismiss && 'text-fg-muted hover:text-foreground',
|
|
480
|
+
resolvedFullWidth && 'w-full',
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
// 2026-07-05 D4 修:asChild 原 silently drop loading/disabled 語意(無 aria-busy/aria-disabled/
|
|
484
|
+
// click guard → <a> loading 期間可重複點擊)。補 ARIA(任何 element 合法;aria-disabled 自動點亮
|
|
485
|
+
// cva 既有視覺)+ functional guard(APG aria-disabled 模式:語意+視覺由元件、功能阻斷由 guard)。
|
|
486
|
+
const { onClick: slotConsumerOnClick, ...slotRest } = restProps as typeof restProps & { onClick?: React.MouseEventHandler<HTMLElement> }
|
|
487
|
+
const buttonEl = asChild ? (
|
|
488
|
+
// Slot 分支:children 必為單一 consumer element(React.Children.only),
|
|
489
|
+
// 內部 slot(loading/startIcon/badge)不渲染;不硬塞 type/disabled(consumer child 可能是 <a>)。
|
|
490
|
+
<Comp
|
|
491
|
+
className={sharedClassName}
|
|
492
|
+
ref={ref}
|
|
493
|
+
aria-label={ariaLabel}
|
|
494
|
+
aria-busy={loading || undefined}
|
|
495
|
+
aria-disabled={disabled || loading || undefined}
|
|
496
|
+
onClick={disabled || loading
|
|
497
|
+
? (e: React.MouseEvent<HTMLElement>) => { e.preventDefault(); e.stopPropagation() }
|
|
498
|
+
: slotConsumerOnClick}
|
|
499
|
+
{...toggleAttrs}
|
|
500
|
+
{...unboundedAttr}
|
|
501
|
+
{...slotRest}
|
|
502
|
+
>
|
|
503
|
+
{children}
|
|
504
|
+
</Comp>
|
|
505
|
+
) : (
|
|
506
|
+
<Comp
|
|
507
|
+
className={sharedClassName}
|
|
508
|
+
ref={ref}
|
|
509
|
+
type="button"
|
|
510
|
+
disabled={disabled || loading}
|
|
511
|
+
aria-busy={loading || undefined}
|
|
512
|
+
aria-label={ariaLabel}
|
|
513
|
+
{...toggleAttrs}
|
|
514
|
+
{...unboundedAttr}
|
|
515
|
+
{...restProps}
|
|
516
|
+
>
|
|
517
|
+
{nativeChildren}
|
|
481
518
|
</Comp>
|
|
482
519
|
)
|
|
483
520
|
|
|
@@ -523,10 +560,13 @@ export const buttonMeta = {
|
|
|
523
560
|
md: { fieldHeight: 32, iconSize: 16, typography: 'body' },
|
|
524
561
|
lg: { fieldHeight: 36, iconSize: 20, typography: 'body-lg' },
|
|
525
562
|
},
|
|
526
|
-
|
|
563
|
+
// 'pressed' = toggle on 持續態(data-[state=on],emphasis 淡藍底/neutral 灰底;2026-07-07 meta 詞彙統一補列)
|
|
564
|
+
states: ['default', 'hover', 'active', 'pressed', 'focus-visible', 'disabled'],
|
|
527
565
|
tokens: {
|
|
528
|
-
|
|
529
|
-
|
|
566
|
+
// 2026-07-04 audit 補齊:原只列 primary variant 家族;按 buttonVariants cva 真實 class 補
|
|
567
|
+
// secondary/tertiary/text/link/danger 消費的 token(auto-compile token 矩陣依此)
|
|
568
|
+
bg: ['--primary', '--primary-hover', '--primary-active', '--primary-subtle', '--bg-disabled', '--surface', '--neutral-hover', '--neutral-active', '--neutral-selected'],
|
|
569
|
+
fg: ['--on-emphasis', '--fg-disabled', '--foreground', '--primary', '--error', '--error-hover', '--error-active'],
|
|
530
570
|
ring: ['--ring'],
|
|
531
571
|
},
|
|
532
572
|
defaultVariant: 'tertiary', // 2026-06-10 修 stale:對齊 cva defaultVariants(2026-06-06 labeled 預設改 tertiary,meta 漏同步)
|
|
@@ -18,7 +18,9 @@ export default meta
|
|
|
18
18
|
|
|
19
19
|
type Story = StoryObj<typeof Calendar>
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// 釘固定日期(2026-07-07 修 VR flake):真實 new Date() 讓 today 標記隨換日移格 → ubuntu
|
|
22
|
+
// baseline 每隔幾天假 breach(0.07–0.5%)。釘死 = deterministic 渲染;月中讓事件分布自然。
|
|
23
|
+
const now = new Date(2026, 6, 15)
|
|
22
24
|
const thisMonth = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
|
|
23
25
|
|
|
24
26
|
const sampleEvents: CalendarEvent[] = [
|
|
@@ -95,7 +97,7 @@ export const ColorMatrix: Story = {
|
|
|
95
97
|
|
|
96
98
|
<div>
|
|
97
99
|
<H3>Cell 視覺 token</H3>
|
|
98
|
-
<Desc>月 view cell 的狀態色彩。Cell
|
|
100
|
+
<Desc>月 view cell 的狀態色彩。Cell 最小高度 min-h-28 容納日期 header + 3 event tile,隨容器高度伸縮;7 欄等分。</Desc>
|
|
99
101
|
<div className="overflow-x-auto">
|
|
100
102
|
<table className="text-caption border-collapse">
|
|
101
103
|
<thead>
|
|
@@ -109,7 +111,7 @@ export const ColorMatrix: Story = {
|
|
|
109
111
|
<tr>
|
|
110
112
|
<Td>Cell 高度</Td>
|
|
111
113
|
<Td mono>min-h-28(112px)</Td>
|
|
112
|
-
<Td>容納 header + 3 event tile
|
|
114
|
+
<Td>容納 header + 3 event tile 的下限,隨容器高度伸縮(root h-full + grid flex-1)</Td>
|
|
113
115
|
</tr>
|
|
114
116
|
<tr>
|
|
115
117
|
<Td>Cell 寬度</Td>
|
|
@@ -14,7 +14,9 @@ const meta: Meta = {
|
|
|
14
14
|
export default meta
|
|
15
15
|
type Story = StoryObj
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
// 釘固定日期(2026-07-07 修 VR flake):真實 new Date() 讓 today 標記隨換日移格 → ubuntu
|
|
18
|
+
// baseline 每隔幾天假 breach(0.07–0.5%)。釘死 = deterministic 渲染;月中讓事件分布自然。
|
|
19
|
+
const now = new Date(2026, 6, 15)
|
|
18
20
|
const thisMonth = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
|
|
19
21
|
|
|
20
22
|
const Section = ({ title, children }: { title: string; children: React.ReactNode }) => (
|
|
@@ -92,6 +92,13 @@ Calendar 是**事件檢視 canvas**,讓 user 以**月 / 週 / 日** 三種 view
|
|
|
92
92
|
weekStartsOn={0 | 1} // 0=Sun, 1=Mon
|
|
93
93
|
renderEventTile={(event) => ReactNode} // 自訂 event tile 視覺
|
|
94
94
|
size="md" | "lg" // cell 大小(MVP 只 md;lg 為 tech debt)
|
|
95
|
+
locale="en-US" // Intl 語系(月份標題 / 星期名;預設 'en-US')
|
|
96
|
+
prevAriaLabel="上個月" // i18n override:prev 導覽鈕 aria-label
|
|
97
|
+
nextAriaLabel="下個月" // i18n override:next 導覽鈕 aria-label
|
|
98
|
+
navAriaLabel="行事曆月份導覽" // i18n override:月份導覽 <nav> landmark aria-label
|
|
99
|
+
viewToggleAriaLabel="檢視切換" // i18n override:檢視切換 SegmentedControl aria-label
|
|
100
|
+
todayLabel="今天" // i18n override:「今天」按鈕文字
|
|
101
|
+
createLabel="新事件" // i18n override:「新事件」CTA 文字(僅在傳 onCreateEvent 時渲染)
|
|
95
102
|
className
|
|
96
103
|
/>
|
|
97
104
|
```
|
|
@@ -134,7 +141,7 @@ interface CalendarEvent {
|
|
|
134
141
|
|
|
135
142
|
### Cell 規則
|
|
136
143
|
|
|
137
|
-
- **Cell 尺寸**:MVP 月 view cell
|
|
144
|
+
- **Cell 尺寸**:MVP 月 view cell 最小高度 `min-h-28`(112px),容納日期 header + 3 個 event tile,並隨容器高度伸縮(root `h-full` + grid `flex-1`);寬度 7 欄等分
|
|
138
145
|
- **日期 header**:右上角數字(對齊 Google Calendar 視覺慣例)
|
|
139
146
|
- **Today cell**:日期數字以 info-filled pill 強調(對齊 Google Calendar today pill)
|
|
140
147
|
- **Outside day cell**:上/下月溢出日期弱化字色 + 背景略暗區分
|
|
@@ -159,7 +166,7 @@ interface CalendarEvent {
|
|
|
159
166
|
- 左 Nav:`<Button iconOnly>` prev/next + `<Button>今天</Button>` 跳 today
|
|
160
167
|
- 中央 title:`<h2 className="text-h3">` or `text-body-lg font-medium`
|
|
161
168
|
- 右視圖切換:`<SegmentedControl>`(day/week/month)—— MVP 只啟用 month,其他 disabled
|
|
162
|
-
- 右上 CTA:`<Button variant="primary" startIcon={Plus}>新事件</Button>`
|
|
169
|
+
- 右上 CTA:`<Button variant="primary" startIcon={Plus}>新事件</Button>` — **條件渲染:僅在傳 `onCreateEvent` 回調時出現**(未傳 = 無 CTA,純瀏覽場景);文案由 `createLabel` prop override(對齊 `todayLabel` 等 chrome 文字 i18n override 慣例)
|
|
163
170
|
|
|
164
171
|
對齊 `patterns/action-bar/action-bar.spec.md`(左 context / 中 focus / 右 CTA 的經典分組)。
|
|
165
172
|
|
|
@@ -21,7 +21,9 @@ type Story = StoryObj<typeof Calendar>
|
|
|
21
21
|
|
|
22
22
|
// ── 真實業務情境 ─────────────────────────────────────────────────────
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// 釘固定日期(2026-07-07 修 VR flake):真實 new Date() 讓 today 標記隨換日移格 → ubuntu
|
|
25
|
+
// baseline 每隔幾天假 breach(0.07–0.5%)。釘死 = deterministic 渲染;月中讓事件分布自然。
|
|
26
|
+
const now = new Date(2026, 6, 15)
|
|
25
27
|
const thisMonth = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0')
|
|
26
28
|
|
|
27
29
|
/**
|
|
@@ -98,6 +98,8 @@ export interface CalendarProps extends Omit<React.HTMLAttributes<HTMLDivElement>
|
|
|
98
98
|
navAriaLabel?: string
|
|
99
99
|
viewToggleAriaLabel?: string
|
|
100
100
|
todayLabel?: string
|
|
101
|
+
/** 「新事件」CTA 文字。Override for i18n。CTA 僅在傳 `onCreateEvent` 時渲染(spec Toolbar 段)。 */
|
|
102
|
+
createLabel?: string
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
// ── Event tile color tokens ─────────────────────────────────────────────────
|
|
@@ -114,17 +116,8 @@ function coerceDate(value: string | Date): Date {
|
|
|
114
116
|
return value instanceof Date ? value : new Date(value)
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const start = coerceDate(e.start)
|
|
120
|
-
const end = coerceDate(e.end)
|
|
121
|
-
// 日期落在 [start, end] 範圍內(日精度)
|
|
122
|
-
const d = new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()
|
|
123
|
-
const s = new Date(start.getFullYear(), start.getMonth(), start.getDate()).getTime()
|
|
124
|
-
const eEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate()).getTime()
|
|
125
|
-
return d >= s && d <= eEnd
|
|
126
|
-
})
|
|
127
|
-
}
|
|
119
|
+
// eventsOnDate(per-cell 全 events 掃描)已由 eventsByDate bucketing memo 取代並移除
|
|
120
|
+
// (2026-07-06 D3 perf;留著會觸發 noUnusedLocals TS6133)。
|
|
128
121
|
|
|
129
122
|
// ── Component ──────────────────────────────────────────────────────────────
|
|
130
123
|
|
|
@@ -151,6 +144,7 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calend
|
|
|
151
144
|
navAriaLabel = '行事曆月份導覽', // i18n-allow: DS default; consumer override via navAriaLabel prop
|
|
152
145
|
viewToggleAriaLabel = '檢視切換', // i18n-allow: DS default; consumer override via viewToggleAriaLabel prop
|
|
153
146
|
todayLabel = '今天', // i18n-allow: DS default; consumer override via todayLabel prop
|
|
147
|
+
createLabel = '新事件', // i18n-allow: DS default; consumer override via createLabel prop
|
|
154
148
|
...props
|
|
155
149
|
}, ref) {
|
|
156
150
|
// Controlled / uncontrolled refDate
|
|
@@ -186,10 +180,13 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calend
|
|
|
186
180
|
return eachDayOfInterval({ start: gridStart, end: gridEnd })
|
|
187
181
|
}, [refDate, weekStartsOn])
|
|
188
182
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
183
|
+
// 2026-07-06 D3 perf:formatter 依 locale memo(對齊 weekdayNames 既有做法),避免每 render 重建
|
|
184
|
+
// Intl.DateTimeFormat(已知貴的 constructor);.format(refDate) 每 render 仍執行(cheap)。
|
|
185
|
+
const monthTitleFormatter = React.useMemo(
|
|
186
|
+
() => new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'long' }),
|
|
187
|
+
[locale],
|
|
188
|
+
)
|
|
189
|
+
const monthTitle = monthTitleFormatter.format(refDate)
|
|
193
190
|
|
|
194
191
|
const today = new Date()
|
|
195
192
|
|
|
@@ -200,6 +197,41 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calend
|
|
|
200
197
|
)
|
|
201
198
|
}, [days, locale])
|
|
202
199
|
|
|
200
|
+
// 2026-07-06 D3 perf:原每 render 對 42 cells 各跑 eventsOnDate 全 events filter = O(42×N) +
|
|
201
|
+
// 每比較配 ~5 個 Date;數百-上千 events(行事曆真實規模)單次 render 數十 ms,且父層任何 re-render
|
|
202
|
+
// 全額重付。改 useMemo 單趟 bucket:每 event 只 parse 一次,展開 [start..end](clamp 到可見 grid,
|
|
203
|
+
// 避免長跨度 event 展開爆量)寫入 date→events Map,順便完成 allDay 排序。cell 內改 O(1) map.get。行為 Δ=0。
|
|
204
|
+
const eventsByDate = React.useMemo(() => {
|
|
205
|
+
const map = new Map<string, CalendarEvent[]>()
|
|
206
|
+
if (days.length === 0) return map
|
|
207
|
+
const first = days[0]
|
|
208
|
+
const last = days[days.length - 1]
|
|
209
|
+
const gridStart = new Date(first.getFullYear(), first.getMonth(), first.getDate()).getTime()
|
|
210
|
+
const gridEnd = new Date(last.getFullYear(), last.getMonth(), last.getDate()).getTime()
|
|
211
|
+
for (const e of events) {
|
|
212
|
+
const start = coerceDate(e.start)
|
|
213
|
+
const end = coerceDate(e.end)
|
|
214
|
+
const eEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate()).getTime()
|
|
215
|
+
let sMs = new Date(start.getFullYear(), start.getMonth(), start.getDate()).getTime()
|
|
216
|
+
if (eEnd < gridStart || sMs > gridEnd) continue // 可見窗外對 42 cells 無貢獻
|
|
217
|
+
if (sMs < gridStart) sMs = gridStart
|
|
218
|
+
const lastMs = Math.min(eEnd, gridEnd)
|
|
219
|
+
const cursor = new Date(sMs)
|
|
220
|
+
while (cursor.getTime() <= lastMs) {
|
|
221
|
+
const key = `${cursor.getFullYear()}-${cursor.getMonth() + 1}-${cursor.getDate()}`
|
|
222
|
+
const bucket = map.get(key)
|
|
223
|
+
if (bucket) bucket.push(e)
|
|
224
|
+
else map.set(key, [e])
|
|
225
|
+
cursor.setDate(cursor.getDate() + 1)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// allDay 排前(對齊 Google Calendar 全天列在上;V8 stable sort 保 events 原序 → 與舊 per-cell 一致)
|
|
229
|
+
for (const bucket of map.values()) {
|
|
230
|
+
bucket.sort((a, b) => Number(b.allDay ?? false) - Number(a.allDay ?? false))
|
|
231
|
+
}
|
|
232
|
+
return map
|
|
233
|
+
}, [events, days])
|
|
234
|
+
|
|
203
235
|
const handleToday = () => setRefDate(new Date())
|
|
204
236
|
const handlePrev = () => setRefDate(subMonths(refDate, 1))
|
|
205
237
|
const handleNext = () => setRefDate(addMonths(refDate, 1))
|
|
@@ -265,7 +297,7 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calend
|
|
|
265
297
|
|
|
266
298
|
{onCreateEvent && (
|
|
267
299
|
<Button variant="primary" size="sm" startIcon={Plus} onClick={onCreateEvent}>
|
|
268
|
-
|
|
300
|
+
{createLabel}
|
|
269
301
|
</Button>
|
|
270
302
|
)}
|
|
271
303
|
</div>
|
|
@@ -294,8 +326,9 @@ const Calendar = React.forwardRef<HTMLDivElement, CalendarProps>(function Calend
|
|
|
294
326
|
{days.slice(rowIdx * 7, rowIdx * 7 + 7).map((date) => {
|
|
295
327
|
const inMonth = isSameMonth(date, refDate)
|
|
296
328
|
const isToday = isSameDay(date, today)
|
|
297
|
-
// 2026-06-01 allDay:全天事件排 cell 頂端(對齊 Google Calendar 全天列在上)
|
|
298
|
-
|
|
329
|
+
// 2026-06-01 allDay:全天事件排 cell 頂端(對齊 Google Calendar 全天列在上)——
|
|
330
|
+
// 排序已在 eventsByDate bucketing memo 內完成(D3 perf),cell 內 O(1) 查表
|
|
331
|
+
const dayEvents = eventsByDate.get(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`) ?? []
|
|
299
332
|
const visibleEvents = dayEvents.slice(0, MAX_TILES_PER_CELL)
|
|
300
333
|
const overflowCount = dayEvents.length - visibleEvents.length
|
|
301
334
|
|
|
@@ -414,7 +447,8 @@ export const calendarMeta = {
|
|
|
414
447
|
sizes: {
|
|
415
448
|
|
|
416
449
|
},
|
|
417
|
-
|
|
450
|
+
// 'active' 移除 — 日期格按壓視覺屬 DateGrid(其 meta 已 −active);nav 按壓屬內嵌 Button(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。
|
|
451
|
+
states: ['default', 'hover', 'focus-visible', 'disabled'],
|
|
418
452
|
tokens: {
|
|
419
453
|
bg: ['bg-muted', 'bg-neutral-hover', 'bg-info', 'bg-surface'],
|
|
420
454
|
fg: ['text-fg-disabled', 'text-fg-muted', 'text-foreground'],
|
|
@@ -41,7 +41,7 @@ const Label = ({ children, warn }: { children: React.ReactNode; warn?: boolean }
|
|
|
41
41
|
|
|
42
42
|
const Section = ({ title, children }: { title: string; children: React.ReactNode }) => (
|
|
43
43
|
<section className="mb-12">
|
|
44
|
-
<h2 className="text-
|
|
44
|
+
<h2 className="text-h3 font-bold text-foreground mb-4 pb-2 border-b border-border">{title}</h2>
|
|
45
45
|
{children}
|
|
46
46
|
</section>
|
|
47
47
|
)
|
|
@@ -271,6 +271,7 @@ const CarouselPrevious = React.forwardRef<HTMLButtonElement, ArrowProps>(
|
|
|
271
271
|
)
|
|
272
272
|
CarouselPrevious.displayName = 'CarouselPrevious'
|
|
273
273
|
|
|
274
|
+
// code-quality-allow: long-function — 與 CarouselPrevious 結構對稱的 JSX-heavy arrow(方向/位置/邊界三態 className 組合),拆 helper 會破壞兩支對讀性
|
|
274
275
|
const CarouselNext = React.forwardRef<HTMLButtonElement, ArrowProps>(
|
|
275
276
|
({ className, 'aria-label': ariaLabel = '下一張' /* i18n-allow: DS default; consumer override via aria-label prop */ }, ref) => {
|
|
276
277
|
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
|
@@ -371,7 +372,9 @@ export const carouselMeta = {
|
|
|
371
372
|
sizes: {
|
|
372
373
|
|
|
373
374
|
},
|
|
374
|
-
|
|
375
|
+
// 'active' 移除 — 全檔無按壓視覺(prev/next 按壓屬內嵌 Button meta,同 Notice/Alert 排除慣例;
|
|
376
|
+
// 2026-07-07 詞彙統一 DS-wide 交叉掃補修)。dot hover 為自有 hover 態(bg-on-emphasis alpha 變體)。
|
|
377
|
+
states: ['default', 'hover', 'focus-visible', 'disabled'],
|
|
375
378
|
tokens: {
|
|
376
379
|
bg: [],
|
|
377
380
|
fg: [],
|
|
@@ -162,7 +162,7 @@ Chart 是 **composite data-visualization** 元件,不是單一互動 primitive:
|
|
|
162
162
|
## A11y 預設
|
|
163
163
|
|
|
164
164
|
- **顏色非唯一語義**:不只靠色彩區分類別,配合 icon / label / pattern(Recharts 的 `strokeDasharray` 等)讓色盲 / 黑白列印仍可辨識
|
|
165
|
-
- **Tooltip 鍵盤可存取**:Recharts v3 的 `accessibilityLayer`(
|
|
165
|
+
- **Tooltip 鍵盤可存取**:Recharts v3 的 `accessibilityLayer`(Recharts 3.x 預設啟用;本 DS 長條 / 折線 / 面積範例另顯式標明此 prop 文件化依賴,圓餅 / 環圈走預設)內建鍵盤導覽——圖表 SVG 自動取得 `tabIndex=0` + `role="application"`,使用者用方向鍵 ←/→ 沿軸刻度逐一瀏覽資料點,讀屏器朗讀當前資料點;無需 controlled `activeIndex` 手動接線
|
|
166
166
|
- **對比度**:`--chart-*` 在 light/dark 的 step 選擇已考量對 canvas bg 的對比(light=step-6 / dark=step-5)
|
|
167
167
|
|
|
168
168
|
---
|
|
@@ -255,7 +255,8 @@ const ChartTooltipContent = React.forwardRef<HTMLDivElement, ChartTooltipContent
|
|
|
255
255
|
{nestLabel ? tooltipLabel : null}
|
|
256
256
|
<span className="text-fg-secondary">{itemConfig?.label || item.name}</span>
|
|
257
257
|
</div>
|
|
258
|
-
{
|
|
258
|
+
{/* 2026-07-04 修:falsy check 會讓合法資料值 0 不渲染(shadcn 上游同病)→ null check */}
|
|
259
|
+
{item.value != null && (
|
|
259
260
|
<span className="text-foreground font-mono font-medium tabular-nums">
|
|
260
261
|
{item.value.toLocaleString()}
|
|
261
262
|
</span>
|
|
@@ -209,7 +209,7 @@ export const ClampPolicyRule: Story = {
|
|
|
209
209
|
title="Per-instance override:傳 'none' 不是 undefined"
|
|
210
210
|
note="這組覆寫設定在 SelectionItem 上(Checkbox 內部用它組合 label)。React destructure default 會把 undefined 當「沒傳」→ fallback 到預設。要明確表達「不截」請傳 'none'"
|
|
211
211
|
>
|
|
212
|
-
<Label>SelectionItem labelMaxLines='none' / labelMaxLines={1} / labelMaxLines={2}(1-
|
|
212
|
+
<Label>SelectionItem labelMaxLines='none' / labelMaxLines={1} / labelMaxLines={2}(1-6 的數字;7 以上無對應 line-clamp class,傳了不生效)</Label>
|
|
213
213
|
</Rule>
|
|
214
214
|
</div>
|
|
215
215
|
),
|
|
@@ -249,7 +249,7 @@ Indeterminate 是由父層邏輯控制的狀態,Checkbox 本身不會自動進
|
|
|
249
249
|
|
|
250
250
|
- **Uncontrolled**:只傳 `defaultChecked`,DOM 自管 — 適合表單 native submit
|
|
251
251
|
- **Controlled**:傳 `checked` + `onCheckedChange`,React state 主導 — 適合需即時聯動其他欄位
|
|
252
|
-
- **Read-only**:用 `readOnly` prop(不是省略 `onCheckedChange`)。standalone:`readOnly` 設 `aria-readonly` / `data-readonly` / `tabIndex=-1` + cva `pointer-events-none
|
|
252
|
+
- **Read-only**:用 `readOnly` prop(不是省略 `onCheckedChange`)。standalone:`readOnly` 設 `aria-readonly` / `data-readonly` / `tabIndex=-1` + cva `pointer-events-none` + onClick preventDefault guard(2026-07-05 D4 補:`<label htmlFor>` 的 synthetic click 非 pointer event,`pointer-events-none` 攔不到,需 guard 才真鎖),鎖互動但保留 checked 視覺;**Field 內(無 inline label)改渲染 readonly 灰框 + ✓/—**(見上方 mode 段)。注意:只傳 `checked` 而不傳 `onCheckedChange` 僅讓 Radix 把值鎖在 prop(不會更新),控件仍可 focus / click、不會進 disabled state — 那不是 readonly
|
|
253
253
|
|
|
254
254
|
### `mode` prop(Field mode,正交於 size)
|
|
255
255
|
|
|
@@ -85,13 +85,16 @@ export interface CheckboxProps
|
|
|
85
85
|
/**
|
|
86
86
|
* Inline label。提供時 Checkbox 自動透過 SelectionItem 包裝,
|
|
87
87
|
* 套用 text-body / text-foreground / disabled 色 的 codified 樣式。
|
|
88
|
-
* 在 <Field> context
|
|
88
|
+
* 在 <Field> context 內且不在 CheckboxGroup 內時,此 prop 會被忽略(由 FieldLabel 接管);
|
|
89
|
+
* CheckboxGroup 內每個 checkbox 的 label 是它自己的選項名,必保留
|
|
90
|
+
* (同檔 shouldSuppressLabel = insideField && !insideGroup,AR50 anchor)。
|
|
89
91
|
*/
|
|
90
92
|
label?: React.ReactNode
|
|
91
93
|
/**
|
|
92
94
|
* Inline description(secondary 文字)。須與 label 搭配使用。
|
|
93
95
|
* 套用 text-body / text-fg-secondary 樣式。
|
|
94
|
-
* 在 <Field> context
|
|
96
|
+
* 在 <Field> context 內且不在 CheckboxGroup 內時,此 prop 會被忽略(由 FieldDescription 接管);
|
|
97
|
+
* CheckboxGroup 內的 description 屬各選項自有,必保留(同 label 的 group 例外)。
|
|
95
98
|
*/
|
|
96
99
|
description?: React.ReactNode
|
|
97
100
|
/** 可選左側 icon(label 前)— 2026-06-12 M30 修:轉發 SelectionItem 既有 canonical 槽(selection-item.tsx jsDoc 為 SSOT;與 avatar 互斥)*/
|
|
@@ -188,13 +191,29 @@ const Checkbox = React.forwardRef<
|
|
|
188
191
|
// readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)
|
|
189
192
|
const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'
|
|
190
193
|
|
|
194
|
+
// 2026-07-04 修:display / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props
|
|
195
|
+
// (id/data-*/aria-*)且不轉發 forwardRef ref → consumer 的 aria-label 等靜默失效。
|
|
196
|
+
// 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Switch/
|
|
197
|
+
// RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。
|
|
198
|
+
const {
|
|
199
|
+
checked: checkedProp,
|
|
200
|
+
defaultChecked: defaultCheckedProp,
|
|
201
|
+
onCheckedChange: _onCheckedChange,
|
|
202
|
+
required: _required,
|
|
203
|
+
name: _name,
|
|
204
|
+
value: _value,
|
|
205
|
+
asChild: _asChild,
|
|
206
|
+
children: _children,
|
|
207
|
+
...restDomProps
|
|
208
|
+
} = props
|
|
209
|
+
|
|
191
210
|
// ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────
|
|
192
211
|
// 純展示模式:無互動 primitive、渲染 ✓ / —(checked=true → ✓ / 其他 → —)。取代 BooleanDisplay。
|
|
193
212
|
if (resolvedMode === 'display') {
|
|
194
|
-
const isChecked =
|
|
213
|
+
const isChecked = checkedProp === true
|
|
195
214
|
return isChecked
|
|
196
|
-
? <span className="text-foreground">✓</span>
|
|
197
|
-
: <span className="text-fg-muted">—</span>
|
|
215
|
+
? <span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className="text-foreground">✓</span>
|
|
216
|
+
: <span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className="text-fg-muted">—</span>
|
|
198
217
|
}
|
|
199
218
|
|
|
200
219
|
// ── mode='readonly' in Field(2026-06-12 user 拍板「灰框 + ✓/—」)─────────────
|
|
@@ -206,10 +225,12 @@ const Checkbox = React.forwardRef<
|
|
|
206
225
|
// Scope:僅 Field 內且無 inline label(FieldLabel 接管 label 的表單欄位場景);
|
|
207
226
|
// standalone readOnly(settings list / SelectionItem row)維持原樣鎖互動不變。
|
|
208
227
|
if (effectiveReadOnly && insideField && effectiveLabel == null) {
|
|
209
|
-
const isChecked = (
|
|
228
|
+
const isChecked = (checkedProp ?? defaultCheckedProp) === true
|
|
210
229
|
const boxSize = resolvedBoxSize
|
|
211
230
|
return (
|
|
212
231
|
<div
|
|
232
|
+
{...(restDomProps as React.HTMLAttributes<HTMLDivElement>)}
|
|
233
|
+
ref={ref as React.Ref<HTMLDivElement>}
|
|
213
234
|
role="checkbox"
|
|
214
235
|
aria-checked={isChecked}
|
|
215
236
|
aria-readonly="true"
|
|
@@ -239,6 +260,18 @@ const Checkbox = React.forwardRef<
|
|
|
239
260
|
aria-describedby={fieldCtx?.descriptionId}
|
|
240
261
|
className={cn(checkboxVariants({ size }), className)}
|
|
241
262
|
{...props}
|
|
263
|
+
// 2026-07-05 D4 修:readOnly 鎖互動補 label 繞道 — <label htmlFor> 的 synthetic click
|
|
264
|
+
// 不是 pointer event,cva pointer-events-none 攔不到,點 label 文字仍 toggle。
|
|
265
|
+
// preventDefault 讓 Radix composeEventHandlers(checkForDefaultPrevented)跳過內部 toggle;
|
|
266
|
+
// 必列在 {...props} 之後才不被 consumer onClick 覆蓋(readOnly 時 consumer onClick 一併鎖,
|
|
267
|
+
// 與 pointer-events-none 擋直接點擊的行為一致)。
|
|
268
|
+
onClick={(event) => {
|
|
269
|
+
if (effectiveReadOnly) {
|
|
270
|
+
event.preventDefault()
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
props.onClick?.(event)
|
|
274
|
+
}}
|
|
242
275
|
>
|
|
243
276
|
<CheckboxPrimitive.Indicator className="grid place-content-center text-current">
|
|
244
277
|
{props.checked === 'indeterminate'
|
|
@@ -283,7 +316,8 @@ export const checkboxMeta = {
|
|
|
283
316
|
md: { fieldHeight: 32, iconSize: 12, typography: 'body' },
|
|
284
317
|
lg: { fieldHeight: 36, iconSize: 16, typography: 'body-lg' },
|
|
285
318
|
},
|
|
286
|
-
|
|
319
|
+
// 'checked' = 勾選持續態(bg-primary;2026-07-07 meta 詞彙統一補列,含 indeterminate 同族)
|
|
320
|
+
states: ['default', 'hover', 'checked', 'focus-visible', 'disabled'],
|
|
287
321
|
tokens: {
|
|
288
322
|
bg: ['bg-disabled', 'bg-primary', 'bg-primary-hover', 'bg-surface'],
|
|
289
323
|
fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground'],
|
|
@@ -134,7 +134,7 @@ export const ColorMatrix: Story = {
|
|
|
134
134
|
<div>
|
|
135
135
|
<H3>狀態 × 色彩 Token 矩陣</H3>
|
|
136
136
|
<Desc>
|
|
137
|
-
Chip 採 pill-設計準則 選中規則(跟 SegmentedControl
|
|
137
|
+
Chip 採 pill-設計準則 選中規則(跟 SegmentedControl 共用;semantic.css SSOT,2026-07-06 拍板改 base):selected 時 `--primary` 同時染 border 和 text,
|
|
138
138
|
**底色維持 `--surface` 不變**——不用 primary-subtle 底色(那是 Button subtle 的視覺語言,跟 filter chip 不同)。
|
|
139
139
|
視覺輕量是 filter 語意必要條件,避免 chip 群組喧賓奪主壓過資料表格。
|
|
140
140
|
</Desc>
|
|
@@ -167,8 +167,8 @@ export const ColorMatrix: Story = {
|
|
|
167
167
|
<tr>
|
|
168
168
|
<Td mono>selected</Td>
|
|
169
169
|
<Td><span className="inline-flex items-center gap-1.5"><Swatch value="--surface" size="sm" /><span className="font-mono">--surface(不變)</span></span></Td>
|
|
170
|
-
<Td><span className="inline-flex items-center gap-1.5"><Swatch value="--primary
|
|
171
|
-
<Td><span className="inline-flex items-center gap-1.5"><Swatch value="--primary
|
|
170
|
+
<Td><span className="inline-flex items-center gap-1.5"><Swatch value="--primary" size="sm" /><span className="font-mono">--primary</span></span></Td>
|
|
171
|
+
<Td><span className="inline-flex items-center gap-1.5"><Swatch value="--primary" size="sm" /><span className="font-mono">--primary</span></span></Td>
|
|
172
172
|
<Td mono>currentColor</Td>
|
|
173
173
|
</tr>
|
|
174
174
|
<tr>
|
|
@@ -185,7 +185,7 @@ export const ColorMatrix: Story = {
|
|
|
185
185
|
|
|
186
186
|
<div>
|
|
187
187
|
<H3>視覺並列對照</H3>
|
|
188
|
-
<Desc>左 default / 中 selected / 右 disabled,觀察 border
|
|
188
|
+
<Desc>左 default / 中 selected / 右 disabled,觀察 border 同時染 primary(base)的視覺變化(非 bg 變化)。</Desc>
|
|
189
189
|
<div className="flex items-center gap-8 px-6 py-5 rounded-lg bg-canvas border border-divider">
|
|
190
190
|
<div className="flex flex-col gap-2 items-start">
|
|
191
191
|
<span className="text-[11px] text-fg-muted font-mono">default</span>
|
|
@@ -301,7 +301,7 @@ export const StateBehavior: Story = {
|
|
|
301
301
|
<H3>四種狀態 × 色彩 Token</H3>
|
|
302
302
|
<Desc>
|
|
303
303
|
選中態走 pill-設計準則 規則(跟 SegmentedControl 完全一致):
|
|
304
|
-
**primary
|
|
304
|
+
**primary base 同時染 border 和 text**,底色維持 bg-surface 不變——不用 primary-subtle
|
|
305
305
|
底色(那是 Button subtle 的視覺語言,跟 chip 不同)。
|
|
306
306
|
</Desc>
|
|
307
307
|
<div className="overflow-x-auto mb-4">
|
|
@@ -323,8 +323,8 @@ export const StateBehavior: Story = {
|
|
|
323
323
|
<tr>
|
|
324
324
|
<Td mono>selected (data-state=on)</Td>
|
|
325
325
|
<Td><TokenCell token="--surface" /></Td>
|
|
326
|
-
<Td><TokenCell token="--primary
|
|
327
|
-
<Td><TokenCell token="--primary
|
|
326
|
+
<Td><TokenCell token="--primary" display="primary" /></Td>
|
|
327
|
+
<Td><TokenCell token="--primary" display="primary" /></Td>
|
|
328
328
|
</tr>
|
|
329
329
|
<tr>
|
|
330
330
|
<Td mono>disabled</Td>
|
|
@@ -351,7 +351,7 @@ export const StateBehavior: Story = {
|
|
|
351
351
|
<H3>Selected 色彩跟 SegmentedControl 完全一致</H3>
|
|
352
352
|
<Desc>
|
|
353
353
|
兩者都是 pill 選擇語意(filter / 單選 radio),選中態視覺語言統一:
|
|
354
|
-
primary
|
|
354
|
+
primary base 染 border + text,底色不變。只有「連體 vs 獨立」的視覺差異,選中規則是同一套。
|
|
355
355
|
</Desc>
|
|
356
356
|
<div className="border border-dashed border-divider rounded-md p-4">
|
|
357
357
|
<div className="text-caption text-fg-muted mb-2">Chip(獨立 pill)</div>
|
|
@@ -416,7 +416,7 @@ export const Accessibility = {
|
|
|
416
416
|
render: () => (
|
|
417
417
|
<div className="max-w-3xl text-body text-fg-secondary">
|
|
418
418
|
<h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
|
|
419
|
-
<p className="whitespace-pre-line">{"詳 「無障礙設計」段。摘要:\n\n ARIA / Pattern :繼承 Radix toggle-group 鍵盤模式(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/toggle-group#accessibility)。\n\n Keyboard 行為 :\n\n- Tab — 進入整組 chip(只有一個 Tab 停留點)\n- ←/→ — 在組內 chip 之間移動焦點\n- Tab — 再按一次離開整組\n- Enter / Space — 切換選取\n\n Focus :焦點環為 2px 的 --ring
|
|
419
|
+
<p className="whitespace-pre-line">{"詳 「無障礙設計」段。摘要:\n\n ARIA / Pattern :繼承 Radix toggle-group 鍵盤模式(role / aria-* / 鍵盤導覽)。詳 [Radix Accessibility docs](https://www.radix-ui.com/primitives/docs/components/toggle-group#accessibility)。\n\n Keyboard 行為 :\n\n- Tab — 進入整組 chip(只有一個 Tab 停留點)\n- ←/→ — 在組內 chip 之間移動焦點\n- Tab — 再按一次離開整組\n- Enter / Space — 切換選取\n\n Focus :焦點環為 2px 的 --ring 色(ring-2 ring-ring ring-offset-1,以 box-shadow 實作並 outline-none;focus-visible 才顯示)。整組 chip 用方向鍵移動焦點、Tab 進出整組——這不是 Dialog 那種把焦點鎖在裡面的行為。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA 對比 ≥ 4.5:1(文字)"}</p>
|
|
420
420
|
</div>
|
|
421
421
|
),
|
|
422
422
|
}
|
|
@@ -197,8 +197,8 @@ export const SelectedStyleRule: Story = {
|
|
|
197
197
|
render: () => (
|
|
198
198
|
<div>
|
|
199
199
|
<Rule
|
|
200
|
-
title="選中 = primary
|
|
201
|
-
note="對齊 SegmentedControl / Tabs
|
|
200
|
+
title="選中 = primary text + border,底色不變"
|
|
201
|
+
note="對齊 SegmentedControl / Tabs 的選中 canonical(primary base 同時染文字和線條;semantic.css SSOT,2026-07-06 拍板自 hover 階改 base——瞬時弱、持續強)。用 bg 強調會讓 chip 看起來變成「按鈕」,混淆多選濾鏡的語意"
|
|
202
202
|
>
|
|
203
203
|
<ChipGroup type="multiple" defaultValue={['react', 'ts']}>
|
|
204
204
|
<Chip value="react">React</Chip>
|
|
@@ -206,7 +206,7 @@ export const SelectedStyleRule: Story = {
|
|
|
206
206
|
<Chip value="ts">TypeScript</Chip>
|
|
207
207
|
<Chip value="js">JavaScript</Chip>
|
|
208
208
|
</ChipGroup>
|
|
209
|
-
<Label>↑ 選中(React / TypeScript)= primary
|
|
209
|
+
<Label>↑ 選中(React / TypeScript)= primary 文字 + 邊框,底色仍 bg-surface</Label>
|
|
210
210
|
</Rule>
|
|
211
211
|
|
|
212
212
|
<Rule
|