@qijenchen/design-system 0.1.0-beta.10
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/README.md +163 -0
- package/dist/components/Accordion/accordion.d.ts +37 -0
- package/dist/components/Accordion/accordion.d.ts.map +1 -0
- package/dist/components/Accordion/accordion.js +78 -0
- package/dist/components/Accordion/accordion.js.map +1 -0
- package/dist/components/Alert/alert.d.ts +47 -0
- package/dist/components/Alert/alert.d.ts.map +1 -0
- package/dist/components/Alert/alert.js +132 -0
- package/dist/components/Alert/alert.js.map +1 -0
- package/dist/components/AppShell/_demo-helpers.d.ts +49 -0
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.d.ts +76 -0
- package/dist/components/AppShell/app-shell.d.ts.map +1 -0
- package/dist/components/AppShell/app-shell.js +214 -0
- package/dist/components/AppShell/app-shell.js.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts +40 -0
- package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -0
- package/dist/components/AspectRatio/aspect-ratio.js +23 -0
- package/dist/components/AspectRatio/aspect-ratio.js.map +1 -0
- package/dist/components/Avatar/avatar.d.ts +85 -0
- package/dist/components/Avatar/avatar.d.ts.map +1 -0
- package/dist/components/Avatar/avatar.js +195 -0
- package/dist/components/Avatar/avatar.js.map +1 -0
- package/dist/components/Badge/badge.d.ts +43 -0
- package/dist/components/Badge/badge.d.ts.map +1 -0
- package/dist/components/Badge/badge.js +69 -0
- package/dist/components/Badge/badge.js.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts +163 -0
- package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb/breadcrumb.js +300 -0
- package/dist/components/Breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts +46 -0
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js +78 -0
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -0
- package/dist/components/Button/button-group.d.ts +49 -0
- package/dist/components/Button/button-group.d.ts.map +1 -0
- package/dist/components/Button/button-group.js +46 -0
- package/dist/components/Button/button-group.js.map +1 -0
- package/dist/components/Button/button.d.ts +203 -0
- package/dist/components/Button/button.d.ts.map +1 -0
- package/dist/components/Button/button.js +309 -0
- package/dist/components/Button/button.js.map +1 -0
- package/dist/components/Calendar/calendar.d.ts +81 -0
- package/dist/components/Calendar/calendar.d.ts.map +1 -0
- package/dist/components/Calendar/calendar.js +282 -0
- package/dist/components/Calendar/calendar.js.map +1 -0
- package/dist/components/Carousel/carousel.d.ts +61 -0
- package/dist/components/Carousel/carousel.d.ts.map +1 -0
- package/dist/components/Carousel/carousel.js +276 -0
- package/dist/components/Carousel/carousel.js.map +1 -0
- package/dist/components/Chart/chart.d.ts +94 -0
- package/dist/components/Chart/chart.d.ts.map +1 -0
- package/dist/components/Chart/chart.js +233 -0
- package/dist/components/Chart/chart.js.map +1 -0
- package/dist/components/Checkbox/checkbox-group.d.ts +58 -0
- package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox-group.js +28 -0
- package/dist/components/Checkbox/checkbox-group.js.map +1 -0
- package/dist/components/Checkbox/checkbox.d.ts +73 -0
- package/dist/components/Checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/checkbox.js +125 -0
- package/dist/components/Checkbox/checkbox.js.map +1 -0
- package/dist/components/Chip/chip.d.ts +54 -0
- package/dist/components/Chip/chip.d.ts.map +1 -0
- package/dist/components/Chip/chip.js +224 -0
- package/dist/components/Chip/chip.js.map +1 -0
- package/dist/components/CircularProgress/circular-progress.d.ts +40 -0
- package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -0
- package/dist/components/CircularProgress/circular-progress.js +118 -0
- package/dist/components/CircularProgress/circular-progress.js.map +1 -0
- package/dist/components/Coachmark/coachmark.d.ts +100 -0
- package/dist/components/Coachmark/coachmark.d.ts.map +1 -0
- package/dist/components/Coachmark/coachmark.js +107 -0
- package/dist/components/Coachmark/coachmark.js.map +1 -0
- package/dist/components/Combobox/combobox.d.ts +150 -0
- package/dist/components/Combobox/combobox.d.ts.map +1 -0
- package/dist/components/Combobox/combobox.js +595 -0
- package/dist/components/Combobox/combobox.js.map +1 -0
- package/dist/components/Command/command.d.ts +106 -0
- package/dist/components/Command/command.d.ts.map +1 -0
- package/dist/components/Command/command.js +123 -0
- package/dist/components/Command/command.js.map +1 -0
- package/dist/components/DataTable/active-editor-controller.d.ts +66 -0
- package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.d.ts +37 -0
- package/dist/components/DataTable/cell-registry.d.ts.map +1 -0
- package/dist/components/DataTable/cell-registry.js +377 -0
- package/dist/components/DataTable/cell-registry.js.map +1 -0
- package/dist/components/DataTable/column-types.d.ts +145 -0
- package/dist/components/DataTable/column-types.d.ts.map +1 -0
- package/dist/components/DataTable/column-types.js +17 -0
- package/dist/components/DataTable/column-types.js.map +1 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +49 -0
- package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts +30 -0
- package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts +78 -0
- package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -0
- package/dist/components/DataTable/data-table-interaction-layer.js +220 -0
- package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts +19 -0
- package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.d.ts +181 -0
- package/dist/components/DataTable/data-table.d.ts.map +1 -0
- package/dist/components/DataTable/data-table.js +1851 -0
- package/dist/components/DataTable/data-table.js.map +1 -0
- package/dist/components/DataTable/filter-operators.d.ts +116 -0
- package/dist/components/DataTable/filter-operators.d.ts.map +1 -0
- package/dist/components/DataTable/filter-tree.d.ts +66 -0
- package/dist/components/DataTable/filter-tree.d.ts.map +1 -0
- package/dist/components/DataTable/lib/column-meta.d.ts +49 -0
- package/dist/components/DataTable/lib/column-meta.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.d.ts +61 -0
- package/dist/components/DateGrid/date-grid.d.ts.map +1 -0
- package/dist/components/DateGrid/date-grid.js +168 -0
- package/dist/components/DateGrid/date-grid.js.map +1 -0
- package/dist/components/DatePicker/date-picker.d.ts +119 -0
- package/dist/components/DatePicker/date-picker.d.ts.map +1 -0
- package/dist/components/DatePicker/date-picker.js +743 -0
- package/dist/components/DatePicker/date-picker.js.map +1 -0
- package/dist/components/DescriptionList/description-list.d.ts +60 -0
- package/dist/components/DescriptionList/description-list.d.ts.map +1 -0
- package/dist/components/DescriptionList/description-list.js +77 -0
- package/dist/components/DescriptionList/description-list.js.map +1 -0
- package/dist/components/Dialog/dialog.d.ts +54 -0
- package/dist/components/Dialog/dialog.d.ts.map +1 -0
- package/dist/components/Dialog/dialog.js +151 -0
- package/dist/components/Dialog/dialog.js.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts +111 -0
- package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -0
- package/dist/components/DropdownMenu/dropdown-menu.js +288 -0
- package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -0
- package/dist/components/Empty/empty.d.ts +40 -0
- package/dist/components/Empty/empty.d.ts.map +1 -0
- package/dist/components/Empty/empty.js +66 -0
- package/dist/components/Empty/empty.js.map +1 -0
- package/dist/components/Field/field-context.d.ts +77 -0
- package/dist/components/Field/field-context.d.ts.map +1 -0
- package/dist/components/Field/field-context.js +37 -0
- package/dist/components/Field/field-context.js.map +1 -0
- package/dist/components/Field/field-types.d.ts +5 -0
- package/dist/components/Field/field-types.d.ts.map +1 -0
- package/dist/components/Field/field-types.js +13 -0
- package/dist/components/Field/field-types.js.map +1 -0
- package/dist/components/Field/field-wrapper.d.ts +17 -0
- package/dist/components/Field/field-wrapper.d.ts.map +1 -0
- package/dist/components/Field/field-wrapper.js +252 -0
- package/dist/components/Field/field-wrapper.js.map +1 -0
- package/dist/components/Field/field.d.ts +127 -0
- package/dist/components/Field/field.d.ts.map +1 -0
- package/dist/components/Field/field.js +295 -0
- package/dist/components/Field/field.js.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts +74 -0
- package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -0
- package/dist/components/FieldControlGroup/field-control-group.js +62 -0
- package/dist/components/FieldControlGroup/field-control-group.js.map +1 -0
- package/dist/components/FileItem/file-item.d.ts +44 -0
- package/dist/components/FileItem/file-item.d.ts.map +1 -0
- package/dist/components/FileItem/file-item.js +202 -0
- package/dist/components/FileItem/file-item.js.map +1 -0
- package/dist/components/FileUpload/file-upload.d.ts +97 -0
- package/dist/components/FileUpload/file-upload.d.ts.map +1 -0
- package/dist/components/FileUpload/file-upload.js +231 -0
- package/dist/components/FileUpload/file-upload.js.map +1 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts +73 -0
- package/dist/components/FileViewer/file-viewer-types.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.d.ts +82 -0
- package/dist/components/FileViewer/file-viewer.d.ts.map +1 -0
- package/dist/components/FileViewer/file-viewer.js +752 -0
- package/dist/components/FileViewer/file-viewer.js.map +1 -0
- package/dist/components/FileViewer/image-renderer.d.ts +9 -0
- package/dist/components/FileViewer/image-renderer.d.ts.map +1 -0
- package/dist/components/FileViewer/image-renderer.js +165 -0
- package/dist/components/FileViewer/image-renderer.js.map +1 -0
- package/dist/components/HoverCard/hover-card.d.ts +30 -0
- package/dist/components/HoverCard/hover-card.d.ts.map +1 -0
- package/dist/components/HoverCard/hover-card.js +61 -0
- package/dist/components/HoverCard/hover-card.js.map +1 -0
- package/dist/components/Input/input.d.ts +72 -0
- package/dist/components/Input/input.d.ts.map +1 -0
- package/dist/components/Input/input.js +148 -0
- package/dist/components/Input/input.js.map +1 -0
- package/dist/components/LinkInput/link-input.d.ts +46 -0
- package/dist/components/LinkInput/link-input.d.ts.map +1 -0
- package/dist/components/LinkInput/link-input.js +215 -0
- package/dist/components/LinkInput/link-input.js.map +1 -0
- package/dist/components/Menu/menu-item.d.ts +83 -0
- package/dist/components/Menu/menu-item.d.ts.map +1 -0
- package/dist/components/Menu/menu-item.js +209 -0
- package/dist/components/Menu/menu-item.js.map +1 -0
- package/dist/components/NameCard/name-card.d.ts +85 -0
- package/dist/components/NameCard/name-card.d.ts.map +1 -0
- package/dist/components/NameCard/name-card.js +153 -0
- package/dist/components/NameCard/name-card.js.map +1 -0
- package/dist/components/Notice/notice.d.ts +69 -0
- package/dist/components/Notice/notice.d.ts.map +1 -0
- package/dist/components/Notice/notice.js +121 -0
- package/dist/components/Notice/notice.js.map +1 -0
- package/dist/components/NumberInput/number-input.d.ts +57 -0
- package/dist/components/NumberInput/number-input.d.ts.map +1 -0
- package/dist/components/NumberInput/number-input.js +131 -0
- package/dist/components/NumberInput/number-input.js.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts +23 -0
- package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js +111 -0
- package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +57 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js +35 -0
- package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts +7 -0
- package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js +25 -0
- package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -0
- package/dist/components/PeoplePicker/people-picker.d.ts +77 -0
- package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -0
- package/dist/components/PeoplePicker/people-picker.js +263 -0
- package/dist/components/PeoplePicker/people-picker.js.map +1 -0
- package/dist/components/PeoplePicker/person-display.d.ts +66 -0
- package/dist/components/PeoplePicker/person-display.d.ts.map +1 -0
- package/dist/components/PeoplePicker/person-display.js +203 -0
- package/dist/components/PeoplePicker/person-display.js.map +1 -0
- package/dist/components/Popover/popover.d.ts +50 -0
- package/dist/components/Popover/popover.d.ts.map +1 -0
- package/dist/components/Popover/popover.js +113 -0
- package/dist/components/Popover/popover.js.map +1 -0
- package/dist/components/ProgressBar/progress-bar.d.ts +37 -0
- package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -0
- package/dist/components/ProgressBar/progress-bar.js +86 -0
- package/dist/components/ProgressBar/progress-bar.js.map +1 -0
- package/dist/components/RadioGroup/radio-group.d.ts +78 -0
- package/dist/components/RadioGroup/radio-group.d.ts.map +1 -0
- package/dist/components/RadioGroup/radio-group.js +153 -0
- package/dist/components/RadioGroup/radio-group.js.map +1 -0
- package/dist/components/Rating/rating.d.ts +46 -0
- package/dist/components/Rating/rating.d.ts.map +1 -0
- package/dist/components/Rating/rating.js +179 -0
- package/dist/components/Rating/rating.js.map +1 -0
- package/dist/components/ScrollArea/scroll-area.d.ts +45 -0
- package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -0
- package/dist/components/ScrollArea/scroll-area.js +65 -0
- package/dist/components/ScrollArea/scroll-area.js.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts +102 -0
- package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -0
- package/dist/components/SegmentedControl/segmented-control.js +171 -0
- package/dist/components/SegmentedControl/segmented-control.js.map +1 -0
- package/dist/components/Select/select.d.ts +102 -0
- package/dist/components/Select/select.d.ts.map +1 -0
- package/dist/components/Select/select.js +435 -0
- package/dist/components/Select/select.js.map +1 -0
- package/dist/components/SelectMenu/select-menu.d.ts +103 -0
- package/dist/components/SelectMenu/select-menu.d.ts.map +1 -0
- package/dist/components/SelectMenu/select-menu.js +239 -0
- package/dist/components/SelectMenu/select-menu.js.map +1 -0
- package/dist/components/SelectionControl/selection-item.d.ts +69 -0
- package/dist/components/SelectionControl/selection-item.d.ts.map +1 -0
- package/dist/components/SelectionControl/selection-item.js +142 -0
- package/dist/components/SelectionControl/selection-item.js.map +1 -0
- package/dist/components/Separator/separator.d.ts +17 -0
- package/dist/components/Separator/separator.d.ts.map +1 -0
- package/dist/components/Separator/separator.js +39 -0
- package/dist/components/Separator/separator.js.map +1 -0
- package/dist/components/Sheet/sheet.d.ts +56 -0
- package/dist/components/Sheet/sheet.d.ts.map +1 -0
- package/dist/components/Sheet/sheet.js +145 -0
- package/dist/components/Sheet/sheet.js.map +1 -0
- package/dist/components/Sidebar/sidebar.d.ts +195 -0
- package/dist/components/Sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar/sidebar.js +826 -0
- package/dist/components/Sidebar/sidebar.js.map +1 -0
- package/dist/components/Skeleton/skeleton.d.ts +16 -0
- package/dist/components/Skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton/skeleton.js +30 -0
- package/dist/components/Skeleton/skeleton.js.map +1 -0
- package/dist/components/Slider/slider.d.ts +48 -0
- package/dist/components/Slider/slider.d.ts.map +1 -0
- package/dist/components/Slider/slider.js +108 -0
- package/dist/components/Slider/slider.js.map +1 -0
- package/dist/components/Steps/steps.d.ts +71 -0
- package/dist/components/Steps/steps.d.ts.map +1 -0
- package/dist/components/Steps/steps.js +583 -0
- package/dist/components/Steps/steps.js.map +1 -0
- package/dist/components/Switch/switch.d.ts +112 -0
- package/dist/components/Switch/switch.d.ts.map +1 -0
- package/dist/components/Switch/switch.js +179 -0
- package/dist/components/Switch/switch.js.map +1 -0
- package/dist/components/Tabs/tabs.d.ts +104 -0
- package/dist/components/Tabs/tabs.d.ts.map +1 -0
- package/dist/components/Tabs/tabs.js +316 -0
- package/dist/components/Tabs/tabs.js.map +1 -0
- package/dist/components/Tag/tag.d.ts +86 -0
- package/dist/components/Tag/tag.d.ts.map +1 -0
- package/dist/components/Tag/tag.js +172 -0
- package/dist/components/Tag/tag.js.map +1 -0
- package/dist/components/Textarea/textarea.d.ts +74 -0
- package/dist/components/Textarea/textarea.d.ts.map +1 -0
- package/dist/components/Textarea/textarea.js +224 -0
- package/dist/components/Textarea/textarea.js.map +1 -0
- package/dist/components/TimePicker/time-columns.d.ts +46 -0
- package/dist/components/TimePicker/time-columns.d.ts.map +1 -0
- package/dist/components/TimePicker/time-columns.js +173 -0
- package/dist/components/TimePicker/time-columns.js.map +1 -0
- package/dist/components/TimePicker/time-picker.d.ts +94 -0
- package/dist/components/TimePicker/time-picker.d.ts.map +1 -0
- package/dist/components/TimePicker/time-picker.js +253 -0
- package/dist/components/TimePicker/time-picker.js.map +1 -0
- package/dist/components/Toast/toast.d.ts +61 -0
- package/dist/components/Toast/toast.d.ts.map +1 -0
- package/dist/components/Toast/toast.js +76 -0
- package/dist/components/Toast/toast.js.map +1 -0
- package/dist/components/Tooltip/tooltip.d.ts +20 -0
- package/dist/components/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip/tooltip.js +53 -0
- package/dist/components/Tooltip/tooltip.js.map +1 -0
- package/dist/components/TreeView/tree-view.d.ts +166 -0
- package/dist/components/TreeView/tree-view.d.ts.map +1 -0
- package/dist/components/TreeView/tree-view.js +617 -0
- package/dist/components/TreeView/tree-view.js.map +1 -0
- package/dist/hooks/use-controllable.d.ts +16 -0
- package/dist/hooks/use-controllable.d.ts.map +1 -0
- package/dist/hooks/use-controllable.js +26 -0
- package/dist/hooks/use-controllable.js.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts +2 -0
- package/dist/hooks/use-is-narrow-viewport.d.ts.map +1 -0
- package/dist/hooks/use-is-narrow-viewport.js +19 -0
- package/dist/hooks/use-is-narrow-viewport.js.map +1 -0
- package/dist/hooks/use-is-touch-device.d.ts +8 -0
- package/dist/hooks/use-is-touch-device.d.ts.map +1 -0
- package/dist/hooks/use-is-touch-device.js +16 -0
- package/dist/hooks/use-is-touch-device.js.map +1 -0
- package/dist/hooks/use-overflow-items.d.ts +124 -0
- package/dist/hooks/use-overflow-items.d.ts.map +1 -0
- package/dist/hooks/use-overflow-items.js +97 -0
- package/dist/hooks/use-overflow-items.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/drag-visual.d.ts +158 -0
- package/dist/lib/drag-visual.d.ts.map +1 -0
- package/dist/lib/drag-visual.js +96 -0
- package/dist/lib/drag-visual.js.map +1 -0
- package/dist/lib/i18n/i18n-context.d.ts +105 -0
- package/dist/lib/i18n/i18n-context.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.d.ts +54 -0
- package/dist/lib/multi-select-ordering.d.ts.map +1 -0
- package/dist/lib/multi-select-ordering.js +13 -0
- package/dist/lib/multi-select-ordering.js.map +1 -0
- package/dist/lib/utils.d.ts +12 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +79 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts +370 -0
- package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -0
- package/dist/patterns/element-anatomy/item-anatomy.js +272 -0
- package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts +80 -0
- package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -0
- package/dist/patterns/header-canonical/chrome-header.js +75 -0
- package/dist/patterns/header-canonical/chrome-header.js.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +101 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js +105 -0
- package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts +28 -0
- package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -0
- package/dist/patterns/overlay-surface/overlay-surface.js +85 -0
- package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts +102 -0
- package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -0
- package/dist/patterns/resize-handle/resize-handle.js +74 -0
- package/dist/patterns/resize-handle/resize-handle.js.map +1 -0
- package/dist/react-day-picker.css +457 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts +40 -0
- package/dist/stories-helpers/anatomy/anatomy-utils.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts +12 -0
- package/dist/tokens/elevation/overlay-geometry.d.ts.map +1 -0
- package/dist/tokens/elevation/overlay-geometry.js +7 -0
- package/dist/tokens/elevation/overlay-geometry.js.map +1 -0
- package/dist/tokens/motion/motion.d.ts +15 -0
- package/dist/tokens/motion/motion.d.ts.map +1 -0
- package/dist/tokens/motion/motion.js +9 -0
- package/dist/tokens/motion/motion.js.map +1 -0
- package/dist/tokens/uiSize/icon-size.d.ts +53 -0
- package/dist/tokens/uiSize/icon-size.d.ts.map +1 -0
- package/package.json +92 -0
- package/src/README.md +32 -0
- package/src/components/Accordion/accordion.tsx +104 -0
- package/src/components/Alert/alert.tsx +188 -0
- package/src/components/AppShell/_demo-helpers.tsx +198 -0
- package/src/components/AppShell/app-shell.tsx +364 -0
- package/src/components/AspectRatio/aspect-ratio.tsx +58 -0
- package/src/components/Avatar/avatar.tsx +368 -0
- package/src/components/Badge/badge.tsx +104 -0
- package/src/components/Breadcrumb/breadcrumb.tsx +619 -0
- package/src/components/BulkActionBar/bulk-action-bar.tsx +156 -0
- package/src/components/Button/button-group.tsx +96 -0
- package/src/components/Button/button.tsx +539 -0
- package/src/components/Calendar/calendar.tsx +411 -0
- package/src/components/Carousel/carousel.tsx +371 -0
- package/src/components/Chart/chart.tsx +376 -0
- package/src/components/Checkbox/checkbox-group.tsx +94 -0
- package/src/components/Checkbox/checkbox.tsx +237 -0
- package/src/components/Chip/chip.tsx +359 -0
- package/src/components/CircularProgress/circular-progress.tsx +204 -0
- package/src/components/Coachmark/coachmark.tsx +255 -0
- package/src/components/Combobox/combobox.tsx +826 -0
- package/src/components/Command/command.tsx +187 -0
- package/src/components/DataTable/active-editor-controller.ts +72 -0
- package/src/components/DataTable/cell-registry.tsx +520 -0
- package/src/components/DataTable/column-types.ts +180 -0
- package/src/components/DataTable/data-table-column-visibility-panel.tsx +261 -0
- package/src/components/DataTable/data-table-filter-panel.tsx +813 -0
- package/src/components/DataTable/data-table-interaction-layer.tsx +483 -0
- package/src/components/DataTable/data-table-sort-manager.tsx +210 -0
- package/src/components/DataTable/data-table.css +165 -0
- package/src/components/DataTable/data-table.tsx +2924 -0
- package/src/components/DataTable/filter-operators.ts +225 -0
- package/src/components/DataTable/filter-tree.ts +313 -0
- package/src/components/DataTable/lib/column-meta.ts +79 -0
- package/src/components/DateGrid/date-grid.tsx +209 -0
- package/src/components/DatePicker/date-picker.tsx +1114 -0
- package/src/components/DescriptionList/description-list.tsx +141 -0
- package/src/components/Dialog/dialog.tsx +267 -0
- package/src/components/DropdownMenu/dropdown-menu.tsx +475 -0
- package/src/components/Empty/empty.tsx +108 -0
- package/src/components/Field/field-context.ts +136 -0
- package/src/components/Field/field-types.ts +52 -0
- package/src/components/Field/field-wrapper.tsx +348 -0
- package/src/components/Field/field.tsx +535 -0
- package/src/components/FieldControlGroup/field-control-group.tsx +136 -0
- package/src/components/FileItem/file-item.tsx +322 -0
- package/src/components/FileUpload/file-upload.tsx +326 -0
- package/src/components/FileViewer/file-viewer-types.ts +76 -0
- package/src/components/FileViewer/file-viewer.tsx +1065 -0
- package/src/components/FileViewer/image-renderer.tsx +256 -0
- package/src/components/HoverCard/hover-card.tsx +79 -0
- package/src/components/Input/input.tsx +233 -0
- package/src/components/LinkInput/link-input.tsx +304 -0
- package/src/components/Menu/menu-item.tsx +334 -0
- package/src/components/NameCard/name-card.tsx +319 -0
- package/src/components/Notice/notice.tsx +196 -0
- package/src/components/NumberInput/number-input.tsx +203 -0
- package/src/components/OverflowIndicator/overflow-indicator.tsx +156 -0
- package/src/components/PeoplePicker/avatar-stack-overflow.ts +100 -0
- package/src/components/PeoplePicker/people-picker-helpers.ts +76 -0
- package/src/components/PeoplePicker/people-picker.tsx +455 -0
- package/src/components/PeoplePicker/person-display.tsx +358 -0
- package/src/components/Popover/popover.tsx +183 -0
- package/src/components/ProgressBar/progress-bar.tsx +157 -0
- package/src/components/README.md +58 -0
- package/src/components/RadioGroup/radio-group.tsx +261 -0
- package/src/components/Rating/rating.tsx +295 -0
- package/src/components/ScrollArea/scroll-area.tsx +110 -0
- package/src/components/SegmentedControl/segmented-control.tsx +304 -0
- package/src/components/Select/select.tsx +658 -0
- package/src/components/SelectMenu/select-menu.tsx +430 -0
- package/src/components/SelectionControl/selection-item.tsx +261 -0
- package/src/components/Separator/separator.tsx +48 -0
- package/src/components/Sheet/sheet.tsx +240 -0
- package/src/components/Sidebar/sidebar.tsx +1280 -0
- package/src/components/Skeleton/skeleton.tsx +35 -0
- package/src/components/Slider/slider.tsx +158 -0
- package/src/components/Steps/steps.tsx +850 -0
- package/src/components/Switch/switch.tsx +285 -0
- package/src/components/Tabs/tabs.tsx +515 -0
- package/src/components/Tag/tag.tsx +246 -0
- package/src/components/Textarea/textarea.tsx +280 -0
- package/src/components/TimePicker/time-columns.tsx +260 -0
- package/src/components/TimePicker/time-picker.tsx +419 -0
- package/src/components/Toast/toast.tsx +129 -0
- package/src/components/Tooltip/tooltip.tsx +68 -0
- package/src/components/TreeView/tree-view.tsx +1031 -0
- package/src/hooks/use-controllable.ts +40 -0
- package/src/hooks/use-is-narrow-viewport.ts +19 -0
- package/src/hooks/use-is-touch-device.ts +21 -0
- package/src/hooks/use-overflow-items.ts +256 -0
- package/src/index.ts +85 -0
- package/src/lib/README.md +82 -0
- package/src/lib/drag-visual.ts +272 -0
- package/src/lib/i18n/README.md +60 -0
- package/src/lib/i18n/i18n-context.tsx +129 -0
- package/src/lib/multi-select-ordering.ts +61 -0
- package/src/lib/utils.ts +93 -0
- package/src/patterns/README.md +67 -0
- package/src/patterns/element-anatomy/item-anatomy.tsx +744 -0
- package/src/patterns/header-canonical/chrome-header.tsx +175 -0
- package/src/patterns/header-canonical/header-canonical.css +27 -0
- package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +217 -0
- package/src/patterns/overlay-surface/overlay-surface.tsx +191 -0
- package/src/patterns/resize-handle/resize-handle.tsx +188 -0
- package/src/stories-helpers/anatomy/anatomy-utils.tsx +64 -0
- package/src/styles/preset.css +31 -0
- package/src/styles/tokens.css +35 -0
- package/src/tokens/README.md +53 -0
- package/src/tokens/color/primitives.css +429 -0
- package/src/tokens/color/semantic.css +539 -0
- package/src/tokens/elevation/overlay-geometry.ts +13 -0
- package/src/tokens/layoutSpace/layoutSpace.css +36 -0
- package/src/tokens/motion/motion.css +30 -0
- package/src/tokens/motion/motion.ts +17 -0
- package/src/tokens/opacity/opacity.css +23 -0
- package/src/tokens/radius/radius.css +19 -0
- package/src/tokens/typography/typography.css +118 -0
- package/src/tokens/uiSize/icon-size.ts +52 -0
- package/src/tokens/uiSize/uiSize.css +125 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
|
|
2
|
+
// code-quality-allow: file-size — foundational composite(Button + iconOnly + danger + loading + asChild + dismiss + pressedTone)— 跨 7 axis variant 集中 SSOT 一處,拆分會 fragment cva variant catalog。當前 528 < cap 800。
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Slot } from '@radix-ui/react-slot'
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
6
|
+
import { CircularProgress } from '@/design-system/components/CircularProgress/circular-progress'
|
|
7
|
+
import type { LucideIcon } from 'lucide-react'
|
|
8
|
+
import { cn } from '@/lib/utils'
|
|
9
|
+
import { useFieldContext } from '@/design-system/components/Field/field-context'
|
|
10
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '@/design-system/components/Tooltip/tooltip'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Button — shadcn 風格,橋接設計系統 token
|
|
14
|
+
*
|
|
15
|
+
* ── Variants ──
|
|
16
|
+
* primary 主要操作,藍底白字
|
|
17
|
+
* secondary 次要品牌操作,藍框藍字;正面 vs 負面並存時用於正面那個
|
|
18
|
+
* tertiary 一般輔助操作,灰框灰字,hover 轉藍(最常用的非主要按鈕)
|
|
19
|
+
* text 無底色無邊框,hover 顯示灰底(工具列、密集 UI)
|
|
20
|
+
* link 外觀像連結的按鈕(本質仍是 button)
|
|
21
|
+
*
|
|
22
|
+
* ── danger prop ──
|
|
23
|
+
* danger 套用在任何 variant 上,將顏色改為危險色(紅色)
|
|
24
|
+
*
|
|
25
|
+
* <Button variant="primary" danger>永久刪除</Button> → 紅底白字(立即不可逆)
|
|
26
|
+
* <Button variant="secondary" danger>移至垃圾桶</Button> → 紅框紅字(點下去還可反悔)
|
|
27
|
+
*
|
|
28
|
+
* ── pressed prop(toggle)──
|
|
29
|
+
* pressed Toggle 按下狀態(持續 on/off),寫入 aria-pressed + data-state
|
|
30
|
+
* 僅 secondary / tertiary / text 三個 variant 支援 toggle 視覺:
|
|
31
|
+
* - secondary + pressed → primary-subtle 底、primary 字、透明邊框
|
|
32
|
+
* - tertiary + pressed → primary-subtle 底、primary 字、透明邊框(同 secondary 按下視覺)
|
|
33
|
+
* - text + pressed → neutral-selected 底,hover 反向變淺,:active 深一階
|
|
34
|
+
* primary / link 傳入 pressed 無視覺效果(語意不符)
|
|
35
|
+
*
|
|
36
|
+
* ── Sizes(預設 md)──
|
|
37
|
+
* xs h-field-xs(24px 固定),不隨 density 縮放
|
|
38
|
+
* sm h-field-sm,md=28px / lg=32px
|
|
39
|
+
* md h-field-md,md=32px / lg=36px ← 預設(跟 Field/Input 對齊)
|
|
40
|
+
* lg h-field-lg,md=36px / lg=40px
|
|
41
|
+
* icon-only 不是獨立尺寸 — 加 iconOnly prop 讓任何尺寸變正方形
|
|
42
|
+
*
|
|
43
|
+
* ── 內部結構 ──
|
|
44
|
+
* [startIcon?] [label] [badge? + endIcon?]
|
|
45
|
+
*
|
|
46
|
+
* ── 用法範例 ──
|
|
47
|
+
* <Button startIcon={Plus}>新增</Button>
|
|
48
|
+
* <Button variant="tertiary">取消</Button>
|
|
49
|
+
* <Button variant="primary" danger>永久刪除</Button>
|
|
50
|
+
* <Button variant="text" pressed={isPinned} startIcon={Pin} aria-label="釘選" iconOnly />
|
|
51
|
+
* <Button badge={<Badge count={3} />} endIcon={ChevronDown}>通知</Button>
|
|
52
|
+
* <Button size="sm" iconOnly startIcon={Plus} aria-label="新增" />
|
|
53
|
+
* <Button iconOnly startIcon={Bell} aria-label="通知 (3 則)"
|
|
54
|
+
* overlayBadge={<Badge count={3} />} /> ← badge 自動貼 icon 右上角
|
|
55
|
+
*
|
|
56
|
+
* ── asChild ──
|
|
57
|
+
* <Button asChild><Link to="/home">回首頁</Link></Button>
|
|
58
|
+
*/
|
|
59
|
+
const buttonVariants = cva(
|
|
60
|
+
[
|
|
61
|
+
'inline-flex items-center justify-center',
|
|
62
|
+
'whitespace-nowrap font-medium',
|
|
63
|
+
'border border-transparent',
|
|
64
|
+
'transition-colors duration-150',
|
|
65
|
+
'cursor-pointer select-none disabled:cursor-not-allowed aria-disabled:cursor-not-allowed',
|
|
66
|
+
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',
|
|
67
|
+
// 2026-05-12 Round 4.5 fix(codex M31 Layer C 抓):`aria-disabled` visual 分支補(per WAI-ARIA APG —
|
|
68
|
+
// aria-disabled 給語意 + visual,但不 suppress functionality;functionality 由 consumer 阻 e.g.
|
|
69
|
+
// RowDragHandle listeners 只在 canDrag spread)。**故意不加** `aria-disabled:pointer-events-none`
|
|
70
|
+
// — Round 4 RowDragHandle Tooltip flicker fix root cause:aria-disabled buttons 必保 pointer events
|
|
71
|
+
// 讓 Radix Tooltip pointerenter 通過。HTML `disabled` 保 PE:none(完全 inactive)。
|
|
72
|
+
'disabled:pointer-events-none',
|
|
73
|
+
// 2026-05-12 fix v2(playwright pixel-quantified verify 抓 opacity=1 不生效):
|
|
74
|
+
// `opacity-disabled` 是 custom Tailwind v4 `@utility`(opacity.css:21),variant prefix
|
|
75
|
+
// `aria-disabled:` 跟 custom @utility 不 compose(`aria-disabled:cursor-not-allowed` 標準
|
|
76
|
+
// utility 能 work,custom 不行)。改 arbitrary value `opacity-[var(--opacity-disabled)]`
|
|
77
|
+
// 繞 custom @utility 限制(Tailwind v4 arbitrary value 直接生 `opacity: var(--opacity-disabled)`)。
|
|
78
|
+
'aria-disabled:opacity-[var(--opacity-disabled)]',
|
|
79
|
+
'rounded-md',
|
|
80
|
+
// Defensive:SVG 不被 flex shrink 擠扁(防 inner-area 計算誤差導致 icon 被擠成
|
|
81
|
+
// width<intrinsic 的 asymmetric 顯示)。詳 ICON_ONLY_PX 段 rationale。
|
|
82
|
+
'[&_svg]:shrink-0',
|
|
83
|
+
],
|
|
84
|
+
{
|
|
85
|
+
variants: {
|
|
86
|
+
variant: {
|
|
87
|
+
primary: [
|
|
88
|
+
'bg-primary text-on-emphasis',
|
|
89
|
+
'hover:bg-primary-hover',
|
|
90
|
+
'active:bg-primary-active',
|
|
91
|
+
'disabled:bg-disabled disabled:text-fg-disabled disabled:border-transparent',
|
|
92
|
+
],
|
|
93
|
+
secondary: [
|
|
94
|
+
'bg-surface text-primary border-primary',
|
|
95
|
+
'hover:text-primary-hover hover:border-primary-hover',
|
|
96
|
+
'active:text-primary-active active:border-primary-active',
|
|
97
|
+
// Overlay trigger active(asChild Popover/DropdownMenu trigger)— 維持 hover 樣式
|
|
98
|
+
// (canonical 對齊 inline-action.spec.md:trigger 維持 host hover 直到 overlay 關閉)
|
|
99
|
+
'data-[state=open]:text-primary-hover data-[state=open]:border-primary-hover',
|
|
100
|
+
'disabled:bg-transparent disabled:text-fg-disabled disabled:border-border',
|
|
101
|
+
// 2026-05-21 v12:Toggle pressed 視覺移到 compoundVariants(variant × pressedTone),
|
|
102
|
+
// 同時支援 emphasis(藍底)/ neutral(灰底)兩 tone。詳 cva.compoundVariants 段。
|
|
103
|
+
],
|
|
104
|
+
tertiary: [
|
|
105
|
+
'bg-surface text-foreground border-border',
|
|
106
|
+
'hover:text-primary-hover hover:border-primary-hover',
|
|
107
|
+
'active:text-primary-active active:border-primary-active',
|
|
108
|
+
// Overlay trigger active — 維持 hover 樣式(同 secondary 邏輯)
|
|
109
|
+
'data-[state=open]:text-primary-hover data-[state=open]:border-primary-hover',
|
|
110
|
+
'disabled:bg-transparent disabled:text-fg-disabled disabled:border-border',
|
|
111
|
+
],
|
|
112
|
+
text: [
|
|
113
|
+
'bg-transparent text-foreground border-transparent',
|
|
114
|
+
'hover:bg-neutral-hover',
|
|
115
|
+
'active:bg-neutral-active',
|
|
116
|
+
// Overlay trigger active — 維持 hover 樣式(canonical 2026-05-02 改:hover token,
|
|
117
|
+
// 不另開 selected 4% — 對齊 shadcn/Radix/Material 狀態極簡派,跨 host 一致)
|
|
118
|
+
'data-[state=open]:bg-neutral-hover',
|
|
119
|
+
'disabled:bg-transparent disabled:text-fg-disabled',
|
|
120
|
+
],
|
|
121
|
+
link: [
|
|
122
|
+
'bg-transparent text-primary border-transparent',
|
|
123
|
+
'hover:text-primary-hover',
|
|
124
|
+
'active:text-primary-active',
|
|
125
|
+
'disabled:text-fg-disabled',
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
danger: {
|
|
129
|
+
true: '', // 實際樣式由 compoundVariants 提供
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* 2026-05-21 v12 — pressed visual tone(per user「我認同這一個方向,然後預設emphasis」):
|
|
133
|
+
* emphasis = 淡藍底(toolbar functional toggle / 篩選啟用 / 面板開關 — Figma toolbar /
|
|
134
|
+
* Linear toolbar / Material ToggleButton 共識)
|
|
135
|
+
* neutral = 灰底(sidebar/contextual nav row pressed — Linear / Notion / VS Code Activity Bar 共識)
|
|
136
|
+
* 預設 `emphasis` per user directive。實際樣式由 compoundVariants(variant × pressedTone)套用。
|
|
137
|
+
* 只在 secondary / tertiary / text variant 觸發 toggle 視覺;primary / link 無視覺效果。
|
|
138
|
+
*/
|
|
139
|
+
pressedTone: {
|
|
140
|
+
emphasis: '',
|
|
141
|
+
neutral: '',
|
|
142
|
+
},
|
|
143
|
+
size: {
|
|
144
|
+
xs: 'h-field-xs px-2 text-caption leading-compact gap-0',
|
|
145
|
+
sm: 'h-field-sm px-3 min-w-14 text-body leading-compact gap-1',
|
|
146
|
+
md: 'h-field-md px-3 min-w-16 text-body leading-compact gap-1',
|
|
147
|
+
lg: 'h-field-lg px-3 min-w-20 text-body-lg leading-compact gap-1',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
compoundVariants: [
|
|
151
|
+
// primary + danger → 紅底白字(立即不可逆操作)
|
|
152
|
+
{
|
|
153
|
+
variant: 'primary',
|
|
154
|
+
danger: true,
|
|
155
|
+
class: [
|
|
156
|
+
'bg-error text-on-emphasis border-transparent',
|
|
157
|
+
'hover:bg-error-hover',
|
|
158
|
+
'active:bg-error-active',
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
// secondary + danger → 紅框紅字(有確認步驟的危險操作)
|
|
162
|
+
{
|
|
163
|
+
variant: 'secondary',
|
|
164
|
+
danger: true,
|
|
165
|
+
class: [
|
|
166
|
+
'bg-surface text-error border-error',
|
|
167
|
+
'hover:text-error-hover hover:border-error-hover',
|
|
168
|
+
'active:text-error-active active:border-error-active',
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
// text + danger → 紅字,hover 灰底
|
|
172
|
+
{
|
|
173
|
+
variant: 'text',
|
|
174
|
+
danger: true,
|
|
175
|
+
class: [
|
|
176
|
+
'text-error',
|
|
177
|
+
'hover:bg-neutral-hover hover:text-error-hover',
|
|
178
|
+
'active:bg-neutral-active active:text-error-active',
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
// ── 2026-05-21 v12 Toggle pressed(variant × pressedTone)──────────────────
|
|
182
|
+
// 視覺由 data-[state=on] + aria-pressed(Radix overlay trigger fallback)觸發
|
|
183
|
+
//
|
|
184
|
+
// emphasis tone:藍底(primary-subtle / primary 字)— functional toggle
|
|
185
|
+
{
|
|
186
|
+
variant: ['secondary', 'tertiary', 'text'],
|
|
187
|
+
pressedTone: 'emphasis',
|
|
188
|
+
class: [
|
|
189
|
+
'data-[state=on]:bg-primary-subtle data-[state=on]:text-primary data-[state=on]:border-transparent',
|
|
190
|
+
'data-[state=on]:hover:text-primary-hover',
|
|
191
|
+
'data-[state=on]:active:text-primary-active',
|
|
192
|
+
'data-[state=on]:disabled:bg-disabled data-[state=on]:disabled:text-fg-disabled data-[state=on]:disabled:border-transparent',
|
|
193
|
+
// aria-pressed fallback(Radix overlay trigger override data-state 時仍生效)
|
|
194
|
+
'aria-pressed:bg-primary-subtle aria-pressed:text-primary aria-pressed:border-transparent',
|
|
195
|
+
'aria-pressed:hover:text-primary-hover',
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
// neutral tone:灰底(neutral-selected family)— sidebar/contextual nav pressed
|
|
199
|
+
{
|
|
200
|
+
variant: ['secondary', 'tertiary', 'text'],
|
|
201
|
+
pressedTone: 'neutral',
|
|
202
|
+
class: [
|
|
203
|
+
'data-[state=on]:bg-neutral-selected data-[state=on]:text-foreground data-[state=on]:border-transparent',
|
|
204
|
+
'data-[state=on]:hover:bg-neutral-selected-hover',
|
|
205
|
+
'data-[state=on]:active:bg-neutral-selected-active',
|
|
206
|
+
'data-[state=on]:disabled:bg-transparent data-[state=on]:disabled:text-fg-disabled',
|
|
207
|
+
// aria-pressed fallback
|
|
208
|
+
'aria-pressed:bg-neutral-selected aria-pressed:text-foreground aria-pressed:border-transparent',
|
|
209
|
+
'aria-pressed:hover:bg-neutral-selected-hover',
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
defaultVariants: {
|
|
214
|
+
variant: 'primary',
|
|
215
|
+
size: 'md',
|
|
216
|
+
pressedTone: 'emphasis',
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
// ── ButtonGroup Context ──────────────────────────────────────────────────────
|
|
222
|
+
// ButtonGroup provides this context; Button reads it for fullWidth injection.
|
|
223
|
+
// Context lives here (not in button-group.tsx) so there is no circular import.
|
|
224
|
+
interface ButtonGroupContextValue {
|
|
225
|
+
fullWidth?: boolean
|
|
226
|
+
}
|
|
227
|
+
const ButtonGroupContext = React.createContext<ButtonGroupContextValue>({})
|
|
228
|
+
|
|
229
|
+
type InternalVariant = VariantProps<typeof buttonVariants>['variant']
|
|
230
|
+
|
|
231
|
+
export interface ButtonProps
|
|
232
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
233
|
+
Omit<VariantProps<typeof buttonVariants>, 'variant' | 'danger'> {
|
|
234
|
+
/**
|
|
235
|
+
* 將樣式套用至子元件(e.g. React Router Link)。
|
|
236
|
+
*
|
|
237
|
+
* ⚠️ **icon-only + asChild 警告**:當 `iconOnly={true}` 且 `asChild={true}` 時,內建
|
|
238
|
+
* Tooltip wrapper 不啟動(Radix Slot 不接受多 child)。consumer 必須**自管 child 的 `aria-label`**
|
|
239
|
+
* 給 screen reader,並視需要自行包 `<Tooltip>`(對齊 Polaris / Radix asChild idiom)。
|
|
240
|
+
* Button 不會主動補 tooltip — 否則會破壞 Slot 單 child 規則。
|
|
241
|
+
*/
|
|
242
|
+
asChild?: boolean
|
|
243
|
+
/**
|
|
244
|
+
* 按鈕視覺強調等級。
|
|
245
|
+
* `destructive` / `ghost` 為 shadcn 內部 compat,請勿在應用程式碼中直接使用。
|
|
246
|
+
*/
|
|
247
|
+
variant?: 'primary' | 'secondary' | 'tertiary' | 'text' | 'link' | (string & {})
|
|
248
|
+
/** 套用危險色(紅色)。可與任何 variant 組合使用。 */
|
|
249
|
+
danger?: boolean
|
|
250
|
+
/**
|
|
251
|
+
* Toggle 按下狀態(持續 on/off)。設定時 Button 變為 toggle:
|
|
252
|
+
* - 自動寫入 `aria-pressed` + `data-state="on" | "off"`
|
|
253
|
+
* - 樣式由 variant × `pressedTone` 的 compoundVariants 套用
|
|
254
|
+
* - 僅 secondary / tertiary / text 有 toggle 視覺;primary / link 傳入無效果
|
|
255
|
+
*
|
|
256
|
+
* 不傳此 prop 時 Button 就是一般按鈕,不帶 aria-pressed。
|
|
257
|
+
*/
|
|
258
|
+
pressed?: boolean
|
|
259
|
+
/**
|
|
260
|
+
* Pressed 視覺色調(2026-05-21 v12 加):
|
|
261
|
+
* - `'emphasis'`(預設)→ 淡藍底 / primary 字(對齊 Figma toolbar / Linear toolbar /
|
|
262
|
+
* Material ToggleButton 共識 — toolbar functional toggle / 篩選啟用 / 面板開關)
|
|
263
|
+
* - `'neutral'` → 灰底 / foreground 字(對齊 Linear / Notion / VS Code Activity Bar
|
|
264
|
+
* 共識 — sidebar/contextual nav row pressed)
|
|
265
|
+
*
|
|
266
|
+
* 僅在 `pressed` 啟用且 variant ∈ {secondary, tertiary, text} 時生效。
|
|
267
|
+
* 跨 toggle context 維持單一 prop API,consumer 視語意選 tone 不另開 variant。
|
|
268
|
+
*/
|
|
269
|
+
pressedTone?: 'emphasis' | 'neutral'
|
|
270
|
+
/** 左側 icon(LucideIcon),最多一個,loading 時自動替換為 spinner */
|
|
271
|
+
startIcon?: LucideIcon
|
|
272
|
+
/** 右側 badge(ReactNode),通常傳入計數指示器 */
|
|
273
|
+
badge?: React.ReactNode
|
|
274
|
+
/**
|
|
275
|
+
* Overlay badge(iconOnly 專用)。接收 `<Badge>` 元素,Button 內部**自動定位在 startIcon 右上角**——
|
|
276
|
+
* badge 中心對齊 icon 的 top-right corner(Material BadgedBox / iOS App icon canonical),不是按鈕邊緣。
|
|
277
|
+
* 解決手刻 `relative + absolute -top-1 -right-1` 讓 badge 飄在按鈕 chrome 右上的問題。
|
|
278
|
+
*
|
|
279
|
+
* 世界級對照:Material BadgedBox、iOS App Icon、Ant Badge wrap icon,badge 相對於**視覺重心**(icon)。
|
|
280
|
+
* 只在 `iconOnly=true` 時生效;非 iconOnly 時應該用 inline `badge` prop 放 suffix 位置。
|
|
281
|
+
*/
|
|
282
|
+
overlayBadge?: React.ReactNode
|
|
283
|
+
/** 右側 icon(LucideIcon),放在 badge 右邊,通常用於 ChevronDown 等方向指示 */
|
|
284
|
+
endIcon?: LucideIcon
|
|
285
|
+
/** Icon-only 模式:移除 padding,變為正方形(必須同時設定 aria-label) */
|
|
286
|
+
iconOnly?: boolean
|
|
287
|
+
/**
|
|
288
|
+
* Dismiss 視覺類(X close only canonical)。專用於 **X(close)icon 的 dismiss 語意** —
|
|
289
|
+
* 「關閉 surface / 忽略訊息」。**不適用 Trash / Delete / Clear / Remove 等 destructive / clear 操作**。
|
|
290
|
+
*
|
|
291
|
+
* 自動套用:
|
|
292
|
+
* - `variant="text"`(強制 override 其他 variant)
|
|
293
|
+
* - `iconOnly=true`(強制)
|
|
294
|
+
* - Icon 色 override:`fg-muted` → hover `foreground`(跟 Inline Action dismiss 視覺一致)
|
|
295
|
+
*
|
|
296
|
+
* 典型 case:Dialog / Sheet / Popover / Alert / Toast / Coachmark 的 **chrome corner close X**
|
|
297
|
+
* (action group region — corner 可多 action,close 左側加 Separator + refresh / share 等)。
|
|
298
|
+
*
|
|
299
|
+
* 非 dismiss(**不套此 prop**):
|
|
300
|
+
* - Trash / Delete → destructive action,Button 用一般 variant 或 Inline Action(按 row size 判)
|
|
301
|
+
* - Clear → 欄位清空,用 Inline Action
|
|
302
|
+
* - Remove → collection 移除,用一般 Button / Inline Action
|
|
303
|
+
*
|
|
304
|
+
* 詳見 button.spec.md「Dismiss 視覺類」段 + patterns/element-anatomy/item-anatomy.spec.md
|
|
305
|
+
* 「Dismiss canonical — X close only」段。
|
|
306
|
+
*/
|
|
307
|
+
dismiss?: boolean
|
|
308
|
+
/** 載入中狀態:startIcon 替換為 spinner,自動 disabled;badge / endIcon 維持顯示以避免 layout shift */
|
|
309
|
+
loading?: boolean
|
|
310
|
+
/** 撐滿父容器寬度 */
|
|
311
|
+
fullWidth?: boolean
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Icon-only padding — calc `(field-height - icon-size) / 2` per size。
|
|
316
|
+
*
|
|
317
|
+
* 設計:startIcon 到左邊距離 = padding = `(height - icon) / 2`。
|
|
318
|
+
* 純 icon-only 時 width = 2*padding + icon = height → **自然正方形**,不需要 aspect-square。
|
|
319
|
+
* 有 suffix(badge / endIcon)時 width = 2*pad + icon + gap + suffix > height → **自然長方形**。
|
|
320
|
+
* StartIcon 到左邊距離始終不變,形狀自動適應內容。
|
|
321
|
+
*
|
|
322
|
+
* 用 CSS var 讓 density 切換時 padding 自動跟著算(field-height 會變)。
|
|
323
|
+
*/
|
|
324
|
+
// IconOnly 用 padding-free + aspect-square + flex-center 的 Polaris/Atlassian idiom
|
|
325
|
+
// (M17 SSOT 必可傳播 — 取代 4 個 size 的 magic-number 公式):
|
|
326
|
+
// - aspect-square 鎖 width=height(來自 h-field-X)
|
|
327
|
+
// - p-0 移除 px-3 (label 模式) override
|
|
328
|
+
// - flex justify-center items-center(base 已有)→ SVG 自動視覺置中
|
|
329
|
+
// 結果:0 magic number,0 公式,0 border-deduction,任何 size / icon size 都自然正方形。
|
|
330
|
+
// World-class 對照:Polaris + Atlassian iconOnly 走 padding-free 派(Material/Ant 走
|
|
331
|
+
// padding-based)。我們選 padding-free 因 SSOT 性更強(SegmentedControl / Tag dismiss
|
|
332
|
+
// 等 host 全可共用同 utility class,無需各自抄公式)。詳 button.spec.md「iconOnly 鐵律」。
|
|
333
|
+
const ICON_ONLY_BASE = 'aspect-square p-0 min-w-0 gap-0'
|
|
334
|
+
|
|
335
|
+
// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding
|
|
336
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
337
|
+
(
|
|
338
|
+
{
|
|
339
|
+
className,
|
|
340
|
+
variant: variantProp,
|
|
341
|
+
danger: dangerProp,
|
|
342
|
+
size,
|
|
343
|
+
asChild = false,
|
|
344
|
+
startIcon: StartIcon,
|
|
345
|
+
badge,
|
|
346
|
+
overlayBadge,
|
|
347
|
+
endIcon: EndIcon,
|
|
348
|
+
iconOnly = false,
|
|
349
|
+
dismiss = false,
|
|
350
|
+
loading = false,
|
|
351
|
+
fullWidth = false,
|
|
352
|
+
pressed,
|
|
353
|
+
children,
|
|
354
|
+
disabled,
|
|
355
|
+
...props
|
|
356
|
+
},
|
|
357
|
+
ref
|
|
358
|
+
) => {
|
|
359
|
+
// ── FieldContext:在 Field 內時自動讀 size,讓 Button 跟 Input 同高 ──
|
|
360
|
+
const fieldCtx = useFieldContext?.()
|
|
361
|
+
const resolvedSize = size ?? (fieldCtx?.size as typeof size) ?? 'md'
|
|
362
|
+
|
|
363
|
+
// ── Dismiss 視覺類 override(2026-04-22 cross-implementation dimming canonical) ──
|
|
364
|
+
// dismiss=true 強制:variant="text" + iconOnly=true + icon 色弱化(fg-muted → hover foreground)
|
|
365
|
+
// 跟 Inline Action dismiss 視覺一致。詳見 button.spec.md「Dismiss 視覺類」。
|
|
366
|
+
const resolvedIconOnly = iconOnly || dismiss
|
|
367
|
+
|
|
368
|
+
// ── Dev-mode warning:overlayBadge 只適用 iconOnly ──
|
|
369
|
+
// 有 label 的 Button 傳入 overlayBadge 會被忽略(只 render icon / 不渲染 overlay slot),
|
|
370
|
+
// 靜默忽略會讓 consumer 誤以為「傳了但位置錯」。Dev mode 印 warning 引導改用 `badge` prop
|
|
371
|
+
// (inline 位置,跟 label 並列)或改 `iconOnly`。Spec SSOT:badge.spec.md「Overlay 適用元件」。
|
|
372
|
+
if (process.env.NODE_ENV !== 'production' && overlayBadge && !iconOnly) {
|
|
373
|
+
// eslint-disable-next-line no-console
|
|
374
|
+
console.warn(
|
|
375
|
+
'[DS Button] `overlayBadge` 只適用於 `iconOnly` Button。有 label 的 Button 請改用 `badge` prop(inline 位置,跟 label 並列),或移除 label 改為 iconOnly。SSOT:badge.spec.md「Overlay 適用元件 canonical」節。'
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 2026-05-23 deep-audit Phase A.4 Decision 1(user verbatim「決策ㄧ照你建議做」):dev-warn `iconOnly + (endIcon|badge)` 並用。
|
|
380
|
+
// Spec SSOT:button.spec.md「iconOnly 嚴格定義為『只有一個 icon,正方形』,不可與 endIcon 或 badge 並用」。
|
|
381
|
+
// 例外:overlayBadge 跟 iconOnly 並用 canonical(L372 反向 warn 已 cover)。
|
|
382
|
+
// 不擋 image canonical「icon + 下拉指示 = 不加 iconOnly + startIcon + endIcon + aria-label」(那 case iconOnly=false 不 trigger)。
|
|
383
|
+
if (process.env.NODE_ENV !== 'production' && iconOnly && (EndIcon !== undefined || badge != null)) {
|
|
384
|
+
// eslint-disable-next-line no-console
|
|
385
|
+
console.warn(
|
|
386
|
+
'[DS Button] `iconOnly` 嚴格定義為「只有一個 icon,正方形」,不可與 `endIcon` 或 `badge` 並用。若需 icon + 下拉指示 → 不加 iconOnly + startIcon + endIcon + aria-label;若需 icon + 角標 → iconOnly + overlayBadge。SSOT:button.spec.md `iconOnly 的邊界` 節 + `badge.spec.md` Overlay 適用元件 canonical。'
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// shadcn compat:AlertDialog、Toast 等元件內部會傳入這些 alias,
|
|
391
|
+
// 在此靜默轉換,不暴露到型別或自動完成。
|
|
392
|
+
// dismiss=true 強制 variant=text(dismiss canonical);override 其他 variant 傳入。
|
|
393
|
+
const resolvedVariant: InternalVariant =
|
|
394
|
+
dismiss ? 'text' :
|
|
395
|
+
(variantProp as string) === 'destructive' ? 'primary' :
|
|
396
|
+
(variantProp as string) === 'ghost' ? 'text' :
|
|
397
|
+
(variantProp as InternalVariant) ?? 'primary'
|
|
398
|
+
|
|
399
|
+
const resolvedDanger = dangerProp || (variantProp as string) === 'destructive'
|
|
400
|
+
|
|
401
|
+
// ButtonGroup context:vertical group 自動注入 fullWidth
|
|
402
|
+
const groupCtx = React.useContext(ButtonGroupContext)
|
|
403
|
+
const resolvedFullWidth = fullWidth || !!groupCtx.fullWidth
|
|
404
|
+
|
|
405
|
+
const Comp = asChild ? Slot : 'button'
|
|
406
|
+
const iconSize = resolvedSize === 'lg' ? 20 : 16
|
|
407
|
+
|
|
408
|
+
// loading 行為:spinner 永遠在 prefix 位置
|
|
409
|
+
// 有 prefix icon → icon 換成 spinner(同位置,零 layout shift)
|
|
410
|
+
// 無 prefix icon → spinner 加在文字左邊(按鈕略微變寬,可接受)
|
|
411
|
+
const hasSuffix = badge != null || EndIcon !== undefined
|
|
412
|
+
|
|
413
|
+
// icon-only 自動 tooltip:從 props 提取 aria-label,同時保留在 DOM
|
|
414
|
+
const { 'aria-label': ariaLabel, ...restProps } = props
|
|
415
|
+
|
|
416
|
+
// Toggle 狀態:pressed 定義時自動寫入 aria-pressed + data-state。
|
|
417
|
+
// 未定義時不寫入任何 toggle 屬性(按鈕為一般 action button)。
|
|
418
|
+
// 樣式由 cva 的 data-[state=on] 分支套用——secondary/tertiary 走 primary-subtle,
|
|
419
|
+
// text 走 neutral-selected family;primary/link 不定義 on 分支,傳入無效果。
|
|
420
|
+
const toggleAttrs =
|
|
421
|
+
pressed === undefined
|
|
422
|
+
? {}
|
|
423
|
+
: { 'aria-pressed': pressed, 'data-state': pressed ? 'on' : 'off' }
|
|
424
|
+
|
|
425
|
+
// Chrome-unbounded marker(2026-04-22 v5 canonical):button 若無視覺邊界(text variant 或 dismiss),
|
|
426
|
+
// 標記 data-unbounded="true"。SurfaceHeader 透過 [&_[data-unbounded]]:my-[...] 套負 margin
|
|
427
|
+
// 讓 layout 佔位縮到 24(chrome-header-height 幾何)— button native size 與 touch target 不變。
|
|
428
|
+
// 詳 overlay-surface.spec.md「Chrome dismiss size canonical」
|
|
429
|
+
const unboundedAttr =
|
|
430
|
+
resolvedVariant === 'text' || dismiss ? { 'data-unbounded': 'true' } : {}
|
|
431
|
+
|
|
432
|
+
const buttonEl = (
|
|
433
|
+
<Comp
|
|
434
|
+
className={cn(
|
|
435
|
+
buttonVariants({ variant: resolvedVariant, danger: resolvedDanger, size: resolvedSize, className }),
|
|
436
|
+
// iconOnly 鐵律:padding-free + aspect-square + flex-center (Polaris idiom)
|
|
437
|
+
// 0 magic-number 0 公式自動正方形。詳 ICON_ONLY_BASE rationale。
|
|
438
|
+
resolvedIconOnly && ICON_ONLY_BASE,
|
|
439
|
+
// Dismiss 視覺弱化:override Button text variant 預設 foreground 為 fg-muted → hover foreground
|
|
440
|
+
// 跟 Inline Action dismiss 視覺一致(cross-implementation dimming canonical)
|
|
441
|
+
dismiss && 'text-fg-muted hover:text-foreground',
|
|
442
|
+
resolvedFullWidth && 'w-full',
|
|
443
|
+
)}
|
|
444
|
+
ref={ref}
|
|
445
|
+
type="button"
|
|
446
|
+
disabled={disabled || loading}
|
|
447
|
+
aria-busy={loading || undefined}
|
|
448
|
+
aria-label={ariaLabel}
|
|
449
|
+
{...toggleAttrs}
|
|
450
|
+
{...unboundedAttr}
|
|
451
|
+
{...restProps}
|
|
452
|
+
>
|
|
453
|
+
{loading ? (
|
|
454
|
+
<CircularProgress size={iconSize} className="text-current" />
|
|
455
|
+
) : StartIcon ? (
|
|
456
|
+
resolvedIconOnly && overlayBadge ? (
|
|
457
|
+
// Overlay badge canonical:wrapper 貼 icon 尺寸,badge 中心對齊 icon top-right corner
|
|
458
|
+
// (Material BadgedBox / iOS App icon),不是 button chrome 角。
|
|
459
|
+
//
|
|
460
|
+
// CSS 細節(2026-04-20 bug fix):用 `inline-block` + 明確 width/height + `leading-none`
|
|
461
|
+
// 避免 `inline-flex` span 在 Button flex container 內被撐高/撐寬(inline-flex 的 span
|
|
462
|
+
// 在某些瀏覽器下會把絕對定位子元素的 translate 計算基準搞錯,造成 badge 噴飛、Button
|
|
463
|
+
// aspect-square 失效)。明確給 span width/height = iconSize 鎖住 positioning context。
|
|
464
|
+
<span
|
|
465
|
+
className="relative inline-block leading-none shrink-0 pointer-events-none"
|
|
466
|
+
style={{ width: iconSize, height: iconSize }}
|
|
467
|
+
>
|
|
468
|
+
<StartIcon size={iconSize} aria-hidden />
|
|
469
|
+
<span className="absolute top-0 right-0 translate-x-1/2 -translate-y-1/2 pointer-events-auto">
|
|
470
|
+
{overlayBadge}
|
|
471
|
+
</span>
|
|
472
|
+
</span>
|
|
473
|
+
) : (
|
|
474
|
+
<StartIcon size={iconSize} aria-hidden />
|
|
475
|
+
)
|
|
476
|
+
) : null}
|
|
477
|
+
{children != null && <span className="px-1">{children}</span>}
|
|
478
|
+
{hasSuffix && (
|
|
479
|
+
<span className="inline-flex items-center gap-1">
|
|
480
|
+
{badge}
|
|
481
|
+
{EndIcon && <EndIcon size={iconSize} aria-hidden />}
|
|
482
|
+
</span>
|
|
483
|
+
)}
|
|
484
|
+
</Comp>
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
// icon-only + aria-label → 自動包 Tooltip(tooltip 是元件保證的行為)
|
|
488
|
+
// 不建立獨立 TooltipProvider——依賴全域 Provider,
|
|
489
|
+
// 這樣所有 tooltip 共享同一組 delay 參數和 warm-up 機制
|
|
490
|
+
if (resolvedIconOnly && typeof ariaLabel === 'string' && !asChild) {
|
|
491
|
+
return (
|
|
492
|
+
<Tooltip>
|
|
493
|
+
<TooltipTrigger asChild>{buttonEl}</TooltipTrigger>
|
|
494
|
+
<TooltipContent>{ariaLabel}</TooltipContent>
|
|
495
|
+
</Tooltip>
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return buttonEl
|
|
500
|
+
}
|
|
501
|
+
)
|
|
502
|
+
Button.displayName = 'Button'
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* componentMeta — Story Auto-Compile 系統消費的結構化 canonical
|
|
506
|
+
* (見 .claude/planning/story-auto-compile.md Phase 1)
|
|
507
|
+
*
|
|
508
|
+
* compile-stories.mjs 讀本 export + spec.md frontmatter 產出
|
|
509
|
+
* anatomy.stories.tsx 的 variant/size/state/token 矩陣 canonical section。
|
|
510
|
+
*
|
|
511
|
+
* Keys 必跟 buttonVariants cva + spec frontmatter 對齊(compile-time 驗證)。
|
|
512
|
+
*/
|
|
513
|
+
export const buttonMeta = {
|
|
514
|
+
component: 'Button',
|
|
515
|
+
family: 3, // Pill Layout
|
|
516
|
+
variants: {
|
|
517
|
+
primary: { purpose: '主要 action / CTA' },
|
|
518
|
+
secondary: { purpose: '次要 action(陪襯 primary)' },
|
|
519
|
+
tertiary: { purpose: '第三級 action(tool-like)' },
|
|
520
|
+
text: { purpose: '文字樣式 action(low emphasis / toolbar)' },
|
|
521
|
+
link: { purpose: '內文連結(inline reading)' },
|
|
522
|
+
},
|
|
523
|
+
sizes: {
|
|
524
|
+
xs: { fieldHeight: 24, iconSize: 16, typography: 'body' },
|
|
525
|
+
sm: { fieldHeight: 28, iconSize: 16, typography: 'body' },
|
|
526
|
+
md: { fieldHeight: 32, iconSize: 16, typography: 'body' },
|
|
527
|
+
lg: { fieldHeight: 40, iconSize: 20, typography: 'body-lg' },
|
|
528
|
+
},
|
|
529
|
+
states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],
|
|
530
|
+
tokens: {
|
|
531
|
+
bg: ['--primary', '--primary-hover', '--primary-active', '--bg-disabled'],
|
|
532
|
+
fg: ['--on-emphasis', '--fg-disabled'],
|
|
533
|
+
ring: ['--ring'],
|
|
534
|
+
},
|
|
535
|
+
defaultVariant: 'primary',
|
|
536
|
+
defaultSize: 'md',
|
|
537
|
+
} as const
|
|
538
|
+
|
|
539
|
+
export { Button, buttonVariants, ButtonGroupContext }
|