@dowel-ui/react 0.1.0
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/LICENSE +21 -0
- package/dist/blocks/admin-users/meta.js +27 -0
- package/dist/blocks/admin-users/meta.js.map +1 -0
- package/dist/blocks/ai-chat/meta.js +30 -0
- package/dist/blocks/ai-chat/meta.js.map +1 -0
- package/dist/blocks/dashboard/meta.js +23 -0
- package/dist/blocks/dashboard/meta.js.map +1 -0
- package/dist/blocks/forgot-password/meta.js +24 -0
- package/dist/blocks/forgot-password/meta.js.map +1 -0
- package/dist/blocks/login/meta.js +26 -0
- package/dist/blocks/login/meta.js.map +1 -0
- package/dist/blocks/pricing/meta.js +24 -0
- package/dist/blocks/pricing/meta.js.map +1 -0
- package/dist/blocks/settings/meta.js +29 -0
- package/dist/blocks/settings/meta.js.map +1 -0
- package/dist/blocks/signup/meta.js +25 -0
- package/dist/blocks/signup/meta.js.map +1 -0
- package/dist/components/accordion/accordion.d.ts +19 -0
- package/dist/components/accordion/accordion.d.ts.map +1 -0
- package/dist/components/accordion/accordion.js +58 -0
- package/dist/components/accordion/accordion.js.map +1 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +2 -0
- package/dist/components/accordion/meta.js +17 -0
- package/dist/components/accordion/meta.js.map +1 -0
- package/dist/components/activity-feed/activity-feed.d.ts +39 -0
- package/dist/components/activity-feed/activity-feed.d.ts.map +1 -0
- package/dist/components/activity-feed/activity-feed.js +77 -0
- package/dist/components/activity-feed/activity-feed.js.map +1 -0
- package/dist/components/activity-feed/index.d.ts +2 -0
- package/dist/components/activity-feed/index.js +2 -0
- package/dist/components/activity-feed/meta.js +17 -0
- package/dist/components/activity-feed/meta.js.map +1 -0
- package/dist/components/ai-agent-status/ai-agent-status.d.ts +30 -0
- package/dist/components/ai-agent-status/ai-agent-status.d.ts.map +1 -0
- package/dist/components/ai-agent-status/ai-agent-status.js +43 -0
- package/dist/components/ai-agent-status/ai-agent-status.js.map +1 -0
- package/dist/components/ai-agent-status/index.d.ts +2 -0
- package/dist/components/ai-agent-status/index.js +2 -0
- package/dist/components/ai-agent-status/meta.js +17 -0
- package/dist/components/ai-agent-status/meta.js.map +1 -0
- package/dist/components/ai-conversation/ai-conversation.d.ts +45 -0
- package/dist/components/ai-conversation/ai-conversation.d.ts.map +1 -0
- package/dist/components/ai-conversation/ai-conversation.js +138 -0
- package/dist/components/ai-conversation/ai-conversation.js.map +1 -0
- package/dist/components/ai-conversation/index.d.ts +2 -0
- package/dist/components/ai-conversation/index.js +2 -0
- package/dist/components/ai-conversation/meta.js +17 -0
- package/dist/components/ai-conversation/meta.js.map +1 -0
- package/dist/components/ai-message/ai-message.d.ts +56 -0
- package/dist/components/ai-message/ai-message.d.ts.map +1 -0
- package/dist/components/ai-message/ai-message.js +90 -0
- package/dist/components/ai-message/ai-message.js.map +1 -0
- package/dist/components/ai-message/index.d.ts +2 -0
- package/dist/components/ai-message/index.js +2 -0
- package/dist/components/ai-message/meta.js +17 -0
- package/dist/components/ai-message/meta.js.map +1 -0
- package/dist/components/ai-model-selector/ai-model-selector.d.ts +42 -0
- package/dist/components/ai-model-selector/ai-model-selector.d.ts.map +1 -0
- package/dist/components/ai-model-selector/ai-model-selector.js +48 -0
- package/dist/components/ai-model-selector/ai-model-selector.js.map +1 -0
- package/dist/components/ai-model-selector/index.d.ts +2 -0
- package/dist/components/ai-model-selector/index.js +2 -0
- package/dist/components/ai-model-selector/meta.js +17 -0
- package/dist/components/ai-model-selector/meta.js.map +1 -0
- package/dist/components/ai-prompt-input/ai-prompt-input.d.ts +61 -0
- package/dist/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -0
- package/dist/components/ai-prompt-input/ai-prompt-input.js +170 -0
- package/dist/components/ai-prompt-input/ai-prompt-input.js.map +1 -0
- package/dist/components/ai-prompt-input/index.d.ts +2 -0
- package/dist/components/ai-prompt-input/index.js +2 -0
- package/dist/components/ai-prompt-input/meta.js +17 -0
- package/dist/components/ai-prompt-input/meta.js.map +1 -0
- package/dist/components/ai-reasoning/ai-reasoning.d.ts +24 -0
- package/dist/components/ai-reasoning/ai-reasoning.d.ts.map +1 -0
- package/dist/components/ai-reasoning/ai-reasoning.js +64 -0
- package/dist/components/ai-reasoning/ai-reasoning.js.map +1 -0
- package/dist/components/ai-reasoning/index.d.ts +2 -0
- package/dist/components/ai-reasoning/index.js +2 -0
- package/dist/components/ai-reasoning/meta.js +17 -0
- package/dist/components/ai-reasoning/meta.js.map +1 -0
- package/dist/components/ai-response/ai-response.d.ts +36 -0
- package/dist/components/ai-response/ai-response.d.ts.map +1 -0
- package/dist/components/ai-response/ai-response.js +46 -0
- package/dist/components/ai-response/ai-response.js.map +1 -0
- package/dist/components/ai-response/index.d.ts +2 -0
- package/dist/components/ai-response/index.js +2 -0
- package/dist/components/ai-response/meta.js +17 -0
- package/dist/components/ai-response/meta.js.map +1 -0
- package/dist/components/ai-sources/ai-sources.d.ts +44 -0
- package/dist/components/ai-sources/ai-sources.d.ts.map +1 -0
- package/dist/components/ai-sources/ai-sources.js +112 -0
- package/dist/components/ai-sources/ai-sources.js.map +1 -0
- package/dist/components/ai-sources/index.d.ts +2 -0
- package/dist/components/ai-sources/index.js +2 -0
- package/dist/components/ai-sources/meta.js +17 -0
- package/dist/components/ai-sources/meta.js.map +1 -0
- package/dist/components/ai-token-usage/ai-token-usage.d.ts +34 -0
- package/dist/components/ai-token-usage/ai-token-usage.d.ts.map +1 -0
- package/dist/components/ai-token-usage/ai-token-usage.js +58 -0
- package/dist/components/ai-token-usage/ai-token-usage.js.map +1 -0
- package/dist/components/ai-token-usage/index.d.ts +2 -0
- package/dist/components/ai-token-usage/index.js +2 -0
- package/dist/components/ai-token-usage/meta.js +17 -0
- package/dist/components/ai-token-usage/meta.js.map +1 -0
- package/dist/components/ai-tool/ai-tool.d.ts +50 -0
- package/dist/components/ai-tool/ai-tool.d.ts.map +1 -0
- package/dist/components/ai-tool/ai-tool.js +129 -0
- package/dist/components/ai-tool/ai-tool.js.map +1 -0
- package/dist/components/ai-tool/index.d.ts +2 -0
- package/dist/components/ai-tool/index.js +2 -0
- package/dist/components/ai-tool/meta.js +17 -0
- package/dist/components/ai-tool/meta.js.map +1 -0
- package/dist/components/alert/alert.d.ts +32 -0
- package/dist/components/alert/alert.d.ts.map +1 -0
- package/dist/components/alert/alert.js +49 -0
- package/dist/components/alert/alert.js.map +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +2 -0
- package/dist/components/alert/meta.js +17 -0
- package/dist/components/alert/meta.js.map +1 -0
- package/dist/components/avatar/avatar.d.ts +23 -0
- package/dist/components/avatar/avatar.d.ts.map +1 -0
- package/dist/components/avatar/avatar.js +44 -0
- package/dist/components/avatar/avatar.js.map +1 -0
- package/dist/components/avatar/index.d.ts +2 -0
- package/dist/components/avatar/index.js +2 -0
- package/dist/components/avatar/meta.js +17 -0
- package/dist/components/avatar/meta.js.map +1 -0
- package/dist/components/badge/badge.d.ts +20 -0
- package/dist/components/badge/badge.d.ts.map +1 -0
- package/dist/components/badge/badge.js +47 -0
- package/dist/components/badge/badge.js.map +1 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +2 -0
- package/dist/components/badge/meta.js +17 -0
- package/dist/components/badge/meta.js.map +1 -0
- package/dist/components/button/button.d.ts +28 -0
- package/dist/components/button/button.d.ts.map +1 -0
- package/dist/components/button/button.js +77 -0
- package/dist/components/button/button.js.map +1 -0
- package/dist/components/button/index.d.ts +2 -0
- package/dist/components/button/index.js +2 -0
- package/dist/components/button/meta.js +17 -0
- package/dist/components/button/meta.js.map +1 -0
- package/dist/components/calendar/calendar.d.ts +16 -0
- package/dist/components/calendar/calendar.d.ts.map +1 -0
- package/dist/components/calendar/calendar.js +70 -0
- package/dist/components/calendar/calendar.js.map +1 -0
- package/dist/components/calendar/index.d.ts +2 -0
- package/dist/components/calendar/index.js +2 -0
- package/dist/components/calendar/meta.js +17 -0
- package/dist/components/calendar/meta.js.map +1 -0
- package/dist/components/card/card.d.ts +23 -0
- package/dist/components/card/card.d.ts.map +1 -0
- package/dist/components/card/card.js +53 -0
- package/dist/components/card/card.js.map +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +2 -0
- package/dist/components/card/meta.js +17 -0
- package/dist/components/card/meta.js.map +1 -0
- package/dist/components/checkbox/checkbox.d.ts +15 -0
- package/dist/components/checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox/checkbox.js +45 -0
- package/dist/components/checkbox/checkbox.js.map +1 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +2 -0
- package/dist/components/checkbox/meta.js +17 -0
- package/dist/components/checkbox/meta.js.map +1 -0
- package/dist/components/code-block/code-block.d.ts +46 -0
- package/dist/components/code-block/code-block.d.ts.map +1 -0
- package/dist/components/code-block/code-block.js +110 -0
- package/dist/components/code-block/code-block.js.map +1 -0
- package/dist/components/code-block/index.d.ts +2 -0
- package/dist/components/code-block/index.js +2 -0
- package/dist/components/code-block/meta.js +17 -0
- package/dist/components/code-block/meta.js.map +1 -0
- package/dist/components/combobox/combobox.d.ts +59 -0
- package/dist/components/combobox/combobox.d.ts.map +1 -0
- package/dist/components/combobox/combobox.js +346 -0
- package/dist/components/combobox/combobox.js.map +1 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +2 -0
- package/dist/components/combobox/meta.js +17 -0
- package/dist/components/combobox/meta.js.map +1 -0
- package/dist/components/command/command.d.ts +65 -0
- package/dist/components/command/command.d.ts.map +1 -0
- package/dist/components/command/command.js +330 -0
- package/dist/components/command/command.js.map +1 -0
- package/dist/components/command/index.d.ts +2 -0
- package/dist/components/command/index.js +2 -0
- package/dist/components/command/meta.js +17 -0
- package/dist/components/command/meta.js.map +1 -0
- package/dist/components/data-table/data-table.d.ts +91 -0
- package/dist/components/data-table/data-table.d.ts.map +1 -0
- package/dist/components/data-table/data-table.js +263 -0
- package/dist/components/data-table/data-table.js.map +1 -0
- package/dist/components/data-table/index.d.ts +2 -0
- package/dist/components/data-table/index.js +2 -0
- package/dist/components/data-table/meta.js +22 -0
- package/dist/components/data-table/meta.js.map +1 -0
- package/dist/components/date-picker/date-picker.d.ts +31 -0
- package/dist/components/date-picker/date-picker.d.ts.map +1 -0
- package/dist/components/date-picker/date-picker.js +123 -0
- package/dist/components/date-picker/date-picker.js.map +1 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +2 -0
- package/dist/components/date-picker/meta.js +21 -0
- package/dist/components/date-picker/meta.js.map +1 -0
- package/dist/components/dialog/dialog.d.ts +30 -0
- package/dist/components/dialog/dialog.d.ts.map +1 -0
- package/dist/components/dialog/dialog.js +79 -0
- package/dist/components/dialog/dialog.js.map +1 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/index.js +2 -0
- package/dist/components/dialog/meta.js +17 -0
- package/dist/components/dialog/meta.js.map +1 -0
- package/dist/components/drawer/drawer.d.ts +32 -0
- package/dist/components/drawer/drawer.d.ts.map +1 -0
- package/dist/components/drawer/drawer.js +153 -0
- package/dist/components/drawer/drawer.js.map +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +2 -0
- package/dist/components/drawer/meta.js +17 -0
- package/dist/components/drawer/meta.js.map +1 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +43 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -0
- package/dist/components/dropdown-menu/dropdown-menu.js +130 -0
- package/dist/components/dropdown-menu/dropdown-menu.js.map +1 -0
- package/dist/components/dropdown-menu/index.d.ts +2 -0
- package/dist/components/dropdown-menu/index.js +2 -0
- package/dist/components/dropdown-menu/meta.js +17 -0
- package/dist/components/dropdown-menu/meta.js.map +1 -0
- package/dist/components/empty-state/empty-state.d.ts +24 -0
- package/dist/components/empty-state/empty-state.d.ts.map +1 -0
- package/dist/components/empty-state/empty-state.js +73 -0
- package/dist/components/empty-state/empty-state.js.map +1 -0
- package/dist/components/empty-state/index.d.ts +2 -0
- package/dist/components/empty-state/index.js +2 -0
- package/dist/components/empty-state/meta.js +17 -0
- package/dist/components/empty-state/meta.js.map +1 -0
- package/dist/components/form/form.d.ts +43 -0
- package/dist/components/form/form.d.ts.map +1 -0
- package/dist/components/form/form.js +127 -0
- package/dist/components/form/form.js.map +1 -0
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.js +2 -0
- package/dist/components/form/meta.js +17 -0
- package/dist/components/form/meta.js.map +1 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/index.js +2 -0
- package/dist/components/input/input.d.ts +21 -0
- package/dist/components/input/input.d.ts.map +1 -0
- package/dist/components/input/input.js +34 -0
- package/dist/components/input/input.js.map +1 -0
- package/dist/components/input/meta.js +17 -0
- package/dist/components/input/meta.js.map +1 -0
- package/dist/components/label/index.d.ts +2 -0
- package/dist/components/label/index.js +2 -0
- package/dist/components/label/label.d.ts +14 -0
- package/dist/components/label/label.d.ts.map +1 -0
- package/dist/components/label/label.js +20 -0
- package/dist/components/label/label.js.map +1 -0
- package/dist/components/label/meta.js +17 -0
- package/dist/components/label/meta.js.map +1 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/index.js +2 -0
- package/dist/components/pagination/meta.js +17 -0
- package/dist/components/pagination/meta.js.map +1 -0
- package/dist/components/pagination/pagination.d.ts +33 -0
- package/dist/components/pagination/pagination.d.ts.map +1 -0
- package/dist/components/pagination/pagination.js +143 -0
- package/dist/components/pagination/pagination.js.map +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +2 -0
- package/dist/components/popover/meta.js +17 -0
- package/dist/components/popover/meta.js.map +1 -0
- package/dist/components/popover/popover.d.ts +24 -0
- package/dist/components/popover/popover.d.ts.map +1 -0
- package/dist/components/popover/popover.js +60 -0
- package/dist/components/popover/popover.js.map +1 -0
- package/dist/components/progress/index.d.ts +2 -0
- package/dist/components/progress/index.js +2 -0
- package/dist/components/progress/meta.js +17 -0
- package/dist/components/progress/meta.js.map +1 -0
- package/dist/components/progress/progress.d.ts +21 -0
- package/dist/components/progress/progress.d.ts.map +1 -0
- package/dist/components/progress/progress.js +55 -0
- package/dist/components/progress/progress.js.map +1 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +2 -0
- package/dist/components/radio-group/meta.js +17 -0
- package/dist/components/radio-group/meta.js.map +1 -0
- package/dist/components/radio-group/radio-group.d.ts +17 -0
- package/dist/components/radio-group/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group/radio-group.js +29 -0
- package/dist/components/radio-group/radio-group.js.map +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +2 -0
- package/dist/components/select/meta.js +17 -0
- package/dist/components/select/meta.js.map +1 -0
- package/dist/components/select/select.d.ts +37 -0
- package/dist/components/select/select.d.ts.map +1 -0
- package/dist/components/select/select.js +128 -0
- package/dist/components/select/select.js.map +1 -0
- package/dist/components/separator/index.d.ts +2 -0
- package/dist/components/separator/index.js +2 -0
- package/dist/components/separator/meta.js +17 -0
- package/dist/components/separator/meta.js.map +1 -0
- package/dist/components/separator/separator.d.ts +15 -0
- package/dist/components/separator/separator.d.ts.map +1 -0
- package/dist/components/separator/separator.js +23 -0
- package/dist/components/separator/separator.js.map +1 -0
- package/dist/components/sheet/index.d.ts +2 -0
- package/dist/components/sheet/index.js +2 -0
- package/dist/components/sheet/meta.js +17 -0
- package/dist/components/sheet/meta.js.map +1 -0
- package/dist/components/sheet/sheet.d.ts +31 -0
- package/dist/components/sheet/sheet.d.ts.map +1 -0
- package/dist/components/sheet/sheet.js +90 -0
- package/dist/components/sheet/sheet.js.map +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +2 -0
- package/dist/components/skeleton/meta.js +17 -0
- package/dist/components/skeleton/meta.js.map +1 -0
- package/dist/components/skeleton/skeleton.d.ts +20 -0
- package/dist/components/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton/skeleton.js +29 -0
- package/dist/components/skeleton/skeleton.js.map +1 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/index.js +2 -0
- package/dist/components/slider/meta.js +17 -0
- package/dist/components/slider/meta.js.map +1 -0
- package/dist/components/slider/slider.d.ts +29 -0
- package/dist/components/slider/slider.d.ts.map +1 -0
- package/dist/components/slider/slider.js +61 -0
- package/dist/components/slider/slider.js.map +1 -0
- package/dist/components/spinner/index.d.ts +2 -0
- package/dist/components/spinner/index.js +2 -0
- package/dist/components/spinner/meta.js +17 -0
- package/dist/components/spinner/meta.js.map +1 -0
- package/dist/components/spinner/spinner.d.ts +21 -0
- package/dist/components/spinner/spinner.d.ts.map +1 -0
- package/dist/components/spinner/spinner.js +45 -0
- package/dist/components/spinner/spinner.js.map +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +2 -0
- package/dist/components/switch/meta.js +17 -0
- package/dist/components/switch/meta.js.map +1 -0
- package/dist/components/switch/switch.d.ts +15 -0
- package/dist/components/switch/switch.d.ts.map +1 -0
- package/dist/components/switch/switch.js +21 -0
- package/dist/components/switch/switch.js.map +1 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +2 -0
- package/dist/components/table/meta.js +17 -0
- package/dist/components/table/meta.js.map +1 -0
- package/dist/components/table/table.d.ts +41 -0
- package/dist/components/table/table.d.ts.map +1 -0
- package/dist/components/table/table.js +78 -0
- package/dist/components/table/table.js.map +1 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/index.js +2 -0
- package/dist/components/tabs/meta.js +17 -0
- package/dist/components/tabs/meta.js.map +1 -0
- package/dist/components/tabs/tabs.d.ts +28 -0
- package/dist/components/tabs/tabs.d.ts.map +1 -0
- package/dist/components/tabs/tabs.js +58 -0
- package/dist/components/tabs/tabs.js.map +1 -0
- package/dist/components/toast/index.d.ts +3 -0
- package/dist/components/toast/index.js +3 -0
- package/dist/components/toast/meta.js +17 -0
- package/dist/components/toast/meta.js.map +1 -0
- package/dist/components/toast/toast-store.d.ts +84 -0
- package/dist/components/toast/toast-store.d.ts.map +1 -0
- package/dist/components/toast/toast-store.js +115 -0
- package/dist/components/toast/toast-store.js.map +1 -0
- package/dist/components/toast/toast.d.ts +39 -0
- package/dist/components/toast/toast.d.ts.map +1 -0
- package/dist/components/toast/toast.js +140 -0
- package/dist/components/toast/toast.js.map +1 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +2 -0
- package/dist/components/tooltip/meta.js +17 -0
- package/dist/components/tooltip/meta.js.map +1 -0
- package/dist/components/tooltip/tooltip.d.ts +24 -0
- package/dist/components/tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip/tooltip.js +38 -0
- package/dist/components/tooltip/tooltip.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.js +51 -0
- package/dist/lib/styles.d.ts +21 -0
- package/dist/lib/styles.d.ts.map +1 -0
- package/dist/lib/styles.js +22 -0
- package/dist/lib/styles.js.map +1 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +21 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/registry/blocks.d.ts +15 -0
- package/dist/registry/blocks.d.ts.map +1 -0
- package/dist/registry/blocks.js +32 -0
- package/dist/registry/blocks.js.map +1 -0
- package/dist/registry/components.d.ts +18 -0
- package/dist/registry/components.d.ts.map +1 -0
- package/dist/registry/components.js +112 -0
- package/dist/registry/components.js.map +1 -0
- package/dist/registry/schema.d.ts +44 -0
- package/dist/registry/schema.d.ts.map +1 -0
- package/dist/registry/schema.js +33 -0
- package/dist/registry/schema.js.map +1 -0
- package/package.json +74 -0
- package/src/blocks/admin-users/admin-users.stories.tsx +83 -0
- package/src/blocks/admin-users/admin-users.test.tsx +159 -0
- package/src/blocks/admin-users/admin-users.tsx +251 -0
- package/src/blocks/admin-users/index.ts +1 -0
- package/src/blocks/admin-users/meta.ts +27 -0
- package/src/blocks/ai-chat/ai-chat.stories.tsx +149 -0
- package/src/blocks/ai-chat/ai-chat.test.tsx +166 -0
- package/src/blocks/ai-chat/ai-chat.tsx +280 -0
- package/src/blocks/ai-chat/index.ts +7 -0
- package/src/blocks/ai-chat/meta.ts +32 -0
- package/src/blocks/dashboard/dashboard.stories.tsx +106 -0
- package/src/blocks/dashboard/dashboard.test.tsx +94 -0
- package/src/blocks/dashboard/dashboard.tsx +192 -0
- package/src/blocks/dashboard/index.ts +6 -0
- package/src/blocks/dashboard/meta.ts +18 -0
- package/src/blocks/forgot-password/forgot-password.stories.tsx +41 -0
- package/src/blocks/forgot-password/forgot-password.test.tsx +62 -0
- package/src/blocks/forgot-password/forgot-password.tsx +158 -0
- package/src/blocks/forgot-password/index.ts +1 -0
- package/src/blocks/forgot-password/meta.ts +18 -0
- package/src/blocks/login/index.ts +1 -0
- package/src/blocks/login/login.stories.tsx +46 -0
- package/src/blocks/login/login.test.tsx +100 -0
- package/src/blocks/login/login.tsx +178 -0
- package/src/blocks/login/meta.ts +18 -0
- package/src/blocks/pricing/index.ts +1 -0
- package/src/blocks/pricing/meta.ts +18 -0
- package/src/blocks/pricing/pricing.stories.tsx +62 -0
- package/src/blocks/pricing/pricing.test.tsx +101 -0
- package/src/blocks/pricing/pricing.tsx +176 -0
- package/src/blocks/settings/index.ts +6 -0
- package/src/blocks/settings/meta.ts +29 -0
- package/src/blocks/settings/settings.stories.tsx +94 -0
- package/src/blocks/settings/settings.test.tsx +167 -0
- package/src/blocks/settings/settings.tsx +317 -0
- package/src/blocks/signup/index.ts +1 -0
- package/src/blocks/signup/meta.ts +18 -0
- package/src/blocks/signup/signup.stories.tsx +27 -0
- package/src/blocks/signup/signup.test.tsx +97 -0
- package/src/blocks/signup/signup.tsx +240 -0
- package/src/components/accordion/accordion.stories.tsx +90 -0
- package/src/components/accordion/accordion.test.tsx +156 -0
- package/src/components/accordion/accordion.tsx +88 -0
- package/src/components/accordion/index.ts +9 -0
- package/src/components/accordion/meta.ts +16 -0
- package/src/components/activity-feed/activity-feed.stories.tsx +163 -0
- package/src/components/activity-feed/activity-feed.test.tsx +125 -0
- package/src/components/activity-feed/activity-feed.tsx +115 -0
- package/src/components/activity-feed/index.ts +12 -0
- package/src/components/activity-feed/meta.ts +17 -0
- package/src/components/ai-agent-status/ai-agent-status.stories.tsx +86 -0
- package/src/components/ai-agent-status/ai-agent-status.test.tsx +66 -0
- package/src/components/ai-agent-status/ai-agent-status.tsx +88 -0
- package/src/components/ai-agent-status/index.ts +6 -0
- package/src/components/ai-agent-status/meta.ts +17 -0
- package/src/components/ai-conversation/ai-conversation.stories.tsx +126 -0
- package/src/components/ai-conversation/ai-conversation.test.tsx +144 -0
- package/src/components/ai-conversation/ai-conversation.tsx +229 -0
- package/src/components/ai-conversation/index.ts +9 -0
- package/src/components/ai-conversation/meta.ts +20 -0
- package/src/components/ai-message/ai-message.stories.tsx +106 -0
- package/src/components/ai-message/ai-message.test.tsx +160 -0
- package/src/components/ai-message/ai-message.tsx +162 -0
- package/src/components/ai-message/index.ts +13 -0
- package/src/components/ai-message/meta.ts +17 -0
- package/src/components/ai-model-selector/ai-model-selector.stories.tsx +66 -0
- package/src/components/ai-model-selector/ai-model-selector.test.tsx +120 -0
- package/src/components/ai-model-selector/ai-model-selector.tsx +112 -0
- package/src/components/ai-model-selector/index.ts +1 -0
- package/src/components/ai-model-selector/meta.ts +17 -0
- package/src/components/ai-prompt-input/ai-prompt-input.stories.tsx +145 -0
- package/src/components/ai-prompt-input/ai-prompt-input.test.tsx +273 -0
- package/src/components/ai-prompt-input/ai-prompt-input.tsx +306 -0
- package/src/components/ai-prompt-input/index.ts +11 -0
- package/src/components/ai-prompt-input/meta.ts +18 -0
- package/src/components/ai-reasoning/ai-reasoning.stories.tsx +60 -0
- package/src/components/ai-reasoning/ai-reasoning.test.tsx +95 -0
- package/src/components/ai-reasoning/ai-reasoning.tsx +106 -0
- package/src/components/ai-reasoning/index.ts +7 -0
- package/src/components/ai-reasoning/meta.ts +17 -0
- package/src/components/ai-response/ai-response.stories.tsx +75 -0
- package/src/components/ai-response/ai-response.test.tsx +96 -0
- package/src/components/ai-response/ai-response.tsx +95 -0
- package/src/components/ai-response/index.ts +7 -0
- package/src/components/ai-response/meta.ts +17 -0
- package/src/components/ai-sources/ai-sources.stories.tsx +93 -0
- package/src/components/ai-sources/ai-sources.test.tsx +102 -0
- package/src/components/ai-sources/ai-sources.tsx +186 -0
- package/src/components/ai-sources/index.ts +11 -0
- package/src/components/ai-sources/meta.ts +17 -0
- package/src/components/ai-token-usage/ai-token-usage.stories.tsx +59 -0
- package/src/components/ai-token-usage/ai-token-usage.test.tsx +83 -0
- package/src/components/ai-token-usage/ai-token-usage.tsx +105 -0
- package/src/components/ai-token-usage/index.ts +6 -0
- package/src/components/ai-token-usage/meta.ts +16 -0
- package/src/components/ai-tool/ai-tool.stories.tsx +96 -0
- package/src/components/ai-tool/ai-tool.test.tsx +137 -0
- package/src/components/ai-tool/ai-tool.tsx +235 -0
- package/src/components/ai-tool/index.ts +13 -0
- package/src/components/ai-tool/meta.ts +17 -0
- package/src/components/alert/alert.stories.tsx +101 -0
- package/src/components/alert/alert.test.tsx +94 -0
- package/src/components/alert/alert.tsx +89 -0
- package/src/components/alert/index.ts +8 -0
- package/src/components/alert/meta.ts +16 -0
- package/src/components/avatar/avatar.stories.tsx +58 -0
- package/src/components/avatar/avatar.test.tsx +64 -0
- package/src/components/avatar/avatar.tsx +68 -0
- package/src/components/avatar/index.ts +9 -0
- package/src/components/avatar/meta.ts +15 -0
- package/src/components/badge/badge.stories.tsx +68 -0
- package/src/components/badge/badge.test.tsx +61 -0
- package/src/components/badge/badge.tsx +54 -0
- package/src/components/badge/index.ts +1 -0
- package/src/components/badge/meta.ts +15 -0
- package/src/components/button/button.stories.tsx +128 -0
- package/src/components/button/button.test.tsx +224 -0
- package/src/components/button/button.tsx +114 -0
- package/src/components/button/index.ts +1 -0
- package/src/components/button/meta.ts +16 -0
- package/src/components/calendar/calendar.stories.tsx +105 -0
- package/src/components/calendar/calendar.test.tsx +255 -0
- package/src/components/calendar/calendar.tsx +115 -0
- package/src/components/calendar/index.ts +1 -0
- package/src/components/calendar/meta.ts +17 -0
- package/src/components/card/card.stories.tsx +61 -0
- package/src/components/card/card.test.tsx +66 -0
- package/src/components/card/card.tsx +81 -0
- package/src/components/card/index.ts +9 -0
- package/src/components/card/meta.ts +16 -0
- package/src/components/checkbox/checkbox.stories.tsx +124 -0
- package/src/components/checkbox/checkbox.test.tsx +121 -0
- package/src/components/checkbox/checkbox.tsx +66 -0
- package/src/components/checkbox/index.ts +1 -0
- package/src/components/checkbox/meta.ts +16 -0
- package/src/components/code-block/code-block.stories.tsx +62 -0
- package/src/components/code-block/code-block.test.tsx +139 -0
- package/src/components/code-block/code-block.tsx +188 -0
- package/src/components/code-block/index.ts +1 -0
- package/src/components/code-block/meta.ts +17 -0
- package/src/components/combobox/combobox.stories.tsx +171 -0
- package/src/components/combobox/combobox.test.tsx +429 -0
- package/src/components/combobox/combobox.tsx +544 -0
- package/src/components/combobox/index.ts +15 -0
- package/src/components/combobox/meta.ts +17 -0
- package/src/components/command/command.stories.tsx +152 -0
- package/src/components/command/command.test.tsx +380 -0
- package/src/components/command/command.tsx +482 -0
- package/src/components/command/index.ts +17 -0
- package/src/components/command/meta.ts +18 -0
- package/src/components/data-table/data-table.stories.tsx +151 -0
- package/src/components/data-table/data-table.test.tsx +288 -0
- package/src/components/data-table/data-table.tsx +485 -0
- package/src/components/data-table/index.ts +13 -0
- package/src/components/data-table/meta.ts +19 -0
- package/src/components/date-picker/date-picker.stories.tsx +103 -0
- package/src/components/date-picker/date-picker.test.tsx +205 -0
- package/src/components/date-picker/date-picker.tsx +198 -0
- package/src/components/date-picker/index.ts +6 -0
- package/src/components/date-picker/meta.ts +18 -0
- package/src/components/dialog/dialog.stories.tsx +140 -0
- package/src/components/dialog/dialog.test.tsx +186 -0
- package/src/components/dialog/dialog.tsx +132 -0
- package/src/components/dialog/index.ts +16 -0
- package/src/components/dialog/meta.ts +16 -0
- package/src/components/drawer/drawer.stories.tsx +111 -0
- package/src/components/drawer/drawer.test.tsx +187 -0
- package/src/components/drawer/drawer.tsx +293 -0
- package/src/components/drawer/index.ts +16 -0
- package/src/components/drawer/meta.ts +16 -0
- package/src/components/dropdown-menu/dropdown-menu.stories.tsx +128 -0
- package/src/components/dropdown-menu/dropdown-menu.test.tsx +321 -0
- package/src/components/dropdown-menu/dropdown-menu.tsx +242 -0
- package/src/components/dropdown-menu/index.ts +21 -0
- package/src/components/dropdown-menu/meta.ts +17 -0
- package/src/components/empty-state/empty-state.stories.tsx +70 -0
- package/src/components/empty-state/empty-state.test.tsx +97 -0
- package/src/components/empty-state/empty-state.tsx +92 -0
- package/src/components/empty-state/index.ts +9 -0
- package/src/components/empty-state/meta.ts +16 -0
- package/src/components/form/form.stories.tsx +144 -0
- package/src/components/form/form.test.tsx +203 -0
- package/src/components/form/form.tsx +221 -0
- package/src/components/form/index.ts +13 -0
- package/src/components/form/meta.ts +17 -0
- package/src/components/input/index.ts +1 -0
- package/src/components/input/input.stories.tsx +84 -0
- package/src/components/input/input.test.tsx +108 -0
- package/src/components/input/input.tsx +51 -0
- package/src/components/input/meta.ts +15 -0
- package/src/components/label/index.ts +1 -0
- package/src/components/label/label.stories.tsx +51 -0
- package/src/components/label/label.test.tsx +55 -0
- package/src/components/label/label.tsx +26 -0
- package/src/components/label/meta.ts +15 -0
- package/src/components/pagination/index.ts +10 -0
- package/src/components/pagination/meta.ts +17 -0
- package/src/components/pagination/pagination.stories.tsx +129 -0
- package/src/components/pagination/pagination.test.tsx +119 -0
- package/src/components/pagination/pagination.tsx +142 -0
- package/src/components/popover/index.ts +9 -0
- package/src/components/popover/meta.ts +18 -0
- package/src/components/popover/popover.stories.tsx +84 -0
- package/src/components/popover/popover.test.tsx +163 -0
- package/src/components/popover/popover.tsx +89 -0
- package/src/components/progress/index.ts +1 -0
- package/src/components/progress/meta.ts +17 -0
- package/src/components/progress/progress.stories.tsx +90 -0
- package/src/components/progress/progress.test.tsx +78 -0
- package/src/components/progress/progress.tsx +70 -0
- package/src/components/radio-group/index.ts +6 -0
- package/src/components/radio-group/meta.ts +16 -0
- package/src/components/radio-group/radio-group.stories.tsx +102 -0
- package/src/components/radio-group/radio-group.test.tsx +152 -0
- package/src/components/radio-group/radio-group.tsx +53 -0
- package/src/components/select/index.ts +14 -0
- package/src/components/select/meta.ts +16 -0
- package/src/components/select/select.stories.tsx +137 -0
- package/src/components/select/select.test.tsx +209 -0
- package/src/components/select/select.tsx +222 -0
- package/src/components/separator/index.ts +1 -0
- package/src/components/separator/meta.ts +15 -0
- package/src/components/separator/separator.stories.tsx +42 -0
- package/src/components/separator/separator.test.tsx +46 -0
- package/src/components/separator/separator.tsx +33 -0
- package/src/components/sheet/index.ts +14 -0
- package/src/components/sheet/meta.ts +16 -0
- package/src/components/sheet/sheet.stories.tsx +107 -0
- package/src/components/sheet/sheet.test.tsx +152 -0
- package/src/components/sheet/sheet.tsx +160 -0
- package/src/components/skeleton/index.ts +1 -0
- package/src/components/skeleton/meta.ts +15 -0
- package/src/components/skeleton/skeleton.stories.tsx +46 -0
- package/src/components/skeleton/skeleton.test.tsx +57 -0
- package/src/components/skeleton/skeleton.tsx +28 -0
- package/src/components/slider/index.ts +1 -0
- package/src/components/slider/meta.ts +19 -0
- package/src/components/slider/slider.stories.tsx +87 -0
- package/src/components/slider/slider.test.tsx +148 -0
- package/src/components/slider/slider.tsx +135 -0
- package/src/components/spinner/index.ts +1 -0
- package/src/components/spinner/meta.ts +15 -0
- package/src/components/spinner/spinner.stories.tsx +47 -0
- package/src/components/spinner/spinner.test.tsx +41 -0
- package/src/components/spinner/spinner.tsx +68 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch/meta.ts +15 -0
- package/src/components/switch/switch.stories.tsx +70 -0
- package/src/components/switch/switch.test.tsx +101 -0
- package/src/components/switch/switch.tsx +42 -0
- package/src/components/table/index.ts +11 -0
- package/src/components/table/meta.ts +17 -0
- package/src/components/table/table.stories.tsx +131 -0
- package/src/components/table/table.test.tsx +153 -0
- package/src/components/table/table.tsx +138 -0
- package/src/components/tabs/index.ts +11 -0
- package/src/components/tabs/meta.ts +17 -0
- package/src/components/tabs/tabs.stories.tsx +139 -0
- package/src/components/tabs/tabs.test.tsx +148 -0
- package/src/components/tabs/tabs.tsx +106 -0
- package/src/components/toast/index.ts +24 -0
- package/src/components/toast/meta.ts +18 -0
- package/src/components/toast/toast-store.ts +181 -0
- package/src/components/toast/toast.stories.tsx +167 -0
- package/src/components/toast/toast.test.tsx +306 -0
- package/src/components/toast/toast.tsx +241 -0
- package/src/components/tooltip/index.ts +8 -0
- package/src/components/tooltip/meta.ts +17 -0
- package/src/components/tooltip/tooltip.stories.tsx +89 -0
- package/src/components/tooltip/tooltip.test.tsx +120 -0
- package/src/components/tooltip/tooltip.tsx +58 -0
- package/src/index.ts +50 -0
- package/src/lib/styles.ts +26 -0
- package/src/lib/utils.test.ts +32 -0
- package/src/lib/utils.ts +24 -0
- package/src/registry/blocks.ts +30 -0
- package/src/registry/components.ts +114 -0
- package/src/registry/meta.test.ts +234 -0
- package/src/registry/schema.ts +58 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineMeta } from "@/registry/schema";
|
|
2
|
+
|
|
3
|
+
export const meta = defineMeta({
|
|
4
|
+
name: "slider",
|
|
5
|
+
title: "Slider",
|
|
6
|
+
description: "Selects a value, or a range, from a continuous span.",
|
|
7
|
+
category: "form",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["radix-ui"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["slider.tsx"],
|
|
12
|
+
a11y:
|
|
13
|
+
'Each thumb is a role="slider" with arrow keys, Home/End and Page Up/Down. The name is ' +
|
|
14
|
+
"forwarded onto the thumbs, since the root has no role — a range slider should name each " +
|
|
15
|
+
"thumb separately with thumbLabels. A development-only warning fires if a thumb would be " +
|
|
16
|
+
"unnamed. Pass aria-valuetext when the raw number is not meaningful on its own " +
|
|
17
|
+
"(a price, a duration). Show the current value on screen too — a slider is imprecise, so " +
|
|
18
|
+
"pair it with a numeric input when exactness matters.",
|
|
19
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Decorator, Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
import { Label } from "@/components/label";
|
|
5
|
+
|
|
6
|
+
import { Slider } from "./slider";
|
|
7
|
+
|
|
8
|
+
/** Named so its type is nameable in declaration output (TS2883). */
|
|
9
|
+
const withFixedWidth: Decorator = (Story) => (
|
|
10
|
+
<div className="w-72">
|
|
11
|
+
<Story />
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const meta = {
|
|
16
|
+
title: "Forms/Slider",
|
|
17
|
+
component: Slider,
|
|
18
|
+
args: { defaultValue: [40], min: 0, max: 100, step: 1, "aria-label": "Volume" },
|
|
19
|
+
argTypes: {
|
|
20
|
+
step: { control: { type: "number", min: 1, max: 25 } },
|
|
21
|
+
disabled: { control: "boolean" },
|
|
22
|
+
},
|
|
23
|
+
decorators: [withFixedWidth],
|
|
24
|
+
} satisfies Meta<typeof Slider>;
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof meta>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {};
|
|
30
|
+
|
|
31
|
+
/** A slider is imprecise; showing the value makes it usable. */
|
|
32
|
+
export const WithValue: Story = {
|
|
33
|
+
parameters: { controls: { disable: true } },
|
|
34
|
+
render: function WithValue() {
|
|
35
|
+
const [value, setValue] = useState([40]);
|
|
36
|
+
return (
|
|
37
|
+
<div className="grid gap-3">
|
|
38
|
+
<div className="flex items-center justify-between">
|
|
39
|
+
<Label htmlFor="quality">Quality</Label>
|
|
40
|
+
<span className="text-sm text-muted-foreground tabular-nums">{value[0]}%</span>
|
|
41
|
+
</div>
|
|
42
|
+
<Slider id="quality" aria-label="Quality" value={value} onValueChange={setValue} />
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Each thumb is its own slider control, so each one gets its own name. */
|
|
49
|
+
export const Range: Story = {
|
|
50
|
+
parameters: { controls: { disable: true } },
|
|
51
|
+
render: function Range() {
|
|
52
|
+
const [range, setRange] = useState([20, 80]);
|
|
53
|
+
return (
|
|
54
|
+
<div className="grid gap-3">
|
|
55
|
+
<div className="flex items-center justify-between">
|
|
56
|
+
<Label>Price range</Label>
|
|
57
|
+
<span className="text-sm text-muted-foreground tabular-nums">
|
|
58
|
+
${range[0]} – ${range[1]}
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
<Slider
|
|
62
|
+
value={range}
|
|
63
|
+
onValueChange={setRange}
|
|
64
|
+
thumbLabels={["Minimum price", "Maximum price"]}
|
|
65
|
+
thumbValueTexts={[`$${String(range[0])}`, `$${String(range[1])}`]}
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const Steps: Story = {
|
|
73
|
+
args: { defaultValue: [50], step: 10 },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const Disabled: Story = {
|
|
77
|
+
args: { disabled: true },
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Vertical: Story = {
|
|
81
|
+
parameters: { controls: { disable: true } },
|
|
82
|
+
render: () => (
|
|
83
|
+
<div className="flex h-44 justify-center">
|
|
84
|
+
<Slider orientation="vertical" defaultValue={[60]} aria-label="Volume" />
|
|
85
|
+
</div>
|
|
86
|
+
),
|
|
87
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { expectNoA11yViolations } from "../../../test/a11y";
|
|
7
|
+
import { Slider } from "./slider";
|
|
8
|
+
|
|
9
|
+
describe("Slider", () => {
|
|
10
|
+
it("renders a single thumb by default", () => {
|
|
11
|
+
render(<Slider aria-label="Volume" />);
|
|
12
|
+
expect(screen.getAllByRole("slider")).toHaveLength(1);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("renders one thumb per value", () => {
|
|
16
|
+
render(<Slider aria-label="Price range" defaultValue={[20, 80]} />);
|
|
17
|
+
expect(screen.getAllByRole("slider")).toHaveLength(2);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("exposes its value and bounds", () => {
|
|
21
|
+
render(<Slider aria-label="Volume" defaultValue={[40]} min={0} max={100} />);
|
|
22
|
+
|
|
23
|
+
const thumb = screen.getByRole("slider");
|
|
24
|
+
expect(thumb).toHaveAttribute("aria-valuenow", "40");
|
|
25
|
+
expect(thumb).toHaveAttribute("aria-valuemin", "0");
|
|
26
|
+
expect(thumb).toHaveAttribute("aria-valuemax", "100");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("increments with the arrow keys", async () => {
|
|
30
|
+
const user = userEvent.setup();
|
|
31
|
+
render(<Slider aria-label="Volume" defaultValue={[40]} />);
|
|
32
|
+
|
|
33
|
+
await user.tab();
|
|
34
|
+
const thumb = screen.getByRole("slider");
|
|
35
|
+
expect(thumb).toHaveFocus();
|
|
36
|
+
|
|
37
|
+
await user.keyboard("{ArrowRight}");
|
|
38
|
+
expect(thumb).toHaveAttribute("aria-valuenow", "41");
|
|
39
|
+
|
|
40
|
+
await user.keyboard("{ArrowLeft}");
|
|
41
|
+
expect(thumb).toHaveAttribute("aria-valuenow", "40");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("jumps to the bounds with Home and End", async () => {
|
|
45
|
+
const user = userEvent.setup();
|
|
46
|
+
render(<Slider aria-label="Volume" defaultValue={[40]} min={10} max={90} />);
|
|
47
|
+
|
|
48
|
+
await user.tab();
|
|
49
|
+
await user.keyboard("{Home}");
|
|
50
|
+
expect(screen.getByRole("slider")).toHaveAttribute("aria-valuenow", "10");
|
|
51
|
+
|
|
52
|
+
await user.keyboard("{End}");
|
|
53
|
+
expect(screen.getByRole("slider")).toHaveAttribute("aria-valuenow", "90");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("honours the step", async () => {
|
|
57
|
+
const user = userEvent.setup();
|
|
58
|
+
render(<Slider aria-label="Volume" defaultValue={[40]} step={10} />);
|
|
59
|
+
|
|
60
|
+
await user.tab();
|
|
61
|
+
await user.keyboard("{ArrowRight}");
|
|
62
|
+
expect(screen.getByRole("slider")).toHaveAttribute("aria-valuenow", "50");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("reports changes", async () => {
|
|
66
|
+
const onValueChange = vi.fn();
|
|
67
|
+
const user = userEvent.setup();
|
|
68
|
+
render(<Slider aria-label="Volume" defaultValue={[40]} onValueChange={onValueChange} />);
|
|
69
|
+
|
|
70
|
+
await user.tab();
|
|
71
|
+
await user.keyboard("{ArrowRight}");
|
|
72
|
+
expect(onValueChange).toHaveBeenCalledWith([41]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("works controlled", async () => {
|
|
76
|
+
const user = userEvent.setup();
|
|
77
|
+
|
|
78
|
+
function Controlled() {
|
|
79
|
+
const [value, setValue] = useState([30]);
|
|
80
|
+
return <Slider aria-label="Volume" value={value} onValueChange={setValue} />;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
render(<Controlled />);
|
|
84
|
+
await user.tab();
|
|
85
|
+
await user.keyboard("{ArrowRight}");
|
|
86
|
+
expect(screen.getByRole("slider")).toHaveAttribute("aria-valuenow", "31");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("does not respond while disabled", async () => {
|
|
90
|
+
const onValueChange = vi.fn();
|
|
91
|
+
const user = userEvent.setup();
|
|
92
|
+
render(
|
|
93
|
+
<Slider aria-label="Volume" defaultValue={[40]} disabled onValueChange={onValueChange} />,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
await user.tab();
|
|
97
|
+
await user.keyboard("{ArrowRight}");
|
|
98
|
+
expect(onValueChange).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("supports vertical orientation", () => {
|
|
102
|
+
render(<Slider aria-label="Volume" orientation="vertical" data-testid="slider" />);
|
|
103
|
+
expect(screen.getByTestId("slider")).toHaveAttribute("data-orientation", "vertical");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("forwards aria-valuetext onto the thumb", () => {
|
|
107
|
+
render(
|
|
108
|
+
<Slider aria-label="Duration" defaultValue={[90]} aria-valuetext="1 minute 30 seconds" />,
|
|
109
|
+
);
|
|
110
|
+
expect(screen.getByRole("slider")).toHaveAttribute("aria-valuetext", "1 minute 30 seconds");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("names each thumb of a range slider separately", () => {
|
|
114
|
+
render(
|
|
115
|
+
<Slider
|
|
116
|
+
defaultValue={[20, 80]}
|
|
117
|
+
thumbLabels={["Minimum price", "Maximum price"]}
|
|
118
|
+
thumbValueTexts={["$20", "$80"]}
|
|
119
|
+
/>,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const min = screen.getByRole("slider", { name: "Minimum price" });
|
|
123
|
+
const max = screen.getByRole("slider", { name: "Maximum price" });
|
|
124
|
+
expect(min).toHaveAttribute("aria-valuetext", "$20");
|
|
125
|
+
expect(max).toHaveAttribute("aria-valuetext", "$80");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("warns in development when a thumb would be unnamed", () => {
|
|
129
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
130
|
+
render(<Slider defaultValue={[40]} />);
|
|
131
|
+
|
|
132
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining("no accessible name"));
|
|
133
|
+
warn.mockRestore();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("does not warn when every thumb is named", () => {
|
|
137
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => undefined);
|
|
138
|
+
render(<Slider defaultValue={[20, 80]} thumbLabels={["Minimum", "Maximum"]} />);
|
|
139
|
+
|
|
140
|
+
expect(warn).not.toHaveBeenCalled();
|
|
141
|
+
warn.mockRestore();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("has no accessibility violations", async () => {
|
|
145
|
+
const { container } = render(<Slider aria-label="Volume" defaultValue={[40]} />);
|
|
146
|
+
await expectNoA11yViolations(container);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Slider as SliderPrimitive } from "radix-ui";
|
|
4
|
+
import { useEffect, useMemo, type ComponentPropsWithRef } from "react";
|
|
5
|
+
|
|
6
|
+
import { focusRing } from "@/lib/styles";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Selects a value, or a range, from a continuous span.
|
|
11
|
+
*
|
|
12
|
+
* Renders one thumb per value, so a range slider is just two values. Sliders
|
|
13
|
+
* are imprecise by nature: if the exact number matters, pair it with a numeric
|
|
14
|
+
* input rather than asking people to land on a pixel.
|
|
15
|
+
*/
|
|
16
|
+
export interface SliderProps extends ComponentPropsWithRef<typeof SliderPrimitive.Root> {
|
|
17
|
+
/**
|
|
18
|
+
* Accessible name per thumb, in order.
|
|
19
|
+
*
|
|
20
|
+
* A range slider is two independent `role="slider"` controls, and naming both
|
|
21
|
+
* of them "Price" tells a screen reader user nothing about which one they are
|
|
22
|
+
* on. Give them distinct names — "Minimum price", "Maximum price".
|
|
23
|
+
*/
|
|
24
|
+
thumbLabels?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Spoken value per thumb, in order, for values whose raw number is not
|
|
27
|
+
* meaningful on its own — a price, a duration, a rating.
|
|
28
|
+
*/
|
|
29
|
+
thumbValueTexts?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function Slider({
|
|
33
|
+
className,
|
|
34
|
+
value,
|
|
35
|
+
defaultValue,
|
|
36
|
+
min = 0,
|
|
37
|
+
max = 100,
|
|
38
|
+
thumbLabels,
|
|
39
|
+
thumbValueTexts,
|
|
40
|
+
// Every naming and value-describing attribute has to move to the thumbs for
|
|
41
|
+
// the same reason: the thumb is the element with role="slider".
|
|
42
|
+
"aria-label": ariaLabel,
|
|
43
|
+
"aria-labelledby": ariaLabelledBy,
|
|
44
|
+
"aria-valuetext": ariaValueText,
|
|
45
|
+
...props
|
|
46
|
+
}: SliderProps) {
|
|
47
|
+
// One thumb per value. Falling back to a single thumb keeps the bare
|
|
48
|
+
// <Slider /> case working without forcing a defaultValue.
|
|
49
|
+
const thumbCount = useMemo(
|
|
50
|
+
() => (value ?? defaultValue ?? [min]).length,
|
|
51
|
+
[value, defaultValue, min],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// The name has to live on the thumb, because the thumb is the element with
|
|
55
|
+
// role="slider". Left on the root it names an element with no role, and the
|
|
56
|
+
// control a screen reader actually lands on is announced unnamed.
|
|
57
|
+
useMissingLabelWarning(thumbCount, thumbLabels, ariaLabel, ariaLabelledBy);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<SliderPrimitive.Root
|
|
61
|
+
data-slot="slider"
|
|
62
|
+
value={value}
|
|
63
|
+
defaultValue={defaultValue}
|
|
64
|
+
min={min}
|
|
65
|
+
max={max}
|
|
66
|
+
className={cn(
|
|
67
|
+
"relative flex w-full touch-none items-center select-none",
|
|
68
|
+
"data-[orientation=vertical]:h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
69
|
+
"data-[disabled]:opacity-55",
|
|
70
|
+
className,
|
|
71
|
+
)}
|
|
72
|
+
{...props}
|
|
73
|
+
>
|
|
74
|
+
<SliderPrimitive.Track
|
|
75
|
+
data-slot="slider-track"
|
|
76
|
+
className={cn(
|
|
77
|
+
"relative grow overflow-hidden rounded-full bg-muted",
|
|
78
|
+
"data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full",
|
|
79
|
+
"data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
|
|
80
|
+
)}
|
|
81
|
+
>
|
|
82
|
+
<SliderPrimitive.Range
|
|
83
|
+
data-slot="slider-range"
|
|
84
|
+
className={cn(
|
|
85
|
+
"absolute bg-primary",
|
|
86
|
+
"data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
</SliderPrimitive.Track>
|
|
90
|
+
{Array.from({ length: thumbCount }, (_, index) => (
|
|
91
|
+
<SliderPrimitive.Thumb
|
|
92
|
+
key={index}
|
|
93
|
+
data-slot="slider-thumb"
|
|
94
|
+
aria-label={thumbLabels?.[index] ?? ariaLabel}
|
|
95
|
+
aria-labelledby={thumbLabels?.[index] ? undefined : ariaLabelledBy}
|
|
96
|
+
aria-valuetext={thumbValueTexts?.[index] ?? ariaValueText}
|
|
97
|
+
className={cn(
|
|
98
|
+
"block size-4 shrink-0 rounded-full border-2 border-primary bg-background shadow-sm",
|
|
99
|
+
"transition-[box-shadow,transform] duration-[var(--duration-instant)]",
|
|
100
|
+
"hover:scale-110 disabled:pointer-events-none",
|
|
101
|
+
focusRing,
|
|
102
|
+
)}
|
|
103
|
+
/>
|
|
104
|
+
))}
|
|
105
|
+
</SliderPrimitive.Root>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Warns, in development only, when a thumb would render without a name.
|
|
111
|
+
*
|
|
112
|
+
* An unnamed slider is invisible on screen and serious for screen reader users,
|
|
113
|
+
* so it is surfaced where it is introduced rather than left for an audit.
|
|
114
|
+
*/
|
|
115
|
+
function useMissingLabelWarning(
|
|
116
|
+
thumbCount: number,
|
|
117
|
+
thumbLabels: string[] | undefined,
|
|
118
|
+
ariaLabel: string | undefined,
|
|
119
|
+
ariaLabelledBy: string | undefined,
|
|
120
|
+
) {
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (process.env.NODE_ENV === "production") return;
|
|
123
|
+
|
|
124
|
+
const fallbackName = ariaLabel ?? ariaLabelledBy;
|
|
125
|
+
const unnamed = Array.from({ length: thumbCount }).some(
|
|
126
|
+
(_, index) => !(thumbLabels?.[index] ?? fallbackName),
|
|
127
|
+
);
|
|
128
|
+
if (!unnamed) return;
|
|
129
|
+
|
|
130
|
+
console.warn(
|
|
131
|
+
"[Slider] A thumb has no accessible name. Pass aria-label or aria-labelledby, or " +
|
|
132
|
+
"thumbLabels to name each thumb of a range slider individually.",
|
|
133
|
+
);
|
|
134
|
+
}, [thumbCount, thumbLabels, ariaLabel, ariaLabelledBy]);
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Spinner, spinnerVariants, type SpinnerProps } from "./spinner";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineMeta } from "@/registry/schema";
|
|
2
|
+
|
|
3
|
+
export const meta = defineMeta({
|
|
4
|
+
name: "spinner",
|
|
5
|
+
title: "Spinner",
|
|
6
|
+
description: "An indeterminate loading indicator for buttons, panels and inline content.",
|
|
7
|
+
category: "feedback",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["class-variance-authority"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["spinner.tsx"],
|
|
12
|
+
a11y:
|
|
13
|
+
"Renders aria-hidden by default so it does not announce inside controls that already " +
|
|
14
|
+
'expose a busy state. Pass `label` to announce it standalone via role="status".',
|
|
15
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/button";
|
|
4
|
+
|
|
5
|
+
import { Spinner } from "./spinner";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Feedback/Spinner",
|
|
9
|
+
component: Spinner,
|
|
10
|
+
args: { size: "md" },
|
|
11
|
+
argTypes: { size: { control: "select", options: ["xs", "sm", "md", "lg", "xl"] } },
|
|
12
|
+
} satisfies Meta<typeof Spinner>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: { label: "Loading" },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Sizes: Story = {
|
|
22
|
+
parameters: { controls: { disable: true } },
|
|
23
|
+
render: () => (
|
|
24
|
+
<div className="flex items-center gap-4">
|
|
25
|
+
{(["xs", "sm", "md", "lg", "xl"] as const).map((size) => (
|
|
26
|
+
<Spinner key={size} size={size} />
|
|
27
|
+
))}
|
|
28
|
+
</div>
|
|
29
|
+
),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const InheritsColour: Story = {
|
|
33
|
+
parameters: { controls: { disable: true } },
|
|
34
|
+
render: () => (
|
|
35
|
+
<div className="flex items-center gap-4">
|
|
36
|
+
<Spinner className="text-primary" />
|
|
37
|
+
<Spinner className="text-destructive" />
|
|
38
|
+
<Spinner className="text-muted-foreground" />
|
|
39
|
+
</div>
|
|
40
|
+
),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Inside a control that already reports its own busy state, omit `label`. */
|
|
44
|
+
export const InsideAButton: Story = {
|
|
45
|
+
parameters: { controls: { disable: true } },
|
|
46
|
+
render: () => <Button loading>Saving changes</Button>,
|
|
47
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { expectNoA11yViolations } from "../../../test/a11y";
|
|
5
|
+
import { Spinner } from "./spinner";
|
|
6
|
+
|
|
7
|
+
describe("Spinner", () => {
|
|
8
|
+
it("is hidden from assistive technology by default", () => {
|
|
9
|
+
const { container } = render(<Spinner />);
|
|
10
|
+
expect(container.querySelector("svg")).toHaveAttribute("aria-hidden", "true");
|
|
11
|
+
expect(screen.queryByRole("status")).not.toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("announces itself when given a label", () => {
|
|
15
|
+
render(<Spinner label="Loading results" />);
|
|
16
|
+
expect(screen.getByRole("status")).toHaveTextContent("Loading results");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it.each([
|
|
20
|
+
["xs", "size-3"],
|
|
21
|
+
["sm", "size-3.5"],
|
|
22
|
+
["md", "size-4"],
|
|
23
|
+
["lg", "size-5"],
|
|
24
|
+
["xl", "size-6"],
|
|
25
|
+
] as const)("applies the %s size", (size, expectedClass) => {
|
|
26
|
+
const { container } = render(<Spinner size={size} />);
|
|
27
|
+
expect(container.querySelector("svg")).toHaveClass(expectedClass);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("lets a consumer className override the size", () => {
|
|
31
|
+
const { container } = render(<Spinner className="size-10" />);
|
|
32
|
+
const svg = container.querySelector("svg");
|
|
33
|
+
expect(svg).toHaveClass("size-10");
|
|
34
|
+
expect(svg).not.toHaveClass("size-4");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("has no accessibility violations", async () => {
|
|
38
|
+
const { container } = render(<Spinner label="Loading" />);
|
|
39
|
+
await expectNoA11yViolations(container);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
|
+
import type { ComponentPropsWithRef } from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
const spinnerVariants = cva("animate-spin text-current", {
|
|
7
|
+
variants: {
|
|
8
|
+
size: {
|
|
9
|
+
xs: "size-3",
|
|
10
|
+
sm: "size-3.5",
|
|
11
|
+
md: "size-4",
|
|
12
|
+
lg: "size-5",
|
|
13
|
+
xl: "size-6",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
size: "md",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export interface SpinnerProps
|
|
22
|
+
extends Omit<ComponentPropsWithRef<"svg">, "children">, VariantProps<typeof spinnerVariants> {
|
|
23
|
+
/**
|
|
24
|
+
* Announced to assistive technology while the spinner is visible.
|
|
25
|
+
*
|
|
26
|
+
* Omit it when the spinner sits inside a control that already communicates
|
|
27
|
+
* its busy state (a loading Button, for example) — announcing twice is worse
|
|
28
|
+
* than not announcing at all.
|
|
29
|
+
*/
|
|
30
|
+
label?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Indeterminate loading indicator. */
|
|
34
|
+
export function Spinner({ className, size, label, ...props }: SpinnerProps) {
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<svg
|
|
38
|
+
viewBox="0 0 24 24"
|
|
39
|
+
fill="none"
|
|
40
|
+
aria-hidden="true"
|
|
41
|
+
className={cn(spinnerVariants({ size }), className)}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
<circle
|
|
45
|
+
cx="12"
|
|
46
|
+
cy="12"
|
|
47
|
+
r="9.5"
|
|
48
|
+
stroke="currentColor"
|
|
49
|
+
strokeWidth="2.5"
|
|
50
|
+
opacity="0.22"
|
|
51
|
+
/>
|
|
52
|
+
<path
|
|
53
|
+
d="M12 2.5a9.5 9.5 0 0 1 9.5 9.5"
|
|
54
|
+
stroke="currentColor"
|
|
55
|
+
strokeWidth="2.5"
|
|
56
|
+
strokeLinecap="round"
|
|
57
|
+
/>
|
|
58
|
+
</svg>
|
|
59
|
+
{label ? (
|
|
60
|
+
<span role="status" className="sr-only">
|
|
61
|
+
{label}
|
|
62
|
+
</span>
|
|
63
|
+
) : null}
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { spinnerVariants };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Switch, type SwitchProps } from "./switch";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineMeta } from "@/registry/schema";
|
|
2
|
+
|
|
3
|
+
export const meta = defineMeta({
|
|
4
|
+
name: "switch",
|
|
5
|
+
title: "Switch",
|
|
6
|
+
description: "An immediate on/off toggle for settings that apply straight away.",
|
|
7
|
+
category: "form",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["radix-ui"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["switch.tsx"],
|
|
12
|
+
a11y:
|
|
13
|
+
'Exposed as role="switch" and toggled with Space or Enter. Needs a visible label tied with ' +
|
|
14
|
+
"htmlFor/id. Do not rely on colour alone to show state — position and the label carry it too.",
|
|
15
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Label } from "@/components/label";
|
|
4
|
+
|
|
5
|
+
import { Switch } from "./switch";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Forms/Switch",
|
|
9
|
+
component: Switch,
|
|
10
|
+
args: { disabled: false },
|
|
11
|
+
argTypes: { disabled: { control: "boolean" } },
|
|
12
|
+
} satisfies Meta<typeof Switch>;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
render: (args) => (
|
|
19
|
+
<div className="flex items-center gap-2">
|
|
20
|
+
<Switch id="airplane" {...args} />
|
|
21
|
+
<Label htmlFor="airplane">Airplane mode</Label>
|
|
22
|
+
</div>
|
|
23
|
+
),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const States: Story = {
|
|
27
|
+
parameters: { controls: { disable: true } },
|
|
28
|
+
render: () => (
|
|
29
|
+
<div className="grid gap-3">
|
|
30
|
+
{[
|
|
31
|
+
{ id: "off", label: "Off", checked: false },
|
|
32
|
+
{ id: "on", label: "On", checked: true },
|
|
33
|
+
].map((state) => (
|
|
34
|
+
<div key={state.id} className="flex items-center gap-2">
|
|
35
|
+
<Switch id={state.id} checked={state.checked} />
|
|
36
|
+
<Label htmlFor={state.id}>{state.label}</Label>
|
|
37
|
+
</div>
|
|
38
|
+
))}
|
|
39
|
+
<div className="flex items-center gap-2">
|
|
40
|
+
<Switch id="disabled-off" disabled />
|
|
41
|
+
<Label htmlFor="disabled-off">Disabled</Label>
|
|
42
|
+
</div>
|
|
43
|
+
<div className="flex items-center gap-2">
|
|
44
|
+
<Switch id="disabled-on" disabled checked />
|
|
45
|
+
<Label htmlFor="disabled-on">Disabled and on</Label>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** A switch applies immediately — if it needs a Save button, use a Checkbox. */
|
|
52
|
+
export const SettingsRow: Story = {
|
|
53
|
+
parameters: { controls: { disable: true } },
|
|
54
|
+
render: () => (
|
|
55
|
+
<div className="w-80 divide-y divide-border rounded-lg border border-border">
|
|
56
|
+
{[
|
|
57
|
+
{ id: "row-1", label: "Automatic deploys", hint: "Deploy every push to main." },
|
|
58
|
+
{ id: "row-2", label: "Preview comments", hint: "Comment on pull requests." },
|
|
59
|
+
].map((row) => (
|
|
60
|
+
<div key={row.id} className="flex items-start justify-between gap-4 p-4">
|
|
61
|
+
<div className="grid gap-1">
|
|
62
|
+
<Label htmlFor={row.id}>{row.label}</Label>
|
|
63
|
+
<p className="text-xs text-muted-foreground">{row.hint}</p>
|
|
64
|
+
</div>
|
|
65
|
+
<Switch id={row.id} defaultChecked={row.id === "row-1"} />
|
|
66
|
+
</div>
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
70
|
+
};
|