@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,78 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
3
|
+
import { type VariantProps } from "class-variance-authority";
|
|
4
|
+
import type { FieldMode, FieldVariant } from "../../components/Field/field-types";
|
|
5
|
+
export interface RadioGroupProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
|
|
6
|
+
/**
|
|
7
|
+
* Field mode(2026-05-05 Phase B3 align):
|
|
8
|
+
* edit — 一般可互動 RadioGroup(預設)
|
|
9
|
+
* display — **純展示**:不渲染 Radix Root / 任何 radio 視覺,僅 child item 中
|
|
10
|
+
* value === group.value 那筆把 label 渲染為純文字 span;其他 item render null。
|
|
11
|
+
* 對齊 Carbon read-only / DataTable single-select cell read mode。
|
|
12
|
+
* readonly — 同 child item 各自 readOnly:radio 視覺保留 + 鎖互動
|
|
13
|
+
* disabled — 同 RadioGroupPrimitive.Root disabled 屬性
|
|
14
|
+
*/
|
|
15
|
+
mode?: FieldMode;
|
|
16
|
+
/**
|
|
17
|
+
* Visual chrome — RadioGroup 本體無 input wrapper variant,本 prop 對主體無視覺影響;
|
|
18
|
+
* 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。
|
|
19
|
+
*/
|
|
20
|
+
variant?: FieldVariant;
|
|
21
|
+
}
|
|
22
|
+
declare const RadioGroup: React.ForwardRefExoticComponent<RadioGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
23
|
+
declare const radioItemVariants: (props?: ({
|
|
24
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
25
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
26
|
+
type RadioItemPrimitiveProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>;
|
|
27
|
+
export interface RadioGroupItemProps extends RadioItemPrimitiveProps, VariantProps<typeof radioItemVariants> {
|
|
28
|
+
/**
|
|
29
|
+
* Inline label。提供時 RadioGroupItem 自動透過 SelectionItem 包裝,
|
|
30
|
+
* 套用 codified 樣式(text-body / text-foreground / disabled 色)。
|
|
31
|
+
* 在 <Field> context 內時此 prop 仍然生效(Radio 的 label 是每個 item
|
|
32
|
+
* 各自的,不是整組 Field 的;FieldLabel 是 RadioGroup 整體的 label)。
|
|
33
|
+
*/
|
|
34
|
+
label?: React.ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Inline description(secondary 文字)。須與 label 搭配使用。
|
|
37
|
+
* 套用 text-body / text-fg-secondary 樣式。
|
|
38
|
+
*/
|
|
39
|
+
description?: React.ReactNode;
|
|
40
|
+
/**
|
|
41
|
+
* readonly 模式:鎖定互動但維持 checked/unchecked 視覺正確。
|
|
42
|
+
* 通常整個 RadioGroup 一起設 readonly(由 parent RadioGroup 的 disabled
|
|
43
|
+
* 或 readonly 行為決定),個別 item 也可設。
|
|
44
|
+
*/
|
|
45
|
+
readOnly?: boolean;
|
|
46
|
+
}
|
|
47
|
+
declare const RadioGroupItem: React.ForwardRefExoticComponent<RadioGroupItemProps & React.RefAttributes<HTMLButtonElement>>;
|
|
48
|
+
export declare const radioGroupMeta: {
|
|
49
|
+
readonly component: "RadioGroup";
|
|
50
|
+
readonly family: 4;
|
|
51
|
+
readonly variants: {};
|
|
52
|
+
readonly sizes: {
|
|
53
|
+
readonly sm: {
|
|
54
|
+
readonly fieldHeight: 28;
|
|
55
|
+
readonly iconSize: 16;
|
|
56
|
+
readonly typography: "body";
|
|
57
|
+
};
|
|
58
|
+
readonly md: {
|
|
59
|
+
readonly fieldHeight: 32;
|
|
60
|
+
readonly iconSize: 16;
|
|
61
|
+
readonly typography: "body";
|
|
62
|
+
};
|
|
63
|
+
readonly lg: {
|
|
64
|
+
readonly fieldHeight: 40;
|
|
65
|
+
readonly iconSize: 20;
|
|
66
|
+
readonly typography: "body";
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
|
|
70
|
+
readonly tokens: {
|
|
71
|
+
readonly bg: readonly ["bg-disabled", "bg-surface"];
|
|
72
|
+
readonly fg: readonly ["text-fg-disabled", "text-fg-secondary", "text-foreground", "text-primary"];
|
|
73
|
+
readonly ring: readonly ["ring-ring"];
|
|
74
|
+
};
|
|
75
|
+
readonly defaultSize: "md";
|
|
76
|
+
};
|
|
77
|
+
export { RadioGroup, RadioGroupItem, radioItemVariants };
|
|
78
|
+
//# sourceMappingURL=radio-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/RadioGroup/radio-group.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,6BAA6B,CAAA;AAElE,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAoB3F,MAAM,WAAW,eACf,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC;IACvE;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,QAAA,MAAM,UAAU,wFAyCd,CAAA;AAUF,QAAA,MAAM,iBAAiB;;8EA2BtB,CAAA;AAOD,KAAK,uBAAuB,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;AAE9F,MAAM,WAAW,mBACf,SAAQ,uBAAuB,EAC7B,YAAY,CAAC,OAAO,iBAAiB,CAAC;IACxC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAID,QAAA,MAAM,cAAc,+FA6EnB,CAAA;AAKD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkBjB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
4
|
+
import { Circle } from "lucide-react";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { useFieldContext } from "../Field/field-context.js";
|
|
8
|
+
import { SelectionItem } from "../SelectionControl/selection-item.js";
|
|
9
|
+
import { EMPTY_DISPLAY } from "../Field/field-wrapper.js";
|
|
10
|
+
const RadioGroupDisplayContext = React.createContext(null);
|
|
11
|
+
const RadioGroup = React.forwardRef(({ className, mode, variant: _chrome, value, defaultValue, ...props }, ref) => {
|
|
12
|
+
if (mode === "display") {
|
|
13
|
+
const selectedValue = value ?? defaultValue;
|
|
14
|
+
if (!selectedValue) {
|
|
15
|
+
return /* @__PURE__ */ jsx("div", { role: "group", className: cn("grid", className), children: /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY }) });
|
|
16
|
+
}
|
|
17
|
+
let selectedLabel = null;
|
|
18
|
+
React.Children.forEach(props.children, (child) => {
|
|
19
|
+
if (!React.isValidElement(child)) return;
|
|
20
|
+
const cProps = child.props;
|
|
21
|
+
const control = cProps.control;
|
|
22
|
+
if (React.isValidElement(control)) {
|
|
23
|
+
const controlValue = control.props.value;
|
|
24
|
+
if (controlValue === selectedValue) {
|
|
25
|
+
selectedLabel = cProps.label ?? selectedValue;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return /* @__PURE__ */ jsx("div", { role: "group", className: cn("grid", className), children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: selectedLabel ?? selectedValue }) });
|
|
30
|
+
}
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
RadioGroupPrimitive.Root,
|
|
33
|
+
{
|
|
34
|
+
className: cn("grid", className),
|
|
35
|
+
value,
|
|
36
|
+
defaultValue,
|
|
37
|
+
...props,
|
|
38
|
+
ref
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
RadioGroup.displayName = "RadioGroup";
|
|
43
|
+
RadioGroup.fieldLayout = "block";
|
|
44
|
+
const radioItemVariants = cva(
|
|
45
|
+
[
|
|
46
|
+
"grid place-content-center shrink-0 rounded-full",
|
|
47
|
+
"border border-border bg-surface",
|
|
48
|
+
"transition-colors duration-150",
|
|
49
|
+
"hover:border-border-hover",
|
|
50
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
51
|
+
"data-[state=checked]:border-primary data-[state=checked]:text-primary",
|
|
52
|
+
"data-[state=checked]:hover:border-primary-hover data-[state=checked]:hover:text-primary-hover",
|
|
53
|
+
"disabled:cursor-not-allowed disabled:bg-disabled disabled:border-transparent disabled:hover:border-transparent",
|
|
54
|
+
"disabled:data-[state=checked]:bg-disabled disabled:data-[state=checked]:border-transparent disabled:data-[state=checked]:text-fg-disabled",
|
|
55
|
+
// readOnly:鎖定互動但維持 checked/unchecked 視覺
|
|
56
|
+
"data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default",
|
|
57
|
+
"data-[readonly=true]:hover:border-border"
|
|
58
|
+
],
|
|
59
|
+
{
|
|
60
|
+
variants: {
|
|
61
|
+
size: {
|
|
62
|
+
sm: "h-4 w-4",
|
|
63
|
+
md: "h-4 w-4",
|
|
64
|
+
lg: "h-5 w-5"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
defaultVariants: {
|
|
68
|
+
size: "md"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
const dotSize = { sm: 8, md: 8, lg: 10 };
|
|
73
|
+
const RadioGroupItem = React.forwardRef(
|
|
74
|
+
({
|
|
75
|
+
className,
|
|
76
|
+
size,
|
|
77
|
+
label,
|
|
78
|
+
description,
|
|
79
|
+
readOnly = false,
|
|
80
|
+
disabled,
|
|
81
|
+
id: idProp,
|
|
82
|
+
...props
|
|
83
|
+
}, ref) => {
|
|
84
|
+
const sizeKey = size ?? "md";
|
|
85
|
+
const dotPx = dotSize[sizeKey];
|
|
86
|
+
const displayCtx = React.useContext(RadioGroupDisplayContext);
|
|
87
|
+
if (displayCtx == null ? void 0 : displayCtx.displayMode) {
|
|
88
|
+
if (displayCtx.selectedValue !== props.value) return null;
|
|
89
|
+
return /* @__PURE__ */ jsx("span", { className: "text-foreground", children: label ?? props.value });
|
|
90
|
+
}
|
|
91
|
+
const fieldCtx = useFieldContext();
|
|
92
|
+
const generatedId = React.useId();
|
|
93
|
+
const inputId = idProp ?? generatedId;
|
|
94
|
+
const rootEl = /* @__PURE__ */ jsx(
|
|
95
|
+
RadioGroupPrimitive.Item,
|
|
96
|
+
{
|
|
97
|
+
id: inputId,
|
|
98
|
+
ref,
|
|
99
|
+
disabled,
|
|
100
|
+
"aria-readonly": readOnly || void 0,
|
|
101
|
+
"data-readonly": readOnly || void 0,
|
|
102
|
+
tabIndex: readOnly ? -1 : void 0,
|
|
103
|
+
className: cn(radioItemVariants({ size }), className),
|
|
104
|
+
...props,
|
|
105
|
+
children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "grid place-content-center", children: /* @__PURE__ */ jsx(
|
|
106
|
+
Circle,
|
|
107
|
+
{
|
|
108
|
+
style: { width: dotPx, height: dotPx },
|
|
109
|
+
className: "fill-current text-current"
|
|
110
|
+
}
|
|
111
|
+
) })
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
if (label == null) return rootEl;
|
|
115
|
+
const resolvedDisabled = disabled ?? (fieldCtx == null ? void 0 : fieldCtx.disabled) ?? false;
|
|
116
|
+
return /* @__PURE__ */ jsx(
|
|
117
|
+
SelectionItem,
|
|
118
|
+
{
|
|
119
|
+
control: rootEl,
|
|
120
|
+
label,
|
|
121
|
+
description,
|
|
122
|
+
htmlFor: inputId,
|
|
123
|
+
disabled: resolvedDisabled,
|
|
124
|
+
size: sizeKey
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
RadioGroupItem.displayName = "RadioGroupItem";
|
|
130
|
+
const radioGroupMeta = {
|
|
131
|
+
component: "RadioGroup",
|
|
132
|
+
family: 4,
|
|
133
|
+
variants: {},
|
|
134
|
+
sizes: {
|
|
135
|
+
sm: { fieldHeight: 28, iconSize: 16, typography: "body" },
|
|
136
|
+
md: { fieldHeight: 32, iconSize: 16, typography: "body" },
|
|
137
|
+
lg: { fieldHeight: 40, iconSize: 20, typography: "body" }
|
|
138
|
+
},
|
|
139
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
140
|
+
tokens: {
|
|
141
|
+
bg: ["bg-disabled", "bg-surface"],
|
|
142
|
+
fg: ["text-fg-disabled", "text-fg-secondary", "text-foreground", "text-primary"],
|
|
143
|
+
ring: ["ring-ring"]
|
|
144
|
+
},
|
|
145
|
+
defaultSize: "md"
|
|
146
|
+
};
|
|
147
|
+
export {
|
|
148
|
+
RadioGroup,
|
|
149
|
+
RadioGroupItem,
|
|
150
|
+
radioGroupMeta,
|
|
151
|
+
radioItemVariants
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=radio-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"radio-group.js","sources":["../../../src/components/RadioGroup/radio-group.tsx"],"sourcesContent":["// @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.\nimport * as React from \"react\"\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\"\nimport { Circle } from \"lucide-react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport type { FieldMode, FieldVariant } from \"@/design-system/components/Field/field-types\"\nimport { useFieldContext } from \"@/design-system/components/Field/field-context\"\nimport { SelectionItem } from \"@/design-system/components/SelectionControl/selection-item\"\nimport { EMPTY_DISPLAY } from \"@/design-system/components/Field/field-wrapper\"\n\n// ── RadioGroup display context ──────────────────────────────────────────────\n// RadioGroup mode='display' 時:Group 不渲染 Radix primitive(無 radio 視覺),\n// 改透過 Context 通知 child RadioGroupItem「我在 display mode、selected value 是 X」;\n// item 自決 — 命中 selected 渲染 label 純文字,未命中 render null。\n// 為什麼用 context(不是 RadioGroup 自己解析 children):children 可能是任意巢狀\n// (Field 包 RadioGroup,內含 RadioGroupItem 散在 fragment / 條件式內),強行 walk children\n// 會破壞 React composability;用 context 讓 item 自己判定是 idiom 對齊 Radix 原生模型。\ninterface RadioGroupDisplayContextValue {\n displayMode: true\n selectedValue?: string\n}\nconst RadioGroupDisplayContext = React.createContext<RadioGroupDisplayContextValue | null>(null)\n\n// ── RadioGroup ──────────────────────────────────────────────────────────────\n\nexport interface RadioGroupProps\n extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {\n /**\n * Field mode(2026-05-05 Phase B3 align):\n * edit — 一般可互動 RadioGroup(預設)\n * display — **純展示**:不渲染 Radix Root / 任何 radio 視覺,僅 child item 中\n * value === group.value 那筆把 label 渲染為純文字 span;其他 item render null。\n * 對齊 Carbon read-only / DataTable single-select cell read mode。\n * readonly — 同 child item 各自 readOnly:radio 視覺保留 + 鎖互動\n * disabled — 同 RadioGroupPrimitive.Root disabled 屬性\n */\n mode?: FieldMode\n /**\n * Visual chrome — RadioGroup 本體無 input wrapper variant,本 prop 對主體無視覺影響;\n * 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。\n */\n variant?: FieldVariant\n}\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n RadioGroupProps\n>(({ className, mode, variant: _chrome, value, defaultValue, ...props }, ref) => {\n // mode='display' — 純展示 selected option 的 label,不渲染任何 radio control 視覺。\n // 對齊 Carbon read-only single-select(只顯示 selected 內容)+ Airtable / Notion read-only。\n // 實作:walk children 找 control.value === selectedValue 的 SelectionItem,render label plain text。\n // (不用 context dispatch 給 RadioGroupItem — SelectionItem layout wrapper 仍會渲染所有 item label)\n if (mode === 'display') {\n const selectedValue = (value ?? defaultValue) as string | undefined\n if (!selectedValue) {\n return <div role=\"group\" className={cn('grid', className)}><span className=\"text-fg-muted\">{EMPTY_DISPLAY}</span></div>\n }\n let selectedLabel: React.ReactNode = null\n React.Children.forEach(props.children, (child) => {\n if (!React.isValidElement(child)) return\n const cProps = child.props as { control?: unknown; label?: React.ReactNode }\n const control = cProps.control\n if (React.isValidElement(control)) {\n const controlValue = (control.props as { value?: unknown }).value\n if (controlValue === selectedValue) {\n selectedLabel = cProps.label ?? selectedValue\n }\n }\n })\n return (\n <div role=\"group\" className={cn('grid', className)}>\n <span className=\"text-foreground\">{selectedLabel ?? selectedValue}</span>\n </div>\n )\n }\n\n return (\n <RadioGroupPrimitive.Root\n className={cn(\"grid\", className)}\n value={value}\n defaultValue={defaultValue}\n {...props}\n ref={ref}\n />\n )\n})\nRadioGroup.displayName = 'RadioGroup'\n// Field layout 宣告:RadioGroup 是 block primitive(多項堆疊),\n// 進入 <Field> 時 control area 自動切 items-start + padding-top 公式對齊。\n// Convention 詳見 components/Field/field.spec.md「Control area:Inline vs Block」段落。\n;(RadioGroup as unknown as { fieldLayout: 'block' }).fieldLayout = 'block'\n\n// ── RadioGroupItem Variants ─────────────────────────────────────────────────\n// 與 Checkbox 完全對齊:sm/md=16px, lg=20px。差異只有形狀(rounded-full)和指示器(filled dot)。\n\nconst radioItemVariants = cva(\n [\n 'grid place-content-center shrink-0 rounded-full',\n 'border border-border bg-surface',\n 'transition-colors duration-150',\n 'hover:border-border-hover',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'data-[state=checked]:border-primary data-[state=checked]:text-primary',\n 'data-[state=checked]:hover:border-primary-hover data-[state=checked]:hover:text-primary-hover',\n 'disabled:cursor-not-allowed disabled:bg-disabled disabled:border-transparent disabled:hover:border-transparent',\n 'disabled:data-[state=checked]:bg-disabled disabled:data-[state=checked]:border-transparent disabled:data-[state=checked]:text-fg-disabled',\n // readOnly:鎖定互動但維持 checked/unchecked 視覺\n 'data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default',\n 'data-[readonly=true]:hover:border-border',\n ],\n {\n variants: {\n size: {\n sm: 'h-4 w-4',\n md: 'h-4 w-4',\n lg: 'h-5 w-5',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n)\n\n// ── Dot Size ────────────────────────────────────────────────────────────────\nconst dotSize: Record<string, number> = { sm: 8, md: 8, lg: 10 }\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\ntype RadioItemPrimitiveProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n\nexport interface RadioGroupItemProps\n extends RadioItemPrimitiveProps,\n VariantProps<typeof radioItemVariants> {\n /**\n * Inline label。提供時 RadioGroupItem 自動透過 SelectionItem 包裝,\n * 套用 codified 樣式(text-body / text-foreground / disabled 色)。\n * 在 <Field> context 內時此 prop 仍然生效(Radio 的 label 是每個 item\n * 各自的,不是整組 Field 的;FieldLabel 是 RadioGroup 整體的 label)。\n */\n label?: React.ReactNode\n /**\n * Inline description(secondary 文字)。須與 label 搭配使用。\n * 套用 text-body / text-fg-secondary 樣式。\n */\n description?: React.ReactNode\n /**\n * readonly 模式:鎖定互動但維持 checked/unchecked 視覺正確。\n * 通常整個 RadioGroup 一起設 readonly(由 parent RadioGroup 的 disabled\n * 或 readonly 行為決定),個別 item 也可設。\n */\n readOnly?: boolean\n}\n\n// ── RadioGroupItem ──────────────────────────────────────────────────────────\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(\n (\n {\n className,\n size,\n label,\n description,\n readOnly = false,\n disabled,\n id: idProp,\n ...props\n },\n ref\n ) => {\n const sizeKey = size ?? 'md'\n const dotPx = dotSize[sizeKey]\n\n // ── RadioGroup mode='display' branch ──────────────────────────────────\n // 命中 selected → 渲染 label 純文字 span;未命中 → render null(group 內只剩 selected 的 label)。\n // 設計理由:對齊 Carbon read-only single-select 「只顯示 selected 內容、不列其他選項」原則。\n const displayCtx = React.useContext(RadioGroupDisplayContext)\n if (displayCtx?.displayMode) {\n if (displayCtx.selectedValue !== props.value) return null\n return <span className=\"text-foreground\">{label ?? props.value}</span>\n }\n\n // 注意:Radio 的 label 語意與 Checkbox/Switch 不同——\n // Checkbox/Switch 的 label 就是該 control 的唯一 label(被 Field context 接管),\n // RadioGroupItem 的 label 是「該選項」的 label(每 item 各自擁有),\n // FieldLabel 則是整個 RadioGroup 的 label。\n // 因此 RadioGroupItem 的 label 不因 Field context 被忽略。\n const fieldCtx = useFieldContext()\n\n const generatedId = React.useId()\n const inputId = idProp ?? generatedId\n\n const rootEl = (\n <RadioGroupPrimitive.Item\n id={inputId}\n ref={ref}\n disabled={disabled}\n aria-readonly={readOnly || undefined}\n data-readonly={readOnly || undefined}\n tabIndex={readOnly ? -1 : undefined}\n className={cn(radioItemVariants({ size }), className)}\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"grid place-content-center\">\n <Circle\n style={{ width: dotPx, height: dotPx }}\n className=\"fill-current text-current\"\n />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n\n // 無 label → 只渲染 radio 本體\n if (label == null) return rootEl\n\n // 有 label → 透過 SelectionItem 包裝,與 Checkbox 一致\n // 同時繼承 Field context 的 disabled(若 RadioGroup 在 Field disabled 內)\n const resolvedDisabled = disabled ?? fieldCtx?.disabled ?? false\n\n return (\n <SelectionItem\n control={rootEl}\n label={label}\n description={description}\n htmlFor={inputId}\n disabled={resolvedDisabled}\n size={sizeKey}\n />\n )\n }\n)\nRadioGroupItem.displayName = 'RadioGroupItem'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const radioGroupMeta = {\n component: 'RadioGroup',\n family: 4,\n variants: {\n\n },\n sizes: {\n sm: { fieldHeight: 28, iconSize: 16, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 16, typography: 'body' },\n lg: { fieldHeight: 40, iconSize: 20, typography: 'body' },\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-disabled', 'bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground', 'text-primary'],\n ring: ['ring-ring'],\n },\n defaultSize: 'md',\n} as const\n\nexport { RadioGroup, RadioGroupItem, radioItemVariants }\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type LucideIcon } from 'lucide-react';
|
|
3
|
+
export interface RatingProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
4
|
+
/** 當前評分(0 ~ max) */
|
|
5
|
+
value?: number;
|
|
6
|
+
/** 預設值(uncontrolled) */
|
|
7
|
+
defaultValue?: number;
|
|
8
|
+
/** 評分改變 callback */
|
|
9
|
+
onChange?: (value: number) => void;
|
|
10
|
+
/** 滿分(預設 5) */
|
|
11
|
+
max?: number;
|
|
12
|
+
/** 尺寸。standalone 建議 xs(24px);Field 內跟隨 Field size 傳 sm/md/lg */
|
|
13
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
14
|
+
/** 精度:full = 整星,half = 半星 */
|
|
15
|
+
precision?: 'full' | 'half';
|
|
16
|
+
/** 唯讀(無 hover / click 響應) */
|
|
17
|
+
readOnly?: boolean;
|
|
18
|
+
/** 完全停用 */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Loading 狀態 — 正在取得既有評分 / 正在儲存。
|
|
22
|
+
* 視覺同 disabled(composite 整塊 opacity-disabled)但 semantic 不同:
|
|
23
|
+
* loading = 暫時性等待(aria-busy),disabled = 永久業務規則(aria-disabled)。
|
|
24
|
+
* 詳 rating.spec.md「Interactive vs ReadOnly」+「Loading canonical」
|
|
25
|
+
*/
|
|
26
|
+
loading?: boolean;
|
|
27
|
+
/** 自訂 icon(預設 Star);傳 LucideIcon */
|
|
28
|
+
icon?: LucideIcon;
|
|
29
|
+
/** a11y label(readOnly 時必填,interactive 時建議填) */
|
|
30
|
+
'aria-label'?: string;
|
|
31
|
+
}
|
|
32
|
+
declare const Rating: React.ForwardRefExoticComponent<RatingProps & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
export declare const ratingMeta: {
|
|
34
|
+
readonly component: "Rating";
|
|
35
|
+
readonly family: 4;
|
|
36
|
+
readonly variants: {};
|
|
37
|
+
readonly sizes: {};
|
|
38
|
+
readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
|
|
39
|
+
readonly tokens: {
|
|
40
|
+
readonly bg: readonly ["bg-transparent"];
|
|
41
|
+
readonly fg: readonly [];
|
|
42
|
+
readonly ring: readonly ["ring-ring"];
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export { Rating };
|
|
46
|
+
//# sourceMappingURL=rating.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rating.d.ts","sourceRoot":"","sources":["../../../src/components/Rating/rating.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAsDpD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACzF,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,eAAe;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,gEAAgE;IAChE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAChC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW;IACX,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oCAAoC;IACpC,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAGD,QAAA,MAAM,MAAM,oFAkHX,CAAA;AA4ED,eAAO,MAAM,UAAU;;;;;;;;;;;CAeb,CAAA;AAEV,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Star } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { useFieldContext } from "../Field/field-context.js";
|
|
6
|
+
const SIZE_PX = { xs: 20, sm: 20, md: 24, lg: 24 };
|
|
7
|
+
const CONTAINER_HEIGHT = {
|
|
8
|
+
xs: "h-field-xs",
|
|
9
|
+
sm: "h-field-sm",
|
|
10
|
+
md: "h-field-md",
|
|
11
|
+
lg: "h-field-lg"
|
|
12
|
+
};
|
|
13
|
+
const Rating = React.forwardRef(
|
|
14
|
+
({
|
|
15
|
+
value,
|
|
16
|
+
defaultValue = 0,
|
|
17
|
+
onChange,
|
|
18
|
+
max = 5,
|
|
19
|
+
size: sizeProp,
|
|
20
|
+
precision = "full",
|
|
21
|
+
readOnly = false,
|
|
22
|
+
disabled = false,
|
|
23
|
+
loading = false,
|
|
24
|
+
icon: Icon = Star,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}, ref) => {
|
|
28
|
+
const fieldCtx = useFieldContext();
|
|
29
|
+
const fieldSize = fieldCtx == null ? void 0 : fieldCtx.size;
|
|
30
|
+
const size = sizeProp ?? fieldSize ?? "xs";
|
|
31
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
32
|
+
const [hoverValue, setHoverValue] = React.useState(null);
|
|
33
|
+
const isControlled = value !== void 0;
|
|
34
|
+
const currentValue = isControlled ? value : internalValue;
|
|
35
|
+
const displayValue = hoverValue ?? currentValue;
|
|
36
|
+
const iconPx = SIZE_PX[size];
|
|
37
|
+
const isInteractive = !readOnly && !disabled && !loading;
|
|
38
|
+
const setValue = (v) => {
|
|
39
|
+
if (!isControlled) setInternalValue(v);
|
|
40
|
+
onChange == null ? void 0 : onChange(v);
|
|
41
|
+
};
|
|
42
|
+
const handleKeyDown = (e) => {
|
|
43
|
+
if (!isInteractive) return;
|
|
44
|
+
const step = precision === "half" ? 0.5 : 1;
|
|
45
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
setValue(Math.min(max, currentValue + step));
|
|
48
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
setValue(Math.max(0, currentValue - step));
|
|
51
|
+
} else if (e.key === "Home") {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
setValue(0);
|
|
54
|
+
} else if (e.key === "End") {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
setValue(max);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
return /* @__PURE__ */ jsx(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
ref,
|
|
63
|
+
role: isInteractive ? "slider" : "img",
|
|
64
|
+
"aria-valuenow": isInteractive ? currentValue : void 0,
|
|
65
|
+
"aria-valuemin": isInteractive ? 0 : void 0,
|
|
66
|
+
"aria-valuemax": isInteractive ? max : void 0,
|
|
67
|
+
"aria-valuetext": isInteractive ? `${currentValue} of ${max} stars` : void 0,
|
|
68
|
+
"aria-disabled": disabled || void 0,
|
|
69
|
+
"aria-readonly": isInteractive && readOnly ? true : void 0,
|
|
70
|
+
"aria-busy": loading || void 0,
|
|
71
|
+
tabIndex: isInteractive ? 0 : void 0,
|
|
72
|
+
onKeyDown: handleKeyDown,
|
|
73
|
+
onMouseLeave: () => setHoverValue(null),
|
|
74
|
+
className: cn(
|
|
75
|
+
"inline-flex items-center gap-1",
|
|
76
|
+
// Container 對齊 field-height family,讓 Rating 可與 Input/Select/Button 並排 row-align
|
|
77
|
+
CONTAINER_HEIGHT[size],
|
|
78
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-md",
|
|
79
|
+
// disabled 跟 loading 視覺相同(composite uniform dim),semantic 由 aria-disabled / aria-busy 區分
|
|
80
|
+
(disabled || loading) && "opacity-disabled pointer-events-none",
|
|
81
|
+
className
|
|
82
|
+
),
|
|
83
|
+
...props,
|
|
84
|
+
children: Array.from({ length: max }, (_, i) => {
|
|
85
|
+
const starValue = i + 1;
|
|
86
|
+
const fillRatio = Math.max(0, Math.min(1, displayValue - i));
|
|
87
|
+
const isHalf = precision === "half" && fillRatio > 0 && fillRatio < 1;
|
|
88
|
+
return /* @__PURE__ */ jsx(
|
|
89
|
+
StarIcon,
|
|
90
|
+
{
|
|
91
|
+
Icon,
|
|
92
|
+
sizePx: iconPx,
|
|
93
|
+
fillRatio,
|
|
94
|
+
isHalf,
|
|
95
|
+
interactive: isInteractive,
|
|
96
|
+
onHover: (halfFirst) => {
|
|
97
|
+
if (!isInteractive) return;
|
|
98
|
+
const v = precision === "half" && halfFirst ? starValue - 0.5 : starValue;
|
|
99
|
+
setHoverValue(v);
|
|
100
|
+
},
|
|
101
|
+
onClick: (halfFirst) => {
|
|
102
|
+
if (!isInteractive) return;
|
|
103
|
+
const v = precision === "half" && halfFirst ? starValue - 0.5 : starValue;
|
|
104
|
+
setValue(v);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
i
|
|
108
|
+
);
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
Rating.displayName = "Rating";
|
|
115
|
+
const FILL_FILLED = "var(--warning)";
|
|
116
|
+
const FILL_EMPTY = "var(--divider)";
|
|
117
|
+
function StarIcon({ Icon, sizePx, fillRatio, isHalf, interactive, onHover, onClick }) {
|
|
118
|
+
if (!isHalf) {
|
|
119
|
+
const fill = fillRatio >= 1 ? FILL_FILLED : FILL_EMPTY;
|
|
120
|
+
return /* @__PURE__ */ jsx(
|
|
121
|
+
"span",
|
|
122
|
+
{
|
|
123
|
+
role: "presentation",
|
|
124
|
+
onMouseEnter: interactive ? () => onHover(false) : void 0,
|
|
125
|
+
onClick: interactive ? () => onClick(false) : void 0,
|
|
126
|
+
className: cn(
|
|
127
|
+
"inline-flex",
|
|
128
|
+
interactive ? "cursor-pointer" : "cursor-default"
|
|
129
|
+
),
|
|
130
|
+
style: { color: fill },
|
|
131
|
+
"aria-hidden": true,
|
|
132
|
+
children: /* @__PURE__ */ jsx(Icon, { size: sizePx, fill, stroke: "none", className: "shrink-0" })
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", style: { width: sizePx, height: sizePx }, children: [
|
|
137
|
+
/* @__PURE__ */ jsx(Icon, { size: sizePx, fill: FILL_EMPTY, stroke: "none", className: "absolute inset-0", style: { color: FILL_EMPTY } }),
|
|
138
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 overflow-hidden", style: { width: sizePx * fillRatio }, children: /* @__PURE__ */ jsx(Icon, { size: sizePx, fill: FILL_FILLED, stroke: "none", style: { color: FILL_FILLED } }) }),
|
|
139
|
+
interactive && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
140
|
+
/* @__PURE__ */ jsx(
|
|
141
|
+
"span",
|
|
142
|
+
{
|
|
143
|
+
role: "presentation",
|
|
144
|
+
onMouseEnter: () => onHover(true),
|
|
145
|
+
onClick: () => onClick(true),
|
|
146
|
+
className: "absolute inset-y-0 left-0 w-1/2 cursor-pointer",
|
|
147
|
+
"aria-hidden": true
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
"span",
|
|
152
|
+
{
|
|
153
|
+
role: "presentation",
|
|
154
|
+
onMouseEnter: () => onHover(false),
|
|
155
|
+
onClick: () => onClick(false),
|
|
156
|
+
className: "absolute inset-y-0 right-0 w-1/2 cursor-pointer",
|
|
157
|
+
"aria-hidden": true
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
] })
|
|
161
|
+
] });
|
|
162
|
+
}
|
|
163
|
+
const ratingMeta = {
|
|
164
|
+
component: "Rating",
|
|
165
|
+
family: 4,
|
|
166
|
+
variants: {},
|
|
167
|
+
sizes: {},
|
|
168
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
169
|
+
tokens: {
|
|
170
|
+
bg: ["bg-transparent"],
|
|
171
|
+
fg: [],
|
|
172
|
+
ring: ["ring-ring"]
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
export {
|
|
176
|
+
Rating,
|
|
177
|
+
ratingMeta
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=rating.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rating.js","sources":["../../../src/components/Rating/rating.tsx"],"sourcesContent":["// @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.\nimport * as React from 'react'\nimport { Star, type LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { useFieldContext } from '@/design-system/components/Field/field-context'\n\n/**\n * Rating — 星星評分元件\n *\n * 世界級對照:Ant Design `<Rate>`、Material MUI `<Rating>`。\n * shadcn 核心沒有 Rating,本元件自建。\n *\n * ── 使用情境 ──\n * - review / feedback:商品評分 / 服務評分(可編輯 + 唯讀兩種)\n * - display:已提交評分的唯讀呈現(商品清單星等)\n *\n * ── 視覺 ──\n * 填色用 `var(--warning)`(yellow-6,世界級黃星 convention;與 warning 語意共用色相\n * 但語境不同,評分 = UX convention color 非 status)。\n * 空色用 `var(--color-neutral-4)`(灰色;與 disabled/empty 同級)。\n *\n * ── 互動 ──\n * interactive(預設):hover 預覽、click 設值、keyboard Left/Right 改值\n * readOnly:純顯示,不響應 hover / click\n *\n * ── 精度 ──\n * precision=\"full\"(預設) — 整星(1, 2, 3, 4, 5)\n * precision=\"half\" — 半星(0.5, 1, 1.5, 2, 2.5, ..., 5)\n */\n\n// ── Icon size canonical(2026-04-21 AR48 修正)──\n//\n// Rating 的「一顆星」視覺重量接近 **Avatar / identity icon**,不是純 inline icon。\n// 理由:\n// - 星星是 filled shape(解析整個 icon 是重量感的一部分),不像純 outline icon 靠 stroke\n// - Field 內 Rating 跟 Avatar / Tag 並排時視覺份量要對齊,否則 row height 一致但 icon 看起來比重量不對\n// - 世界級對照:Ant Rate in Form = 20px、Material MUI Rating fontSize=inherit 預設約 24、Airbnb 評分星 24px\n//\n// 因此 Field 內 Rating icon size 對齊 **item-anatomy inline Avatar sizes**:sm=20 / md=24 / lg=24。\n// 非 icon tier(16/16/20)——star 不是次要 affordance icon,它是主要資料視覺。\n//\n// Container 高度仍對齊 `--field-height-*`(sm=28 / md=32 / lg=36),讓 Rating 可與其他\n// field-height family 元件(Input / Select)並排時 row height 對齊。\n//\n// ── 使用情境 ──\n// - **Standalone**(獨立展示評分,如商品卡 / 評論)→ 預設 `xs`(container 24,icon 20,\n// 對齊 Avatar sm 20px;iOS HIG / Airbnb 商品卡星星 20-24px)\n// - **Field 內**(表單評分欄位)→ 跟 Field 尺寸對齊(sm=20 / md=24 / lg=24,default md)\nconst SIZE_PX = { xs: 20, sm: 20, md: 24, lg: 24 } as const\nconst CONTAINER_HEIGHT: Record<'xs' | 'sm' | 'md' | 'lg', string> = {\n xs: 'h-field-xs',\n sm: 'h-field-sm',\n md: 'h-field-md',\n lg: 'h-field-lg',\n}\n\nexport interface RatingProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** 當前評分(0 ~ max) */\n value?: number\n /** 預設值(uncontrolled) */\n defaultValue?: number\n /** 評分改變 callback */\n onChange?: (value: number) => void\n /** 滿分(預設 5) */\n max?: number\n /** 尺寸。standalone 建議 xs(24px);Field 內跟隨 Field size 傳 sm/md/lg */\n size?: 'xs' | 'sm' | 'md' | 'lg'\n /** 精度:full = 整星,half = 半星 */\n precision?: 'full' | 'half'\n /** 唯讀(無 hover / click 響應) */\n readOnly?: boolean\n /** 完全停用 */\n disabled?: boolean\n /**\n * Loading 狀態 — 正在取得既有評分 / 正在儲存。\n * 視覺同 disabled(composite 整塊 opacity-disabled)但 semantic 不同:\n * loading = 暫時性等待(aria-busy),disabled = 永久業務規則(aria-disabled)。\n * 詳 rating.spec.md「Interactive vs ReadOnly」+「Loading canonical」\n */\n loading?: boolean\n /** 自訂 icon(預設 Star);傳 LucideIcon */\n icon?: LucideIcon\n /** a11y label(readOnly 時必填,interactive 時建議填) */\n 'aria-label'?: string\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Rating = React.forwardRef<HTMLDivElement, RatingProps>(\n (\n {\n value,\n defaultValue = 0,\n onChange,\n max = 5,\n size: sizeProp,\n precision = 'full',\n readOnly = false,\n disabled = false,\n loading = false,\n icon: Icon = Star,\n className,\n ...props\n },\n ref,\n ) => {\n // Context-aware default size(AR31 canonical):\n // - Field 內(有 FieldContext.size) → 跟 Field size 對齊(sm / md / lg)\n // - Standalone(無 Field context) → default `xs`(24px,對齊 Avatar / Tag sm / iOS HIG standalone)\n // consumer 可傳 size 顯式 override。世界級對照:Material Rating standalone 24dp、\n // Ant Rate in Form 跟 Form.itemSize,standalone 24px。\n const fieldCtx = useFieldContext()\n const fieldSize = fieldCtx?.size as ('sm' | 'md' | 'lg' | undefined)\n const size: 'xs' | 'sm' | 'md' | 'lg' =\n sizeProp ?? fieldSize ?? 'xs'\n const [internalValue, setInternalValue] = React.useState(defaultValue)\n const [hoverValue, setHoverValue] = React.useState<number | null>(null)\n const isControlled = value !== undefined\n const currentValue = isControlled ? value : internalValue\n const displayValue = hoverValue ?? currentValue\n const iconPx = SIZE_PX[size]\n const isInteractive = !readOnly && !disabled && !loading\n\n const setValue = (v: number) => {\n if (!isControlled) setInternalValue(v)\n onChange?.(v)\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isInteractive) return\n const step = precision === 'half' ? 0.5 : 1\n // Full ARIA slider pattern(WAI-ARIA):Arrow / Home / End 支援 — D4 UX audit 2026-04-22\n if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {\n e.preventDefault()\n setValue(Math.min(max, currentValue + step))\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {\n e.preventDefault()\n setValue(Math.max(0, currentValue - step))\n } else if (e.key === 'Home') {\n e.preventDefault()\n setValue(0)\n } else if (e.key === 'End') {\n e.preventDefault()\n setValue(max)\n }\n }\n\n return (\n <div\n ref={ref}\n role={isInteractive ? 'slider' : 'img'}\n aria-valuenow={isInteractive ? currentValue : undefined}\n aria-valuemin={isInteractive ? 0 : undefined}\n aria-valuemax={isInteractive ? max : undefined}\n aria-valuetext={isInteractive ? `${currentValue} of ${max} stars` : undefined}\n aria-disabled={disabled || undefined}\n // a11y: aria-readonly 只允許於 slider role(非 img)— axe aria-allowed-attr 2026-04-25\n aria-readonly={isInteractive && readOnly ? true : undefined}\n aria-busy={loading || undefined}\n tabIndex={isInteractive ? 0 : undefined}\n onKeyDown={handleKeyDown}\n onMouseLeave={() => setHoverValue(null)}\n className={cn(\n 'inline-flex items-center gap-1',\n // Container 對齊 field-height family,讓 Rating 可與 Input/Select/Button 並排 row-align\n CONTAINER_HEIGHT[size],\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-md',\n // disabled 跟 loading 視覺相同(composite uniform dim),semantic 由 aria-disabled / aria-busy 區分\n (disabled || loading) && 'opacity-disabled pointer-events-none',\n className,\n )}\n {...props}\n >\n {Array.from({ length: max }, (_, i) => {\n const starValue = i + 1\n const fillRatio = Math.max(0, Math.min(1, displayValue - i)) // 0..1\n const isHalf = precision === 'half' && fillRatio > 0 && fillRatio < 1\n\n return (\n <StarIcon\n key={i}\n Icon={Icon}\n sizePx={iconPx}\n fillRatio={fillRatio}\n isHalf={isHalf}\n interactive={isInteractive}\n onHover={(halfFirst) => {\n if (!isInteractive) return\n const v = precision === 'half' && halfFirst ? starValue - 0.5 : starValue\n setHoverValue(v)\n }}\n onClick={(halfFirst) => {\n if (!isInteractive) return\n const v = precision === 'half' && halfFirst ? starValue - 0.5 : starValue\n setValue(v)\n }}\n />\n )\n })}\n </div>\n )\n },\n)\nRating.displayName = 'Rating'\n\n// ── StarIcon: 單顆星 + half-precision overlay ─────────────────────────────\n\ninterface StarIconProps {\n Icon: LucideIcon\n sizePx: number\n fillRatio: number // 0..1\n isHalf: boolean\n interactive: boolean\n onHover: (halfFirst: boolean) => void\n onClick: (halfFirst: boolean) => void\n}\n\nconst FILL_FILLED = 'var(--warning)' // yellow-6 — 黃星 convention\nconst FILL_EMPTY = 'var(--divider)' // 灰色空星(neutral-4 借 divider semantic alias,user 2026-05-09 拍板;對齊 Material rgba(0,0,0,0.26) muted-fill canonical)\n\nfunction StarIcon({ Icon, sizePx, fillRatio, isHalf, interactive, onHover, onClick }: StarIconProps) {\n // a11y(2026-04-25 axe nested-interactive fix):inner 點擊目標改 <span>(非 interactive\n // element),不會跟外層 role='slider' 形成 nested-interactive 違規。鍵盤控制統一在外層\n // slider 的 arrow keys,inner 只處理 mouse click 定位。Ant Rate / Material MUI 同模式。\n if (!isHalf) {\n // Full: 一整顆 fill(filled 或 empty)\n const fill = fillRatio >= 1 ? FILL_FILLED : FILL_EMPTY\n return (\n <span\n role=\"presentation\"\n onMouseEnter={interactive ? () => onHover(false) : undefined}\n onClick={interactive ? () => onClick(false) : undefined}\n className={cn(\n 'inline-flex',\n interactive ? 'cursor-pointer' : 'cursor-default',\n )}\n style={{ color: fill }}\n aria-hidden\n >\n {/* stroke=\"none\" 移除 Lucide Star 預設的 outline stroke(1.5px 黑線),\n 讓星星是純 fill-only 的 shape——fill 與 outline 同色視覺上仍有亮度差。\n 世界級對照:Ant Rate / Material MUI Rating 皆純 fill,無 outline stroke。*/}\n <Icon size={sizePx} fill={fill} stroke=\"none\" className=\"shrink-0\" />\n </span>\n )\n }\n\n // Half: 兩個重疊 icon,左半 filled / 右半 empty + 兩個 hover zone 切半星\n return (\n <span className=\"relative inline-flex\" style={{ width: sizePx, height: sizePx }}>\n <Icon size={sizePx} fill={FILL_EMPTY} stroke=\"none\" className=\"absolute inset-0\" style={{ color: FILL_EMPTY }} />\n <span className=\"absolute inset-0 overflow-hidden\" style={{ width: sizePx * fillRatio }}>\n <Icon size={sizePx} fill={FILL_FILLED} stroke=\"none\" style={{ color: FILL_FILLED }} />\n </span>\n {interactive && (\n <>\n <span\n role=\"presentation\"\n onMouseEnter={() => onHover(true)}\n onClick={() => onClick(true)}\n className=\"absolute inset-y-0 left-0 w-1/2 cursor-pointer\"\n aria-hidden\n />\n <span\n role=\"presentation\"\n onMouseEnter={() => onHover(false)}\n onClick={() => onClick(false)}\n className=\"absolute inset-y-0 right-0 w-1/2 cursor-pointer\"\n aria-hidden\n />\n </>\n )}\n </span>\n )\n}\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const ratingMeta = {\n component: 'Rating',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-transparent'],\n fg: [],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Rating }\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
|
3
|
+
/**
|
|
4
|
+
* ScrollArea — 自訂樣式的捲動區(Radix ScrollArea primitive 包裝)
|
|
5
|
+
*
|
|
6
|
+
* 世界級對照:shadcn `ScrollArea` / Ant Design scrollable 容器的 pattern。
|
|
7
|
+
*
|
|
8
|
+
* ── 為什麼需要 ScrollArea ──
|
|
9
|
+
* Native scrollbar 跨 OS 不一致:
|
|
10
|
+
* macOS: overlay(不吃寬度,預設隱藏,滾動時浮出)
|
|
11
|
+
* Windows / Linux: always-visible(永遠吃 ~15-17px 寬度)
|
|
12
|
+
*
|
|
13
|
+
* 結果:同一個 DataTable / Sheet / Dialog 內容在 macOS 看起來對齊,在 Windows
|
|
14
|
+
* 右側被吃 17px 跑版(「Left pinned + Row Actions」那張圖的問題)。
|
|
15
|
+
*
|
|
16
|
+
* ScrollArea 用 Radix 包裝自建 overlay 捲軸 → **跨 OS 一致不吃寬度**,
|
|
17
|
+
* 捲動時浮現(hover / scroll 自動顯示)。
|
|
18
|
+
*
|
|
19
|
+
* ── 何時用 ──
|
|
20
|
+
* - DataTable 橫向捲動(水平跑版最明顯場景)
|
|
21
|
+
* - Sheet / Dialog 垂直內容捲動(body 太長)
|
|
22
|
+
* - Sidebar nav 長列表
|
|
23
|
+
* - 任何「內容可能溢出容器」且「跨 OS 視覺必須一致」的場景
|
|
24
|
+
*
|
|
25
|
+
* ── 何時不用 ──
|
|
26
|
+
* - 全頁捲動(瀏覽器 document scroll,保持 native 即可;ScrollArea 是 sub-region)
|
|
27
|
+
* - 單行 truncate(用 text-overflow:ellipsis 就夠)
|
|
28
|
+
* - 極短內容(不會捲動 → 不需 wrapper)
|
|
29
|
+
*/
|
|
30
|
+
declare const ScrollArea: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
declare const ScrollBar: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
32
|
+
export declare const scrollAreaMeta: {
|
|
33
|
+
readonly component: "ScrollArea";
|
|
34
|
+
readonly family: null;
|
|
35
|
+
readonly variants: {};
|
|
36
|
+
readonly sizes: {};
|
|
37
|
+
readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
|
|
38
|
+
readonly tokens: {
|
|
39
|
+
readonly bg: readonly [];
|
|
40
|
+
readonly fg: readonly [];
|
|
41
|
+
readonly ring: readonly [];
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export { ScrollArea, ScrollBar };
|
|
45
|
+
//# sourceMappingURL=scroll-area.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-area.d.ts","sourceRoot":"","sources":["../../../src/components/ScrollArea/scroll-area.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,6BAA6B,CAAA;AAGlE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,QAAA,MAAM,UAAU,+JA2Bd,CAAA;AAGF,QAAA,MAAM,SAAS,wKAwBb,CAAA;AAKF,eAAO,MAAM,cAAc;;;;;;;;;;;CAejB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
6
|
+
ScrollAreaPrimitive.Root,
|
|
7
|
+
{
|
|
8
|
+
ref,
|
|
9
|
+
className: cn("relative flex flex-col overflow-hidden", className),
|
|
10
|
+
...props,
|
|
11
|
+
children: [
|
|
12
|
+
/* @__PURE__ */ jsx(
|
|
13
|
+
ScrollAreaPrimitive.Viewport,
|
|
14
|
+
{
|
|
15
|
+
tabIndex: 0,
|
|
16
|
+
className: "flex-1 min-h-0 w-full rounded-[inherit] focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-primary",
|
|
17
|
+
children
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
/* @__PURE__ */ jsx(ScrollBar, {}),
|
|
21
|
+
/* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
));
|
|
25
|
+
ScrollArea.displayName = "ScrollArea";
|
|
26
|
+
const ScrollBar = React.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
|
|
27
|
+
ScrollAreaPrimitive.ScrollAreaScrollbar,
|
|
28
|
+
{
|
|
29
|
+
ref,
|
|
30
|
+
orientation,
|
|
31
|
+
className: cn(
|
|
32
|
+
"flex touch-none select-none transition-colors",
|
|
33
|
+
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
|
|
34
|
+
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
|
35
|
+
className
|
|
36
|
+
),
|
|
37
|
+
...props,
|
|
38
|
+
children: /* @__PURE__ */ jsx(
|
|
39
|
+
ScrollAreaPrimitive.ScrollAreaThumb,
|
|
40
|
+
{
|
|
41
|
+
className: cn("relative flex-1 rounded-full bg-[var(--scrollbar-thumb)] hover:bg-[var(--scrollbar-thumb-hover)] transition-colors")
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
));
|
|
46
|
+
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
|
|
47
|
+
const scrollAreaMeta = {
|
|
48
|
+
component: "ScrollArea",
|
|
49
|
+
family: null,
|
|
50
|
+
// non-family composite / overlay / layout
|
|
51
|
+
variants: {},
|
|
52
|
+
sizes: {},
|
|
53
|
+
states: ["default", "hover", "active", "focus-visible", "disabled"],
|
|
54
|
+
tokens: {
|
|
55
|
+
bg: [],
|
|
56
|
+
fg: [],
|
|
57
|
+
ring: []
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
ScrollArea,
|
|
62
|
+
ScrollBar,
|
|
63
|
+
scrollAreaMeta
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=scroll-area.js.map
|