@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,96 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { expectNoA11yViolations } from "../../../test/a11y";
|
|
5
|
+
import { Response, ThinkingIndicator } from "./ai-response";
|
|
6
|
+
|
|
7
|
+
describe("Response", () => {
|
|
8
|
+
it("renders its text", () => {
|
|
9
|
+
render(<Response>The capital of France is Paris.</Response>);
|
|
10
|
+
expect(screen.getByText("The capital of France is Paris.")).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("is NOT a live region", () => {
|
|
14
|
+
// Announcing streamed text as it arrives interrupts a screen reader on
|
|
15
|
+
// every token; state goes through ConversationStatus instead.
|
|
16
|
+
const { container } = render(<Response streaming>Partial…</Response>);
|
|
17
|
+
const response = container.querySelector("[data-slot='response']");
|
|
18
|
+
|
|
19
|
+
expect(response).not.toHaveAttribute("aria-live");
|
|
20
|
+
expect(response).not.toHaveAttribute("role");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("shows a decorative caret while streaming", () => {
|
|
24
|
+
const { container } = render(<Response streaming>Partial</Response>);
|
|
25
|
+
const caret = container.querySelector("[data-slot='response-caret']");
|
|
26
|
+
|
|
27
|
+
expect(caret).toBeInTheDocument();
|
|
28
|
+
expect(caret).toHaveAttribute("aria-hidden", "true");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("has no caret when it is not streaming", () => {
|
|
32
|
+
const { container } = render(<Response>Done</Response>);
|
|
33
|
+
expect(container.querySelector("[data-slot='response-caret']")).not.toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("marks the streaming state for styling", () => {
|
|
37
|
+
const { container } = render(<Response streaming>Partial</Response>);
|
|
38
|
+
expect(container.querySelector("[data-slot='response']")).toHaveAttribute(
|
|
39
|
+
"data-streaming",
|
|
40
|
+
"true",
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("preserves paragraph whitespace", () => {
|
|
45
|
+
const { container } = render(<Response>{"line one\nline two"}</Response>);
|
|
46
|
+
expect(container.querySelector("[data-slot='response']")).toHaveClass(
|
|
47
|
+
"whitespace-pre-wrap",
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("renders markup a consumer has already rendered", () => {
|
|
52
|
+
render(
|
|
53
|
+
<Response>
|
|
54
|
+
<p>First</p>
|
|
55
|
+
<p>Second</p>
|
|
56
|
+
</Response>,
|
|
57
|
+
);
|
|
58
|
+
expect(screen.getByText("First")).toBeInTheDocument();
|
|
59
|
+
expect(screen.getByText("Second")).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("lets a consumer className override a conflicting utility", () => {
|
|
63
|
+
const { container } = render(<Response className="text-base">Hi</Response>);
|
|
64
|
+
const response = container.querySelector("[data-slot='response']");
|
|
65
|
+
expect(response).toHaveClass("text-base");
|
|
66
|
+
expect(response).not.toHaveClass("text-sm");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("has no accessibility violations", async () => {
|
|
70
|
+
const { container } = render(<Response streaming>Streaming text…</Response>);
|
|
71
|
+
await expectNoA11yViolations(container);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("ThinkingIndicator", () => {
|
|
76
|
+
it("is labelled, because it is the only thing on screen", () => {
|
|
77
|
+
render(<ThinkingIndicator />);
|
|
78
|
+
expect(screen.getByText("Thinking")).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("accepts a custom label", () => {
|
|
82
|
+
render(<ThinkingIndicator label="Searching the web" />);
|
|
83
|
+
expect(screen.getByText("Searching the web")).toBeInTheDocument();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("hides its dots from assistive technology", () => {
|
|
87
|
+
const { container } = render(<ThinkingIndicator />);
|
|
88
|
+
const dots = container.querySelectorAll("span[aria-hidden='true']");
|
|
89
|
+
expect(dots).toHaveLength(3);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("has no accessibility violations", async () => {
|
|
93
|
+
const { container } = render(<ThinkingIndicator />);
|
|
94
|
+
await expectNoA11yViolations(container);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ComponentPropsWithRef } from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The text of an assistant response.
|
|
9
|
+
*
|
|
10
|
+
* Renders plain text with paragraph whitespace preserved. Markdown is
|
|
11
|
+
* deliberately not parsed here: a Markdown renderer is a dependency, a security
|
|
12
|
+
* decision about raw HTML, and a styling surface all at once, and every product
|
|
13
|
+
* makes those differently. Pass already-rendered content as children when you
|
|
14
|
+
* need it — the prose styling below applies either way.
|
|
15
|
+
*
|
|
16
|
+
* Not a live region, and not by omission. See the note on `Conversation`:
|
|
17
|
+
* announcing streamed text token by token is unusable with a screen reader.
|
|
18
|
+
*/
|
|
19
|
+
export interface ResponseProps extends ComponentPropsWithRef<"div"> {
|
|
20
|
+
/** Shows the caret. Purely visual — it carries no announcement. */
|
|
21
|
+
streaming?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Response({ className, streaming, children, ...props }: ResponseProps) {
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
data-slot="response"
|
|
28
|
+
data-streaming={streaming || undefined}
|
|
29
|
+
className={cn(
|
|
30
|
+
"text-sm leading-relaxed whitespace-pre-wrap text-foreground",
|
|
31
|
+
// Minimal prose styling for consumers who pass rendered Markdown.
|
|
32
|
+
"[&_a]:text-primary [&_a]:underline [&_a]:underline-offset-4",
|
|
33
|
+
"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em]",
|
|
34
|
+
"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5",
|
|
35
|
+
"[&_p+p]:mt-3",
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
>
|
|
40
|
+
{children}
|
|
41
|
+
{streaming ? <ResponseCaret /> : null}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The trailing cursor. Decorative — the streaming state is announced, if at
|
|
47
|
+
* all, through ConversationStatus. */
|
|
48
|
+
export function ResponseCaret({ className, ...props }: ComponentPropsWithRef<"span">) {
|
|
49
|
+
return (
|
|
50
|
+
<span
|
|
51
|
+
data-slot="response-caret"
|
|
52
|
+
aria-hidden="true"
|
|
53
|
+
className={cn(
|
|
54
|
+
"ml-0.5 inline-block h-[1em] w-[2px] translate-y-[0.15em] animate-caret bg-current align-baseline",
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Shown while waiting for the first token.
|
|
64
|
+
*
|
|
65
|
+
* A distinct state from streaming: nothing has arrived yet, so there is no text
|
|
66
|
+
* to show a caret after. Labelled for assistive technology because, unlike the
|
|
67
|
+
* caret, this is the only thing on screen.
|
|
68
|
+
*/
|
|
69
|
+
export interface ThinkingIndicatorProps extends ComponentPropsWithRef<"div"> {
|
|
70
|
+
label?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function ThinkingIndicator({
|
|
74
|
+
className,
|
|
75
|
+
label = "Thinking",
|
|
76
|
+
...props
|
|
77
|
+
}: ThinkingIndicatorProps) {
|
|
78
|
+
return (
|
|
79
|
+
<div
|
|
80
|
+
data-slot="thinking-indicator"
|
|
81
|
+
className={cn("flex items-center gap-1.5 text-sm text-muted-foreground", className)}
|
|
82
|
+
{...props}
|
|
83
|
+
>
|
|
84
|
+
<span className="sr-only">{label}</span>
|
|
85
|
+
{[0, 1, 2].map((index) => (
|
|
86
|
+
<span
|
|
87
|
+
key={index}
|
|
88
|
+
aria-hidden="true"
|
|
89
|
+
className="size-1.5 animate-pulse-soft rounded-full bg-current"
|
|
90
|
+
style={{ animationDelay: `${String(index * 160)}ms` }}
|
|
91
|
+
/>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineMeta } from "@/registry/schema";
|
|
2
|
+
|
|
3
|
+
export const meta = defineMeta({
|
|
4
|
+
name: "ai-response",
|
|
5
|
+
title: "AI Response",
|
|
6
|
+
description: "Assistant response text, with a streaming caret and a thinking indicator.",
|
|
7
|
+
category: "ai",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: [],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["ai-response.tsx"],
|
|
12
|
+
a11y:
|
|
13
|
+
"Deliberately not a live region: announcing streamed text as it arrives interrupts a screen " +
|
|
14
|
+
"reader user on every token. Announce state through ConversationStatus and let them read the " +
|
|
15
|
+
"response when it settles. The caret is decorative; ThinkingIndicator carries a label because " +
|
|
16
|
+
"it is the only thing on screen while waiting for the first token.",
|
|
17
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Decorator, Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Response } from "@/components/ai-response";
|
|
4
|
+
|
|
5
|
+
import { InlineCitation, Source, Sources, SourcesContent, SourcesTrigger } from "./ai-sources";
|
|
6
|
+
|
|
7
|
+
/** Named so its type is nameable in declaration output (TS2883). */
|
|
8
|
+
const withFixedWidth: Decorator = (Story) => (
|
|
9
|
+
<div className="w-[32rem]">
|
|
10
|
+
<Story />
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: "AI/Sources",
|
|
16
|
+
component: Sources,
|
|
17
|
+
parameters: { controls: { disable: true } },
|
|
18
|
+
decorators: [withFixedWidth],
|
|
19
|
+
} satisfies Meta<typeof Sources>;
|
|
20
|
+
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
|
|
24
|
+
const SOURCES = [
|
|
25
|
+
{
|
|
26
|
+
index: 1,
|
|
27
|
+
title: "ARIA Authoring Practices — Table pattern",
|
|
28
|
+
origin: "w3.org",
|
|
29
|
+
excerpt: "Scrollable regions should be focusable so keyboard users can scroll them.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
index: 2,
|
|
33
|
+
title: "Accessible data tables",
|
|
34
|
+
origin: "example.org",
|
|
35
|
+
excerpt: "Native table semantics convey row and column position without extra ARIA.",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/** Markers next to the claim, the list underneath saying what each one is. */
|
|
40
|
+
export const Default: Story = {
|
|
41
|
+
render: () => (
|
|
42
|
+
<div className="grid gap-3">
|
|
43
|
+
<Response>
|
|
44
|
+
A scroll container needs an explicit focus stop to be reachable by keyboard
|
|
45
|
+
<InlineCitation index={1} title={SOURCES[0]!.title} href="#1" />, and native table
|
|
46
|
+
semantics carry position without extra ARIA
|
|
47
|
+
<InlineCitation index={2} title={SOURCES[1]!.title} href="#2" />.
|
|
48
|
+
</Response>
|
|
49
|
+
<Sources>
|
|
50
|
+
<SourcesTrigger count={SOURCES.length} />
|
|
51
|
+
<SourcesContent>
|
|
52
|
+
{SOURCES.map((source) => (
|
|
53
|
+
<Source key={source.index} {...source} href={`#${String(source.index)}`} />
|
|
54
|
+
))}
|
|
55
|
+
</SourcesContent>
|
|
56
|
+
</Sources>
|
|
57
|
+
</div>
|
|
58
|
+
),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const Expanded: Story = {
|
|
62
|
+
render: () => (
|
|
63
|
+
<Sources defaultOpen>
|
|
64
|
+
<SourcesTrigger count={SOURCES.length} />
|
|
65
|
+
<SourcesContent>
|
|
66
|
+
{SOURCES.map((source) => (
|
|
67
|
+
<Source key={source.index} {...source} href={`#${String(source.index)}`} />
|
|
68
|
+
))}
|
|
69
|
+
</SourcesContent>
|
|
70
|
+
</Sources>
|
|
71
|
+
),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** A marker with nowhere to go renders as text, not a link that does nothing. */
|
|
75
|
+
export const WithoutLinks: Story = {
|
|
76
|
+
render: () => (
|
|
77
|
+
<Response>
|
|
78
|
+
Internal policy requires two approvals
|
|
79
|
+
<InlineCitation index={1} title="Engineering handbook, section 4" />.
|
|
80
|
+
</Response>
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const SingleSource: Story = {
|
|
85
|
+
render: () => (
|
|
86
|
+
<Sources defaultOpen>
|
|
87
|
+
<SourcesTrigger count={1} />
|
|
88
|
+
<SourcesContent>
|
|
89
|
+
<Source index={1} title="Engineering handbook" origin="internal" href="#1" />
|
|
90
|
+
</SourcesContent>
|
|
91
|
+
</Sources>
|
|
92
|
+
),
|
|
93
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { expectNoA11yViolations } from "../../../test/a11y";
|
|
6
|
+
import { InlineCitation, Source, Sources, SourcesContent, SourcesTrigger } from "./ai-sources";
|
|
7
|
+
|
|
8
|
+
describe("InlineCitation", () => {
|
|
9
|
+
it("carries the source title in its accessible name", () => {
|
|
10
|
+
render(<InlineCitation index={1} title="Encyclopaedia entry on France" href="#1" />);
|
|
11
|
+
// The visible text is a bare number, which conveys nothing on its own.
|
|
12
|
+
expect(
|
|
13
|
+
screen.getByRole("link", { name: "Source 1: Encyclopaedia entry on France" }),
|
|
14
|
+
).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("renders as text, not a dead link, without an href", () => {
|
|
18
|
+
render(<InlineCitation index={2} title="Internal document" />);
|
|
19
|
+
expect(screen.queryByRole("link")).not.toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText("Source 2: Internal document")).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("shows the marker number visually", () => {
|
|
24
|
+
const { container } = render(<InlineCitation index={3} title="A source" />);
|
|
25
|
+
expect(container.querySelector("[aria-hidden='true']")).toHaveTextContent("3");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("Sources", () => {
|
|
30
|
+
function Example() {
|
|
31
|
+
return (
|
|
32
|
+
<Sources>
|
|
33
|
+
<SourcesTrigger count={2} />
|
|
34
|
+
<SourcesContent>
|
|
35
|
+
<Source index={1} title="Paris — overview" origin="example.org" href="#1" />
|
|
36
|
+
<Source
|
|
37
|
+
index={2}
|
|
38
|
+
title="France factbook"
|
|
39
|
+
origin="factbook.example"
|
|
40
|
+
excerpt="Paris is the capital and most populous city."
|
|
41
|
+
href="#2"
|
|
42
|
+
/>
|
|
43
|
+
</SourcesContent>
|
|
44
|
+
</Sources>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
it("is collapsed by default", () => {
|
|
49
|
+
render(<Example />);
|
|
50
|
+
expect(screen.getByRole("button", { name: "2 sources" })).toHaveAttribute(
|
|
51
|
+
"aria-expanded",
|
|
52
|
+
"false",
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("pluralises the count", () => {
|
|
57
|
+
render(
|
|
58
|
+
<Sources>
|
|
59
|
+
<SourcesTrigger count={1} />
|
|
60
|
+
<SourcesContent>
|
|
61
|
+
<Source index={1} title="Only one" href="#1" />
|
|
62
|
+
</SourcesContent>
|
|
63
|
+
</Sources>,
|
|
64
|
+
);
|
|
65
|
+
expect(screen.getByRole("button", { name: "1 source" })).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("lists the sources in order, matching the marker numbers", async () => {
|
|
69
|
+
const user = userEvent.setup();
|
|
70
|
+
render(<Example />);
|
|
71
|
+
|
|
72
|
+
await user.click(screen.getByRole("button", { name: "2 sources" }));
|
|
73
|
+
|
|
74
|
+
const list = await screen.findByRole("list");
|
|
75
|
+
expect(list.tagName).toBe("OL");
|
|
76
|
+
expect(screen.getAllByRole("listitem")).toHaveLength(2);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("shows origin and excerpt when given", async () => {
|
|
80
|
+
const user = userEvent.setup();
|
|
81
|
+
render(<Example />);
|
|
82
|
+
|
|
83
|
+
await user.click(screen.getByRole("button", { name: "2 sources" }));
|
|
84
|
+
expect(await screen.findByText("factbook.example")).toBeInTheDocument();
|
|
85
|
+
expect(
|
|
86
|
+
screen.getByText(/Paris is the capital and most populous city\./),
|
|
87
|
+
).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("has no accessibility violations", async () => {
|
|
91
|
+
const { container } = render(
|
|
92
|
+
<Sources defaultOpen>
|
|
93
|
+
<SourcesTrigger count={2} />
|
|
94
|
+
<SourcesContent>
|
|
95
|
+
<Source index={1} title="Paris — overview" origin="example.org" href="#1" />
|
|
96
|
+
<Source index={2} title="France factbook" href="#2" />
|
|
97
|
+
</SourcesContent>
|
|
98
|
+
</Sources>,
|
|
99
|
+
);
|
|
100
|
+
await expectNoA11yViolations(container);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Collapsible as CollapsiblePrimitive } from "radix-ui";
|
|
4
|
+
import type { ComponentPropsWithRef } from "react";
|
|
5
|
+
|
|
6
|
+
import { focusRing } from "@/lib/styles";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Where a response came from.
|
|
11
|
+
*
|
|
12
|
+
* Citations are the difference between an assertion and a claim someone can
|
|
13
|
+
* check, so they are first-class here rather than a footnote: an inline marker
|
|
14
|
+
* next to the sentence, and a list underneath that says what each marker is.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An inline citation marker.
|
|
19
|
+
*
|
|
20
|
+
* The visible text is a bare number, which tells a screen reader user nothing,
|
|
21
|
+
* so the real title goes in the accessible name. Rendered as a link when given
|
|
22
|
+
* an href, and as plain text otherwise — a marker that looks clickable and is
|
|
23
|
+
* not is worse than one that does not.
|
|
24
|
+
*/
|
|
25
|
+
export interface InlineCitationProps extends ComponentPropsWithRef<"a"> {
|
|
26
|
+
/** Position in the source list, starting at 1. */
|
|
27
|
+
index: number;
|
|
28
|
+
/** What is being cited. Becomes the accessible name. */
|
|
29
|
+
title: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function InlineCitation({
|
|
33
|
+
className,
|
|
34
|
+
index,
|
|
35
|
+
title,
|
|
36
|
+
href,
|
|
37
|
+
...props
|
|
38
|
+
}: InlineCitationProps) {
|
|
39
|
+
const shared = cn(
|
|
40
|
+
"mx-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded px-1 align-[0.15em]",
|
|
41
|
+
"bg-muted text-2xs font-medium text-muted-foreground tabular-nums",
|
|
42
|
+
className,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (!href) {
|
|
46
|
+
return (
|
|
47
|
+
<span data-slot="inline-citation" className={shared}>
|
|
48
|
+
<span aria-hidden="true">{index}</span>
|
|
49
|
+
<span className="sr-only">
|
|
50
|
+
Source {index}: {title}
|
|
51
|
+
</span>
|
|
52
|
+
</span>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<a
|
|
58
|
+
data-slot="inline-citation"
|
|
59
|
+
href={href}
|
|
60
|
+
aria-label={`Source ${String(index)}: ${title}`}
|
|
61
|
+
className={cn(
|
|
62
|
+
shared,
|
|
63
|
+
"transition-colors duration-[var(--duration-fast)] hover:bg-accent hover:text-foreground",
|
|
64
|
+
focusRing,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
>
|
|
68
|
+
<span aria-hidden="true">{index}</span>
|
|
69
|
+
</a>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type SourcesProps = ComponentPropsWithRef<typeof CollapsiblePrimitive.Root>;
|
|
74
|
+
|
|
75
|
+
export function Sources({ className, ...props }: SourcesProps) {
|
|
76
|
+
return (
|
|
77
|
+
<CollapsiblePrimitive.Root
|
|
78
|
+
data-slot="sources"
|
|
79
|
+
className={cn("w-full text-sm", className)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface SourcesTriggerProps extends ComponentPropsWithRef<
|
|
86
|
+
typeof CollapsiblePrimitive.Trigger
|
|
87
|
+
> {
|
|
88
|
+
count: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function SourcesTrigger({ className, count, children, ...props }: SourcesTriggerProps) {
|
|
92
|
+
return (
|
|
93
|
+
<CollapsiblePrimitive.Trigger
|
|
94
|
+
data-slot="sources-trigger"
|
|
95
|
+
className={cn(
|
|
96
|
+
"flex items-center gap-1.5 rounded-md text-xs text-muted-foreground",
|
|
97
|
+
"transition-colors duration-[var(--duration-fast)] hover:text-foreground",
|
|
98
|
+
"[&[data-state=open]>svg:last-child]:rotate-180",
|
|
99
|
+
focusRing,
|
|
100
|
+
className,
|
|
101
|
+
)}
|
|
102
|
+
{...props}
|
|
103
|
+
>
|
|
104
|
+
{children ?? `${String(count)} ${count === 1 ? "source" : "sources"}`}
|
|
105
|
+
<svg
|
|
106
|
+
viewBox="0 0 24 24"
|
|
107
|
+
fill="none"
|
|
108
|
+
aria-hidden="true"
|
|
109
|
+
className="size-3.5 shrink-0 transition-transform duration-[var(--duration-normal)]"
|
|
110
|
+
>
|
|
111
|
+
<path
|
|
112
|
+
d="m6 9 6 6 6-6"
|
|
113
|
+
stroke="currentColor"
|
|
114
|
+
strokeWidth="2"
|
|
115
|
+
strokeLinecap="round"
|
|
116
|
+
strokeLinejoin="round"
|
|
117
|
+
/>
|
|
118
|
+
</svg>
|
|
119
|
+
</CollapsiblePrimitive.Trigger>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function SourcesContent({
|
|
124
|
+
className,
|
|
125
|
+
children,
|
|
126
|
+
...props
|
|
127
|
+
}: ComponentPropsWithRef<typeof CollapsiblePrimitive.Content>) {
|
|
128
|
+
return (
|
|
129
|
+
<CollapsiblePrimitive.Content
|
|
130
|
+
data-slot="sources-content"
|
|
131
|
+
className={cn(
|
|
132
|
+
"overflow-hidden",
|
|
133
|
+
"data-[state=closed]:animate-accordion-close data-[state=open]:animate-accordion-open",
|
|
134
|
+
className,
|
|
135
|
+
)}
|
|
136
|
+
{...props}
|
|
137
|
+
>
|
|
138
|
+
{/* Ordered, because the numbers in the inline markers refer to positions
|
|
139
|
+
in this list. */}
|
|
140
|
+
<ol className="mt-2 flex flex-col gap-1.5">{children}</ol>
|
|
141
|
+
</CollapsiblePrimitive.Content>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface SourceProps extends ComponentPropsWithRef<"a"> {
|
|
146
|
+
index: number;
|
|
147
|
+
title: string;
|
|
148
|
+
/** Where it came from — a domain, a filename, a document title. */
|
|
149
|
+
origin?: string;
|
|
150
|
+
/** The quoted passage, if there is one. */
|
|
151
|
+
excerpt?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function Source({ className, index, title, origin, excerpt, ...props }: SourceProps) {
|
|
155
|
+
return (
|
|
156
|
+
<li data-slot="source">
|
|
157
|
+
<a
|
|
158
|
+
className={cn(
|
|
159
|
+
"flex gap-2 rounded-md border border-border bg-card/50 px-2.5 py-2",
|
|
160
|
+
"transition-colors duration-[var(--duration-fast)] hover:bg-accent/50",
|
|
161
|
+
focusRing,
|
|
162
|
+
className,
|
|
163
|
+
)}
|
|
164
|
+
{...props}
|
|
165
|
+
>
|
|
166
|
+
<span
|
|
167
|
+
aria-hidden="true"
|
|
168
|
+
className="mt-0.5 grid size-4 shrink-0 place-items-center rounded bg-muted text-2xs font-medium text-muted-foreground tabular-nums"
|
|
169
|
+
>
|
|
170
|
+
{index}
|
|
171
|
+
</span>
|
|
172
|
+
<span className="min-w-0 flex-1">
|
|
173
|
+
<span className="block truncate text-xs font-medium text-foreground">{title}</span>
|
|
174
|
+
{origin ? (
|
|
175
|
+
<span className="block truncate text-2xs text-muted-foreground">{origin}</span>
|
|
176
|
+
) : null}
|
|
177
|
+
{excerpt ? (
|
|
178
|
+
<span className="mt-1 line-clamp-2 block text-xs text-muted-foreground">
|
|
179
|
+
“{excerpt}”
|
|
180
|
+
</span>
|
|
181
|
+
) : null}
|
|
182
|
+
</span>
|
|
183
|
+
</a>
|
|
184
|
+
</li>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineMeta } from "@/registry/schema";
|
|
2
|
+
|
|
3
|
+
export const meta = defineMeta({
|
|
4
|
+
name: "ai-sources",
|
|
5
|
+
title: "AI Sources",
|
|
6
|
+
description: "Inline citation markers and the source list they refer to.",
|
|
7
|
+
category: "ai",
|
|
8
|
+
status: "stable",
|
|
9
|
+
dependencies: ["radix-ui"],
|
|
10
|
+
registryDependencies: [],
|
|
11
|
+
files: ["ai-sources.tsx"],
|
|
12
|
+
a11y:
|
|
13
|
+
"An inline marker shows a bare number, which conveys nothing on its own, so the source title " +
|
|
14
|
+
"is carried in its accessible name. A marker with no href renders as text rather than as a " +
|
|
15
|
+
"link that goes nowhere. The source list is ordered, because the marker numbers refer to " +
|
|
16
|
+
"positions in it.",
|
|
17
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Decorator, Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { TokenCount, TokenUsage } from "./ai-token-usage";
|
|
4
|
+
|
|
5
|
+
/** Named so its type is nameable in declaration output (TS2883). */
|
|
6
|
+
const withFixedWidth: Decorator = (Story) => (
|
|
7
|
+
<div className="w-72">
|
|
8
|
+
<Story />
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: "AI/Token Usage",
|
|
14
|
+
component: TokenUsage,
|
|
15
|
+
args: { used: 42000, limit: 200000 },
|
|
16
|
+
argTypes: {
|
|
17
|
+
used: { control: { type: "range", min: 0, max: 240000, step: 1000 } },
|
|
18
|
+
},
|
|
19
|
+
decorators: [withFixedWidth],
|
|
20
|
+
} satisfies Meta<typeof TokenUsage>;
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {};
|
|
26
|
+
|
|
27
|
+
/** Running out of context is a cliff, not a slope — so the gauge warns early. */
|
|
28
|
+
export const Thresholds: Story = {
|
|
29
|
+
parameters: { controls: { disable: true } },
|
|
30
|
+
render: () => (
|
|
31
|
+
<div className="grid gap-5">
|
|
32
|
+
<TokenUsage used={42000} limit={200000} />
|
|
33
|
+
<TokenUsage used={175000} limit={200000} />
|
|
34
|
+
<TokenUsage used={212000} limit={200000} />
|
|
35
|
+
</div>
|
|
36
|
+
),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const CustomFormat: Story = {
|
|
40
|
+
parameters: { controls: { disable: true } },
|
|
41
|
+
render: () => (
|
|
42
|
+
<TokenUsage
|
|
43
|
+
used={128000}
|
|
44
|
+
limit={200000}
|
|
45
|
+
label="Context"
|
|
46
|
+
format={(value) => `${String(Math.round(value / 1000))}k`}
|
|
47
|
+
/>
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const InlineCount: Story = {
|
|
52
|
+
parameters: { controls: { disable: true } },
|
|
53
|
+
render: () => (
|
|
54
|
+
<div className="flex items-center gap-3">
|
|
55
|
+
<TokenCount value={1284} />
|
|
56
|
+
<TokenCount value={412} label="output tokens" />
|
|
57
|
+
</div>
|
|
58
|
+
),
|
|
59
|
+
};
|