@refraction-ui/astro 0.4.0 → 0.4.4
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/dist/accordion/index.ts +1 -0
- package/dist/ai/ai-manager.ts +121 -0
- package/dist/ai/index.ts +23 -0
- package/dist/ai/mock-providers.ts +68 -0
- package/dist/ai/sanitizer.ts +174 -0
- package/dist/ai/tts-manager.ts +80 -0
- package/dist/ai/types.ts +72 -0
- package/dist/animated-text/animated-text.styles.ts +28 -0
- package/dist/animated-text/animated-text.ts +83 -0
- package/dist/animated-text/index.ts +15 -0
- package/dist/app-shell/app-shell.ts +252 -0
- package/dist/app-shell/auth-shell.ts +84 -0
- package/dist/app-shell/index.ts +22 -0
- package/dist/app-shell/page-shell.ts +125 -0
- package/dist/astro-accordion/Button.astro +55 -0
- package/dist/astro-accordion/index.ts +1 -0
- package/dist/astro-ai/AIScript.astro +69 -0
- package/dist/astro-ai/TTSScript.astro +60 -0
- package/dist/astro-ai/index.ts +16 -0
- package/dist/astro-animated-text/AnimatedText.astro +81 -0
- package/dist/astro-animated-text/TypewriterText.astro +90 -0
- package/dist/astro-animated-text/index.ts +1 -0
- package/dist/astro-app-shell/AppShell.astro +195 -0
- package/dist/astro-app-shell/AppShellContent.astro +29 -0
- package/dist/astro-app-shell/AppShellHeader.astro +54 -0
- package/dist/astro-app-shell/AppShellMain.astro +18 -0
- package/dist/astro-app-shell/AppShellMobileNav.astro +27 -0
- package/dist/astro-app-shell/AppShellOverlay.astro +21 -0
- package/dist/astro-app-shell/AppShellSidebar.astro +26 -0
- package/dist/astro-app-shell/AuthShell.astro +31 -0
- package/dist/astro-app-shell/AuthShellCard.astro +24 -0
- package/dist/astro-app-shell/PageShell.astro +36 -0
- package/dist/astro-app-shell/PageShellFooter.astro +30 -0
- package/dist/astro-app-shell/PageShellNav.astro +33 -0
- package/dist/astro-app-shell/PageShellSection.astro +32 -0
- package/dist/astro-app-shell/index.ts +21 -0
- package/dist/astro-auth/AuthGuard.astro +133 -0
- package/dist/astro-auth/index.ts +5 -0
- package/dist/astro-avatar/Avatar.astro +22 -0
- package/dist/astro-avatar/AvatarFallback.astro +18 -0
- package/dist/astro-avatar/AvatarImage.astro +48 -0
- package/dist/astro-avatar/index.ts +1 -0
- package/dist/astro-avatar-group/AvatarGroup.astro +42 -0
- package/dist/astro-avatar-group/index.ts +1 -0
- package/dist/astro-badge/Badge.astro +27 -0
- package/dist/astro-badge/index.ts +1 -0
- package/dist/astro-bottom-nav/BottomNav.astro +40 -0
- package/dist/astro-bottom-nav/index.ts +1 -0
- package/dist/astro-breadcrumbs/Breadcrumbs.astro +56 -0
- package/dist/astro-breadcrumbs/index.ts +1 -0
- package/dist/astro-button/Button.astro +55 -0
- package/dist/astro-button/index.ts +1 -0
- package/dist/astro-calendar/Calendar.astro +259 -0
- package/dist/astro-calendar/index.ts +1 -0
- package/dist/astro-callout/Callout.astro +3 -0
- package/dist/astro-callout/index.ts +1 -0
- package/dist/astro-card/Card.astro +20 -0
- package/dist/astro-card/CardContent.astro +13 -0
- package/dist/astro-card/CardDescription.astro +13 -0
- package/dist/astro-card/CardFooter.astro +13 -0
- package/dist/astro-card/CardHeader.astro +13 -0
- package/dist/astro-card/CardTitle.astro +15 -0
- package/dist/astro-card/index.ts +1 -0
- package/dist/astro-card-grid/CardGrid.astro +17 -0
- package/dist/astro-card-grid/index.ts +1 -0
- package/dist/astro-carousel/Button.astro +55 -0
- package/dist/astro-carousel/index.ts +1 -0
- package/dist/astro-charts/Bars.astro +53 -0
- package/dist/astro-charts/Chart.astro +31 -0
- package/dist/astro-charts/Circles.astro +48 -0
- package/dist/astro-charts/Gradient.astro +34 -0
- package/dist/astro-charts/Histogram.astro +107 -0
- package/dist/astro-charts/Line.astro +55 -0
- package/dist/astro-charts/PieChart.astro +63 -0
- package/dist/astro-charts/ScatterPlot.astro +95 -0
- package/dist/astro-charts/XAxis.astro +46 -0
- package/dist/astro-charts/YAxis.astro +44 -0
- package/dist/astro-charts/index.ts +26 -0
- package/dist/astro-checkbox/Checkbox.astro +129 -0
- package/dist/astro-checkbox/index.ts +1 -0
- package/dist/astro-code-block/CodeBlock.astro +3 -0
- package/dist/astro-code-block/index.ts +1 -0
- package/dist/astro-code-editor/CodeEditor.astro +123 -0
- package/dist/astro-code-editor/index.ts +1 -0
- package/dist/astro-collapsible/Collapsible.astro +58 -0
- package/dist/astro-collapsible/CollapsibleContent.astro +21 -0
- package/dist/astro-collapsible/CollapsibleTrigger.astro +17 -0
- package/dist/astro-collapsible/index.ts +1 -0
- package/dist/astro-command/Command.astro +170 -0
- package/dist/astro-command/CommandEmpty.astro +17 -0
- package/dist/astro-command/CommandGroup.astro +25 -0
- package/dist/astro-command/CommandInput.astro +21 -0
- package/dist/astro-command/CommandItem.astro +26 -0
- package/dist/astro-command/CommandList.astro +17 -0
- package/dist/astro-command/CommandSeparator.astro +14 -0
- package/dist/astro-command/index.ts +1 -0
- package/dist/astro-command-input/CommandInput.astro +6 -0
- package/dist/astro-command-input/index.ts +1 -0
- package/dist/astro-content-protection/ContentProtection.astro +104 -0
- package/dist/astro-content-protection/index.ts +1 -0
- package/dist/astro-data-table/DataTable.astro +263 -0
- package/dist/astro-data-table/index.ts +1 -0
- package/dist/astro-date-picker/DatePicker.astro +398 -0
- package/dist/astro-date-picker/index.ts +1 -0
- package/dist/astro-device-frame/DeviceFrame.astro +44 -0
- package/dist/astro-device-frame/index.ts +1 -0
- package/dist/astro-dialog/Dialog.astro +138 -0
- package/dist/astro-dialog/DialogClose.astro +16 -0
- package/dist/astro-dialog/DialogContent.astro +24 -0
- package/dist/astro-dialog/DialogDescription.astro +15 -0
- package/dist/astro-dialog/DialogFooter.astro +14 -0
- package/dist/astro-dialog/DialogHeader.astro +14 -0
- package/dist/astro-dialog/DialogOverlay.astro +17 -0
- package/dist/astro-dialog/DialogTitle.astro +15 -0
- package/dist/astro-dialog/DialogTrigger.astro +18 -0
- package/dist/astro-dialog/index.ts +1 -0
- package/dist/astro-diff-viewer/DiffViewer.astro +371 -0
- package/dist/astro-diff-viewer/index.ts +1 -0
- package/dist/astro-dropdown-menu/DropdownMenu.astro +138 -0
- package/dist/astro-dropdown-menu/DropdownMenuContent.astro +20 -0
- package/dist/astro-dropdown-menu/DropdownMenuItem.astro +21 -0
- package/dist/astro-dropdown-menu/DropdownMenuLabel.astro +14 -0
- package/dist/astro-dropdown-menu/DropdownMenuSeparator.astro +14 -0
- package/dist/astro-dropdown-menu/DropdownMenuTrigger.astro +18 -0
- package/dist/astro-dropdown-menu/index.ts +1 -0
- package/dist/astro-emoji-picker/EmojiPicker.astro +255 -0
- package/dist/astro-emoji-picker/index.ts +1 -0
- package/dist/astro-feedback-dialog/FeedbackDialog.astro +152 -0
- package/dist/astro-feedback-dialog/index.ts +1 -0
- package/dist/astro-file-tree/astro-file-tree.astro +4 -0
- package/dist/astro-file-tree/index.ts +1 -0
- package/dist/astro-file-upload/FileUpload.astro +306 -0
- package/dist/astro-file-upload/index.ts +1 -0
- package/dist/astro-footer/Footer.astro +61 -0
- package/dist/astro-footer/index.ts +1 -0
- package/dist/astro-icon-system/astro-icon-system.astro +4 -0
- package/dist/astro-icon-system/index.ts +1 -0
- package/dist/astro-inline-editor/InlineEditor.astro +169 -0
- package/dist/astro-inline-editor/index.ts +1 -0
- package/dist/astro-input/Input.astro +49 -0
- package/dist/astro-input/index.ts +1 -0
- package/dist/astro-input-group/InputGroup.astro +29 -0
- package/dist/astro-input-group/InputGroupAddon.astro +14 -0
- package/dist/astro-input-group/InputGroupButton.astro +19 -0
- package/dist/astro-input-group/InputGroupText.astro +11 -0
- package/dist/astro-input-group/index.ts +1 -0
- package/dist/astro-install-prompt/InstallPrompt.astro +115 -0
- package/dist/astro-install-prompt/index.ts +1 -0
- package/dist/astro-keyboard-shortcut/KeyboardShortcut.astro +83 -0
- package/dist/astro-keyboard-shortcut/ShortcutBadge.astro +41 -0
- package/dist/astro-keyboard-shortcut/index.ts +1 -0
- package/dist/astro-language-selector/LanguageSelector.astro +247 -0
- package/dist/astro-language-selector/index.ts +1 -0
- package/dist/astro-link-card/LinkCard.astro +17 -0
- package/dist/astro-link-card/index.ts +1 -0
- package/dist/astro-markdown-renderer/MarkdownRenderer.astro +62 -0
- package/dist/astro-markdown-renderer/index.ts +1 -0
- package/dist/astro-mobile-nav/MobileNav.astro +84 -0
- package/dist/astro-mobile-nav/MobileNavContent.astro +29 -0
- package/dist/astro-mobile-nav/MobileNavLink.astro +16 -0
- package/dist/astro-mobile-nav/MobileNavTrigger.astro +57 -0
- package/dist/astro-mobile-nav/index.ts +1 -0
- package/dist/astro-navbar/Navbar.astro +49 -0
- package/dist/astro-navbar/index.ts +1 -0
- package/dist/astro-otp-input/OtpInput.astro +253 -0
- package/dist/astro-otp-input/index.ts +1 -0
- package/dist/astro-pagination/Pagination.astro +3 -0
- package/dist/astro-pagination/index.ts +1 -0
- package/dist/astro-payment/Payment.astro +19 -0
- package/dist/astro-payment/index.ts +1 -0
- package/dist/astro-popover/Popover.astro +87 -0
- package/dist/astro-popover/PopoverClose.astro +16 -0
- package/dist/astro-popover/PopoverContent.astro +23 -0
- package/dist/astro-popover/PopoverTrigger.astro +18 -0
- package/dist/astro-popover/index.ts +1 -0
- package/dist/astro-presence-indicator/PresenceIndicator.astro +26 -0
- package/dist/astro-presence-indicator/index.ts +1 -0
- package/dist/astro-progress-display/BadgeDisplay.astro +33 -0
- package/dist/astro-progress-display/ProgressBar.astro +27 -0
- package/dist/astro-progress-display/StatsGrid.astro +32 -0
- package/dist/astro-progress-display/index.ts +1 -0
- package/dist/astro-radio/RadioGroup.astro +111 -0
- package/dist/astro-radio/RadioItem.astro +36 -0
- package/dist/astro-radio/index.ts +1 -0
- package/dist/astro-reaction-bar/ReactionBar.astro +117 -0
- package/dist/astro-reaction-bar/index.ts +1 -0
- package/dist/astro-resizable-layout/ResizableDivider.astro +27 -0
- package/dist/astro-resizable-layout/ResizableLayout.astro +162 -0
- package/dist/astro-resizable-layout/ResizablePane.astro +28 -0
- package/dist/astro-resizable-layout/index.ts +11 -0
- package/dist/astro-rich-editor/RichEditor.astro +260 -0
- package/dist/astro-rich-editor/index.ts +25 -0
- package/dist/astro-search-bar/SearchBar.astro +140 -0
- package/dist/astro-search-bar/SearchResultItem.astro +16 -0
- package/dist/astro-search-bar/SearchResults.astro +17 -0
- package/dist/astro-search-bar/index.ts +1 -0
- package/dist/astro-select/Select.astro +165 -0
- package/dist/astro-select/SelectContent.astro +19 -0
- package/dist/astro-select/SelectItem.astro +42 -0
- package/dist/astro-select/SelectTrigger.astro +36 -0
- package/dist/astro-select/index.ts +1 -0
- package/dist/astro-sidebar/Sidebar.astro +64 -0
- package/dist/astro-sidebar/index.ts +1 -0
- package/dist/astro-skeleton/Skeleton.astro +39 -0
- package/dist/astro-skeleton/SkeletonText.astro +22 -0
- package/dist/astro-skeleton/index.ts +1 -0
- package/dist/astro-skip-to-content/SkipToContent.astro +3 -0
- package/dist/astro-skip-to-content/index.ts +1 -0
- package/dist/astro-slide-viewer/SlideViewer.astro +231 -0
- package/dist/astro-slide-viewer/index.ts +1 -0
- package/dist/astro-slider/index.ts +1 -0
- package/dist/astro-status-indicator/StatusIndicator.astro +31 -0
- package/dist/astro-status-indicator/index.ts +1 -0
- package/dist/astro-steps/Steps.astro +3 -0
- package/dist/astro-steps/index.ts +1 -0
- package/dist/astro-switch/Switch.astro +89 -0
- package/dist/astro-switch/index.ts +1 -0
- package/dist/astro-table-of-contents/TableOfContents.astro +53 -0
- package/dist/astro-table-of-contents/index.ts +1 -0
- package/dist/astro-tabs/Tabs.astro +96 -0
- package/dist/astro-tabs/TabsContent.astro +20 -0
- package/dist/astro-tabs/TabsList.astro +16 -0
- package/dist/astro-tabs/TabsTrigger.astro +24 -0
- package/dist/astro-tabs/index.ts +1 -0
- package/dist/astro-textarea/Textarea.astro +51 -0
- package/dist/astro-textarea/index.ts +1 -0
- package/dist/astro-theme/ThemeScript.astro +13 -0
- package/dist/astro-theme/ThemeToggle.astro +279 -0
- package/dist/astro-theme/index.ts +1 -0
- package/dist/astro-thread-view/ThreadView.astro +159 -0
- package/dist/astro-thread-view/index.ts +1 -0
- package/dist/astro-toast/Toast.astro +49 -0
- package/dist/astro-toast/Toaster.astro +142 -0
- package/dist/astro-toast/index.ts +1 -0
- package/dist/astro-tooltip/Tooltip.astro +95 -0
- package/dist/astro-tooltip/TooltipContent.astro +22 -0
- package/dist/astro-tooltip/TooltipTrigger.astro +16 -0
- package/dist/astro-tooltip/index.ts +1 -0
- package/dist/astro-version-selector/VersionSelector.astro +174 -0
- package/dist/astro-version-selector/index.ts +1 -0
- package/dist/astro-video-player/VideoPlayer.astro +153 -0
- package/dist/astro-video-player/index.ts +1 -0
- package/dist/auth/adapters/mock.ts +74 -0
- package/dist/auth/auth-machine.ts +120 -0
- package/dist/auth/index.ts +22 -0
- package/dist/auth/rbac.ts +44 -0
- package/dist/auth/types.ts +44 -0
- package/dist/avatar/avatar.styles.ts +47 -0
- package/dist/avatar/avatar.ts +73 -0
- package/dist/avatar/index.ts +15 -0
- package/dist/avatar-group/avatar-group.styles.ts +63 -0
- package/dist/avatar-group/avatar-group.ts +106 -0
- package/dist/avatar-group/index.ts +18 -0
- package/dist/badge/badge.styles.ts +24 -0
- package/dist/badge/badge.ts +48 -0
- package/dist/badge/index.ts +10 -0
- package/dist/bottom-nav/bottom-nav.styles.ts +18 -0
- package/dist/bottom-nav/bottom-nav.ts +33 -0
- package/dist/bottom-nav/index.ts +2 -0
- package/dist/breadcrumbs/breadcrumbs.styles.ts +20 -0
- package/dist/breadcrumbs/breadcrumbs.ts +72 -0
- package/dist/breadcrumbs/index.ts +8 -0
- package/dist/button/button.styles.ts +38 -0
- package/dist/button/button.ts +64 -0
- package/dist/button/index.ts +10 -0
- package/dist/calendar/calendar.styles.ts +21 -0
- package/dist/calendar/calendar.ts +202 -0
- package/dist/calendar/index.ts +9 -0
- package/dist/callout/callout.ts +1 -0
- package/dist/callout/index.ts +1 -0
- package/dist/card/card.styles.ts +55 -0
- package/dist/card/card.ts +45 -0
- package/dist/card/index.ts +20 -0
- package/dist/card-grid/card-grid.ts +9 -0
- package/dist/card-grid/index.ts +1 -0
- package/dist/carousel/index.ts +1 -0
- package/dist/charts/axis.ts +50 -0
- package/dist/charts/chart.ts +73 -0
- package/dist/charts/colorblind.ts +100 -0
- package/dist/charts/data.ts +72 -0
- package/dist/charts/geometry.ts +54 -0
- package/dist/charts/index.ts +61 -0
- package/dist/charts/scales.ts +151 -0
- package/dist/checkbox/checkbox.styles.ts +33 -0
- package/dist/checkbox/checkbox.ts +73 -0
- package/dist/checkbox/index.ts +10 -0
- package/dist/code-block/code-block.ts +1 -0
- package/dist/code-block/index.ts +1 -0
- package/dist/code-editor/code-editor.styles.ts +32 -0
- package/dist/code-editor/code-editor.ts +140 -0
- package/dist/code-editor/index.ts +9 -0
- package/dist/collapsible/collapsible.styles.ts +14 -0
- package/dist/collapsible/collapsible.ts +93 -0
- package/dist/collapsible/index.ts +7 -0
- package/dist/command/command.styles.ts +27 -0
- package/dist/command/command.ts +179 -0
- package/dist/command/index.ts +14 -0
- package/dist/command-input/command-input.ts +176 -0
- package/dist/command-input/index.ts +1 -0
- package/dist/content-protection/content-protection.styles.ts +9 -0
- package/dist/content-protection/content-protection.ts +68 -0
- package/dist/content-protection/index.ts +8 -0
- package/dist/data-table/data-table.styles.ts +55 -0
- package/dist/data-table/data-table.ts +183 -0
- package/dist/data-table/index.ts +15 -0
- package/dist/date-picker/date-picker.styles.ts +31 -0
- package/dist/date-picker/date-picker.ts +333 -0
- package/dist/date-picker/index.ts +18 -0
- package/dist/device-frame/device-frame.styles.ts +21 -0
- package/dist/device-frame/device-frame.ts +112 -0
- package/dist/device-frame/index.ts +10 -0
- package/dist/dialog/dialog.styles.ts +8 -0
- package/dist/dialog/dialog.ts +133 -0
- package/dist/dialog/index.ts +8 -0
- package/dist/diff-viewer/diff-viewer.styles.ts +124 -0
- package/dist/diff-viewer/diff-viewer.ts +255 -0
- package/dist/diff-viewer/index.ts +20 -0
- package/dist/dropdown-menu/dropdown-menu.styles.ts +9 -0
- package/dist/dropdown-menu/dropdown-menu.ts +139 -0
- package/dist/dropdown-menu/index.ts +9 -0
- package/dist/emoji-picker/emoji-data.ts +282 -0
- package/dist/emoji-picker/emoji-picker.styles.ts +32 -0
- package/dist/emoji-picker/emoji-picker.ts +165 -0
- package/dist/emoji-picker/index.ts +25 -0
- package/dist/feedback-dialog/feedback-dialog.styles.ts +15 -0
- package/dist/feedback-dialog/feedback-dialog.ts +147 -0
- package/dist/feedback-dialog/index.ts +11 -0
- package/dist/file-upload/file-upload.styles.ts +30 -0
- package/dist/file-upload/file-upload.ts +260 -0
- package/dist/file-upload/index.ts +19 -0
- package/dist/footer/footer.styles.ts +5 -0
- package/dist/footer/footer.ts +32 -0
- package/dist/footer/index.ts +9 -0
- package/dist/index.ts +77 -0
- package/dist/inline-editor/index.ts +13 -0
- package/dist/inline-editor/inline-editor.styles.ts +42 -0
- package/dist/inline-editor/inline-editor.ts +96 -0
- package/dist/input/index.ts +9 -0
- package/dist/input/input.styles.ts +15 -0
- package/dist/input/input.ts +84 -0
- package/dist/input-group/index.ts +13 -0
- package/dist/input-group/input-group.styles.ts +50 -0
- package/dist/input-group/input-group.ts +44 -0
- package/dist/install-prompt/index.ts +9 -0
- package/dist/install-prompt/install-prompt.styles.ts +5 -0
- package/dist/install-prompt/install-prompt.ts +68 -0
- package/dist/keyboard-shortcut/index.ts +12 -0
- package/dist/keyboard-shortcut/keyboard-shortcut.styles.ts +8 -0
- package/dist/keyboard-shortcut/keyboard-shortcut.ts +153 -0
- package/dist/language-selector/index.ts +8 -0
- package/dist/language-selector/language-selector.styles.ts +28 -0
- package/dist/language-selector/language-selector.ts +149 -0
- package/dist/link-card/index.ts +1 -0
- package/dist/link-card/link-card.ts +9 -0
- package/dist/markdown-renderer/index.ts +8 -0
- package/dist/markdown-renderer/markdown-renderer.styles.ts +31 -0
- package/dist/markdown-renderer/markdown-renderer.ts +251 -0
- package/dist/mobile-nav/index.ts +14 -0
- package/dist/mobile-nav/mobile-nav.styles.ts +39 -0
- package/dist/mobile-nav/mobile-nav.ts +74 -0
- package/dist/navbar/index.ts +9 -0
- package/dist/navbar/navbar.styles.ts +29 -0
- package/dist/navbar/navbar.ts +39 -0
- package/dist/otp-input/index.ts +13 -0
- package/dist/otp-input/otp-input.styles.ts +51 -0
- package/dist/otp-input/otp-input.ts +198 -0
- package/dist/pagination/index.ts +1 -0
- package/dist/payment/index.ts +1 -0
- package/dist/payment/payment.ts +16 -0
- package/dist/popover/index.ts +7 -0
- package/dist/popover/popover.styles.ts +16 -0
- package/dist/popover/popover.ts +89 -0
- package/dist/presence-indicator/index.ts +14 -0
- package/dist/presence-indicator/presence-indicator.styles.ts +29 -0
- package/dist/presence-indicator/presence-indicator.ts +63 -0
- package/dist/progress-display/index.ts +15 -0
- package/dist/progress-display/progress-display.styles.ts +72 -0
- package/dist/progress-display/progress-display.ts +60 -0
- package/dist/radio/index.ts +8 -0
- package/dist/radio/radio.styles.ts +34 -0
- package/dist/radio/radio.ts +70 -0
- package/dist/reaction-bar/index.ts +14 -0
- package/dist/reaction-bar/reaction-bar.styles.ts +23 -0
- package/dist/reaction-bar/reaction-bar.ts +87 -0
- package/dist/resizable-layout/index.ts +12 -0
- package/dist/resizable-layout/resizable-layout.styles.ts +50 -0
- package/dist/resizable-layout/resizable-layout.ts +139 -0
- package/dist/rich-editor/editor.ts +342 -0
- package/dist/rich-editor/emoji.ts +175 -0
- package/dist/rich-editor/history.ts +79 -0
- package/dist/rich-editor/index.ts +106 -0
- package/dist/rich-editor/markdown-shortcuts.ts +248 -0
- package/dist/rich-editor/mentions.ts +162 -0
- package/dist/rich-editor/model.ts +206 -0
- package/dist/rich-editor/operations.ts +772 -0
- package/dist/rich-editor/selection.ts +157 -0
- package/dist/rich-editor/serialization.ts +711 -0
- package/dist/rich-editor/slash-commands.ts +212 -0
- package/dist/search-bar/index.ts +7 -0
- package/dist/search-bar/search-bar.styles.ts +29 -0
- package/dist/search-bar/search-bar.ts +130 -0
- package/dist/select/index.ts +13 -0
- package/dist/select/select.styles.ts +52 -0
- package/dist/select/select.ts +152 -0
- package/dist/shared/a11y.ts +33 -0
- package/dist/shared/aria.ts +30 -0
- package/dist/shared/cn.ts +35 -0
- package/dist/shared/cva.ts +79 -0
- package/dist/shared/engine-adapter.ts +10 -0
- package/dist/shared/focus-trap.ts +123 -0
- package/dist/shared/index.ts +60 -0
- package/dist/shared/keyboard.ts +36 -0
- package/dist/shared/live-region.ts +90 -0
- package/dist/shared/motion.ts +15 -0
- package/dist/shared/skip-link.ts +35 -0
- package/dist/shared/state-machine.ts +57 -0
- package/dist/shared/tokens.ts +16 -0
- package/dist/shared/types.ts +45 -0
- package/dist/shared/variants.ts +17 -0
- package/dist/sidebar/index.ts +9 -0
- package/dist/sidebar/sidebar.styles.ts +27 -0
- package/dist/sidebar/sidebar.ts +59 -0
- package/dist/skeleton/index.ts +8 -0
- package/dist/skeleton/skeleton.styles.ts +16 -0
- package/dist/skeleton/skeleton.ts +39 -0
- package/dist/skip-to-content/index.ts +1 -0
- package/dist/skip-to-content/skip-to-content.ts +1 -0
- package/dist/slide-viewer/index.ts +16 -0
- package/dist/slide-viewer/slide-viewer.styles.ts +57 -0
- package/dist/slide-viewer/slide-viewer.ts +152 -0
- package/dist/slider/index.ts +1 -0
- package/dist/slider/slider.ts +2 -0
- package/dist/status-indicator/index.ts +15 -0
- package/dist/status-indicator/status-indicator.styles.ts +41 -0
- package/dist/status-indicator/status-indicator.ts +66 -0
- package/dist/steps/index.ts +1 -0
- package/dist/steps/steps.ts +1 -0
- package/dist/switch/index.ts +7 -0
- package/dist/switch/switch.styles.ts +55 -0
- package/dist/switch/switch.ts +63 -0
- package/dist/table-of-contents/index.ts +1 -0
- package/dist/table-of-contents/table-of-contents.ts +37 -0
- package/dist/tabs/index.ts +8 -0
- package/dist/tabs/tabs.styles.ts +9 -0
- package/dist/tabs/tabs.ts +133 -0
- package/dist/textarea/index.ts +7 -0
- package/dist/textarea/textarea.styles.ts +15 -0
- package/dist/textarea/textarea.ts +59 -0
- package/dist/theme/dom-adapters.ts +60 -0
- package/dist/theme/index.ts +18 -0
- package/dist/theme/theme-machine.ts +130 -0
- package/dist/theme/theme-script.ts +18 -0
- package/dist/thread-view/index.ts +26 -0
- package/dist/thread-view/thread-view.styles.ts +35 -0
- package/dist/thread-view/thread-view.ts +176 -0
- package/dist/toast/index.ts +13 -0
- package/dist/toast/toast.styles.ts +19 -0
- package/dist/toast/toast.ts +203 -0
- package/dist/tooltip/index.ts +7 -0
- package/dist/tooltip/tooltip.styles.ts +16 -0
- package/dist/tooltip/tooltip.ts +109 -0
- package/dist/version-selector/index.ts +12 -0
- package/dist/version-selector/version-selector.styles.ts +41 -0
- package/dist/version-selector/version-selector.ts +136 -0
- package/dist/video-player/index.ts +12 -0
- package/dist/video-player/video-player.styles.ts +42 -0
- package/dist/video-player/video-player.ts +100 -0
- package/package.json +20 -19
- package/src/index.ts +0 -94
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { AuthAdapter, User } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mock auth adapter for testing and development.
|
|
5
|
+
* No external dependencies. Stores state in memory.
|
|
6
|
+
*/
|
|
7
|
+
export function createMockAdapter(initialUser?: User): AuthAdapter {
|
|
8
|
+
let currentUser: User | null = initialUser ?? null
|
|
9
|
+
const listeners = new Set<(user: User | null) => void>()
|
|
10
|
+
|
|
11
|
+
function notify() {
|
|
12
|
+
for (const fn of listeners) {
|
|
13
|
+
fn(currentUser)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
async signIn(email, _password) {
|
|
19
|
+
currentUser = {
|
|
20
|
+
uid: 'mock-' + email,
|
|
21
|
+
email,
|
|
22
|
+
displayName: email.split('@')[0],
|
|
23
|
+
photoURL: null,
|
|
24
|
+
roles: ['student'],
|
|
25
|
+
}
|
|
26
|
+
notify()
|
|
27
|
+
return currentUser
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
async signInWithOAuth(_provider) {
|
|
31
|
+
currentUser = {
|
|
32
|
+
uid: 'mock-oauth',
|
|
33
|
+
email: 'oauth@example.com',
|
|
34
|
+
displayName: 'OAuth User',
|
|
35
|
+
photoURL: null,
|
|
36
|
+
roles: ['student'],
|
|
37
|
+
}
|
|
38
|
+
notify()
|
|
39
|
+
return currentUser
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async signUp(email, _password, displayName) {
|
|
43
|
+
currentUser = {
|
|
44
|
+
uid: 'mock-' + email,
|
|
45
|
+
email,
|
|
46
|
+
displayName,
|
|
47
|
+
photoURL: null,
|
|
48
|
+
roles: ['student'],
|
|
49
|
+
}
|
|
50
|
+
notify()
|
|
51
|
+
return currentUser
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
async signOut() {
|
|
55
|
+
currentUser = null
|
|
56
|
+
notify()
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
async resetPassword(_email) {
|
|
60
|
+
// no-op in mock
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async getToken() {
|
|
64
|
+
return currentUser ? 'mock-token-' + currentUser.uid : null
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
onAuthStateChange(callback) {
|
|
68
|
+
listeners.add(callback)
|
|
69
|
+
// Fire immediately with current state
|
|
70
|
+
callback(currentUser)
|
|
71
|
+
return () => { listeners.delete(callback) }
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { User, AuthState, AuthStatus, AuthConfig, AuthAdapter, OAuthProvider } from './types.js'
|
|
2
|
+
|
|
3
|
+
export interface AuthAPI {
|
|
4
|
+
getState(): AuthState
|
|
5
|
+
signIn(email: string, password: string): Promise<User>
|
|
6
|
+
signInWithOAuth(provider: OAuthProvider): Promise<User>
|
|
7
|
+
signUp(email: string, password: string, displayName: string): Promise<User>
|
|
8
|
+
signOut(): Promise<void>
|
|
9
|
+
resetPassword(email: string): Promise<void>
|
|
10
|
+
getToken(): Promise<string | null>
|
|
11
|
+
subscribe(fn: (state: AuthState) => void): () => void
|
|
12
|
+
destroy(): void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createAuth(
|
|
16
|
+
adapter: AuthAdapter,
|
|
17
|
+
config: Omit<AuthConfig, 'adapter'> = {},
|
|
18
|
+
): AuthAPI {
|
|
19
|
+
const listeners = new Set<(state: AuthState) => void>()
|
|
20
|
+
let state: AuthState = { user: null, status: 'loading' }
|
|
21
|
+
let unsubAuth: (() => void) | null = null
|
|
22
|
+
let tokenRefreshTimer: ReturnType<typeof setInterval> | null = null
|
|
23
|
+
|
|
24
|
+
const { tokenRefreshInterval = 50, testMode = false, testUser } = config
|
|
25
|
+
|
|
26
|
+
function setState(newState: AuthState) {
|
|
27
|
+
state = newState
|
|
28
|
+
for (const fn of listeners) {
|
|
29
|
+
fn(state)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function setUser(user: User | null) {
|
|
34
|
+
setState({
|
|
35
|
+
user,
|
|
36
|
+
status: user ? 'authenticated' : 'unauthenticated',
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Start token refresh timer
|
|
41
|
+
function startTokenRefresh() {
|
|
42
|
+
if (tokenRefreshTimer) clearInterval(tokenRefreshTimer)
|
|
43
|
+
tokenRefreshTimer = setInterval(
|
|
44
|
+
() => { adapter.getToken().catch(() => {}) },
|
|
45
|
+
tokenRefreshInterval * 60 * 1000,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Initialize
|
|
50
|
+
if (testMode && testUser) {
|
|
51
|
+
setUser(testUser)
|
|
52
|
+
} else {
|
|
53
|
+
unsubAuth = adapter.onAuthStateChange((user) => {
|
|
54
|
+
setUser(user)
|
|
55
|
+
if (user) {
|
|
56
|
+
startTokenRefresh()
|
|
57
|
+
} else if (tokenRefreshTimer) {
|
|
58
|
+
clearInterval(tokenRefreshTimer)
|
|
59
|
+
tokenRefreshTimer = null
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
getState() {
|
|
66
|
+
return state
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
async signIn(email, password) {
|
|
70
|
+
const user = await adapter.signIn(email, password)
|
|
71
|
+
setUser(user)
|
|
72
|
+
startTokenRefresh()
|
|
73
|
+
return user
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async signInWithOAuth(provider) {
|
|
77
|
+
const user = await adapter.signInWithOAuth(provider)
|
|
78
|
+
setUser(user)
|
|
79
|
+
startTokenRefresh()
|
|
80
|
+
return user
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async signUp(email, password, displayName) {
|
|
84
|
+
const user = await adapter.signUp(email, password, displayName)
|
|
85
|
+
setUser(user)
|
|
86
|
+
startTokenRefresh()
|
|
87
|
+
return user
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
async signOut() {
|
|
91
|
+
await adapter.signOut()
|
|
92
|
+
if (tokenRefreshTimer) {
|
|
93
|
+
clearInterval(tokenRefreshTimer)
|
|
94
|
+
tokenRefreshTimer = null
|
|
95
|
+
}
|
|
96
|
+
setUser(null)
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
async resetPassword(email) {
|
|
100
|
+
await adapter.resetPassword(email)
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
async getToken() {
|
|
104
|
+
return adapter.getToken()
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
subscribe(fn) {
|
|
108
|
+
listeners.add(fn)
|
|
109
|
+
return () => { listeners.delete(fn) }
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
destroy() {
|
|
113
|
+
listeners.clear()
|
|
114
|
+
unsubAuth?.()
|
|
115
|
+
if (tokenRefreshTimer) {
|
|
116
|
+
clearInterval(tokenRefreshTimer)
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
User,
|
|
3
|
+
AuthState,
|
|
4
|
+
AuthStatus,
|
|
5
|
+
OAuthProvider,
|
|
6
|
+
AuthConfig,
|
|
7
|
+
AuthAdapter,
|
|
8
|
+
} from './types.js'
|
|
9
|
+
|
|
10
|
+
export { createAuth, type AuthAPI } from './auth-machine.js'
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
hasRole,
|
|
14
|
+
hasAnyRole,
|
|
15
|
+
hasAllRoles,
|
|
16
|
+
canAccessAdmin,
|
|
17
|
+
canAccessReviewer,
|
|
18
|
+
getDefaultPortal,
|
|
19
|
+
getAssignableRoles,
|
|
20
|
+
} from './rbac.js'
|
|
21
|
+
|
|
22
|
+
export { createMockAdapter } from './adapters/mock.js'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { User } from './types.js'
|
|
2
|
+
|
|
3
|
+
/** Check if user has a specific role */
|
|
4
|
+
export function hasRole(user: User | null, role: string): boolean {
|
|
5
|
+
return user?.roles?.includes(role) ?? false
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Check if user has any of the specified roles */
|
|
9
|
+
export function hasAnyRole(user: User | null, roles: string[]): boolean {
|
|
10
|
+
if (!user?.roles) return false
|
|
11
|
+
return roles.some((role) => user.roles.includes(role))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Check if user has all of the specified roles */
|
|
15
|
+
export function hasAllRoles(user: User | null, roles: string[]): boolean {
|
|
16
|
+
if (!user?.roles) return false
|
|
17
|
+
return roles.every((role) => user.roles.includes(role))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Convenience role checks */
|
|
21
|
+
export function canAccessAdmin(user: User | null): boolean {
|
|
22
|
+
return hasRole(user, 'admin')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function canAccessReviewer(user: User | null): boolean {
|
|
26
|
+
return hasAnyRole(user, ['admin', 'reviewer'])
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Get the default portal URL based on highest-privilege role */
|
|
30
|
+
export function getDefaultPortal(roles: string[]): string {
|
|
31
|
+
if (roles.includes('admin')) return '/admin'
|
|
32
|
+
if (roles.includes('reviewer')) return '/reviewer'
|
|
33
|
+
if (roles.includes('parent')) return '/parent'
|
|
34
|
+
if (roles.includes('student')) return '/student'
|
|
35
|
+
return '/'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Get roles that the given user can assign to others */
|
|
39
|
+
export function getAssignableRoles(user: User | null): string[] {
|
|
40
|
+
if (!user) return []
|
|
41
|
+
if (hasRole(user, 'admin')) return ['admin', 'reviewer', 'parent', 'student']
|
|
42
|
+
if (hasRole(user, 'reviewer')) return ['student']
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** User object — framework-agnostic, provider-agnostic */
|
|
2
|
+
export interface User {
|
|
3
|
+
uid: string
|
|
4
|
+
email: string | null
|
|
5
|
+
displayName: string | null
|
|
6
|
+
photoURL: string | null
|
|
7
|
+
roles: string[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Auth state */
|
|
11
|
+
export type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated'
|
|
12
|
+
|
|
13
|
+
export interface AuthState {
|
|
14
|
+
user: User | null
|
|
15
|
+
status: AuthStatus
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** OAuth providers */
|
|
19
|
+
export type OAuthProvider = string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* AuthAdapter — interface implemented by provider adapters (e.g. Firebase, Supabase, Auth0).
|
|
23
|
+
* Consumers must provide an implementation of this adapter to the AuthProvider.
|
|
24
|
+
*/
|
|
25
|
+
export interface AuthAdapter {
|
|
26
|
+
signIn(email: string, password: string): Promise<User>
|
|
27
|
+
signInWithOAuth(provider: OAuthProvider): Promise<User>
|
|
28
|
+
signUp(email: string, password: string, displayName: string): Promise<User>
|
|
29
|
+
signOut(): Promise<void>
|
|
30
|
+
resetPassword(email: string): Promise<void>
|
|
31
|
+
getToken(): Promise<string | null>
|
|
32
|
+
onAuthStateChange(callback: (user: User | null) => void): () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AuthConfig {
|
|
36
|
+
/** The adapter implementation for your specific auth provider (Supabase, Firebase, Auth0, Custom, etc.) */
|
|
37
|
+
adapter: AuthAdapter
|
|
38
|
+
/** Token refresh interval in minutes. Default: 50 */
|
|
39
|
+
tokenRefreshInterval?: number
|
|
40
|
+
/** Enable E2E test mode with mock user */
|
|
41
|
+
testMode?: boolean
|
|
42
|
+
/** Mock user for test mode */
|
|
43
|
+
testUser?: User
|
|
44
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
import type { TokenContract } from '../shared/index.ts'
|
|
3
|
+
|
|
4
|
+
export const avatarTokens: TokenContract = {
|
|
5
|
+
name: 'avatar',
|
|
6
|
+
tokens: {
|
|
7
|
+
bg: { variable: '--rfr-avatar-bg', fallback: 'hsl(var(--muted))' },
|
|
8
|
+
fg: { variable: '--rfr-avatar-fg', fallback: 'hsl(var(--muted-foreground))' },
|
|
9
|
+
border: { variable: '--rfr-avatar-border', fallback: 'hsl(var(--border))' },
|
|
10
|
+
},
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const avatarVariants = cva({
|
|
14
|
+
base: 'relative flex shrink-0 overflow-hidden rounded-full',
|
|
15
|
+
variants: {
|
|
16
|
+
size: {
|
|
17
|
+
xs: 'h-6 w-6',
|
|
18
|
+
sm: 'h-8 w-8',
|
|
19
|
+
md: 'h-10 w-10',
|
|
20
|
+
lg: 'h-12 w-12',
|
|
21
|
+
xl: 'h-16 w-16',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
size: 'md',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const avatarImageVariants = cva({
|
|
30
|
+
base: 'aspect-square h-full w-full object-cover',
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const avatarFallbackVariants = cva({
|
|
34
|
+
base: 'flex h-full w-full items-center justify-center rounded-full bg-muted text-muted-foreground',
|
|
35
|
+
variants: {
|
|
36
|
+
size: {
|
|
37
|
+
xs: 'text-xs',
|
|
38
|
+
sm: 'text-xs',
|
|
39
|
+
md: 'text-sm',
|
|
40
|
+
lg: 'text-base',
|
|
41
|
+
xl: 'text-lg',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
size: 'md',
|
|
46
|
+
},
|
|
47
|
+
})
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
4
|
+
|
|
5
|
+
export type AvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
|
|
6
|
+
|
|
7
|
+
export interface AvatarProps {
|
|
8
|
+
src?: string
|
|
9
|
+
alt?: string
|
|
10
|
+
fallback?: string
|
|
11
|
+
size?: AvatarSize
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AvatarAPI {
|
|
15
|
+
/** ARIA attributes to spread on the root element */
|
|
16
|
+
ariaProps: Partial<AccessibilityProps>
|
|
17
|
+
/** Data attributes for CSS styling hooks */
|
|
18
|
+
dataAttributes: Record<string, string>
|
|
19
|
+
/** Image ARIA props */
|
|
20
|
+
imageProps: {
|
|
21
|
+
alt: string
|
|
22
|
+
role: string
|
|
23
|
+
}
|
|
24
|
+
/** Fallback text (initials) */
|
|
25
|
+
fallbackText: string
|
|
26
|
+
/** Current state */
|
|
27
|
+
state: {
|
|
28
|
+
size: AvatarSize
|
|
29
|
+
hasSrc: boolean
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract initials from a name or fallback string.
|
|
35
|
+
* Takes first letter of first two words, uppercased.
|
|
36
|
+
*/
|
|
37
|
+
export function getInitials(name: string): string {
|
|
38
|
+
const parts = name.trim().split(/\s+/)
|
|
39
|
+
if (parts.length === 0 || parts[0] === '') return ''
|
|
40
|
+
if (parts.length === 1) return parts[0].charAt(0).toUpperCase()
|
|
41
|
+
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createAvatar(props: AvatarProps = {}): AvatarAPI {
|
|
45
|
+
const { src, alt = '', fallback = '', size = 'md' } = props
|
|
46
|
+
|
|
47
|
+
const ariaProps: Partial<AccessibilityProps> = {
|
|
48
|
+
role: 'img',
|
|
49
|
+
}
|
|
50
|
+
if (alt) {
|
|
51
|
+
ariaProps['aria-label'] = alt
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const fallbackText = fallback ? getInitials(fallback) : (alt ? getInitials(alt) : '')
|
|
55
|
+
|
|
56
|
+
const dataAttributes: Record<string, string> = {
|
|
57
|
+
'data-slot': 'avatar',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
ariaProps,
|
|
62
|
+
dataAttributes,
|
|
63
|
+
imageProps: {
|
|
64
|
+
alt,
|
|
65
|
+
role: 'img',
|
|
66
|
+
},
|
|
67
|
+
fallbackText,
|
|
68
|
+
state: {
|
|
69
|
+
size,
|
|
70
|
+
hasSrc: !!src,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createAvatar,
|
|
3
|
+
getInitials,
|
|
4
|
+
type AvatarProps,
|
|
5
|
+
type AvatarAPI,
|
|
6
|
+
type AvatarSize,
|
|
7
|
+
type AvatarLoadingStatus,
|
|
8
|
+
} from './avatar.js'
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
avatarVariants,
|
|
12
|
+
avatarImageVariants,
|
|
13
|
+
avatarFallbackVariants,
|
|
14
|
+
avatarTokens,
|
|
15
|
+
} from './avatar.styles.js'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
export const avatarGroupStyles =
|
|
4
|
+
'flex items-center -space-x-2'
|
|
5
|
+
|
|
6
|
+
export const avatarVariants = cva({
|
|
7
|
+
base: 'relative inline-flex items-center justify-center rounded-full border-2 border-background bg-muted text-muted-foreground font-medium overflow-hidden ring-2 ring-background',
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
xs: 'h-6 w-6 text-[10px]',
|
|
11
|
+
sm: 'h-8 w-8 text-xs',
|
|
12
|
+
md: 'h-10 w-10 text-sm',
|
|
13
|
+
lg: 'h-12 w-12 text-base',
|
|
14
|
+
xl: 'h-16 w-16 text-xl',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
size: 'md',
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const avatarOverflowBadgeVariants = cva({
|
|
23
|
+
base: 'relative inline-flex items-center justify-center rounded-full border-2 border-background bg-muted text-muted-foreground font-medium ring-2 ring-background',
|
|
24
|
+
variants: {
|
|
25
|
+
size: {
|
|
26
|
+
xs: 'h-6 w-6 text-[10px]',
|
|
27
|
+
sm: 'h-8 w-8 text-xs',
|
|
28
|
+
md: 'h-10 w-10 text-sm',
|
|
29
|
+
lg: 'h-12 w-12 text-base',
|
|
30
|
+
xl: 'h-16 w-16 text-xl',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: {
|
|
34
|
+
size: 'md',
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const avatarImageStyles =
|
|
39
|
+
'h-full w-full object-cover'
|
|
40
|
+
|
|
41
|
+
export const avatarPresenceDotVariants = cva({
|
|
42
|
+
base: 'absolute bottom-0 right-0 rounded-full border-2 border-background',
|
|
43
|
+
variants: {
|
|
44
|
+
size: {
|
|
45
|
+
xs: 'h-2 w-2',
|
|
46
|
+
sm: 'h-2.5 w-2.5',
|
|
47
|
+
md: 'h-3 w-3',
|
|
48
|
+
lg: 'h-3.5 w-3.5',
|
|
49
|
+
xl: 'h-4 w-4',
|
|
50
|
+
},
|
|
51
|
+
status: {
|
|
52
|
+
online: 'bg-green-500',
|
|
53
|
+
offline: 'bg-gray-400',
|
|
54
|
+
away: 'bg-yellow-500',
|
|
55
|
+
busy: 'bg-red-500',
|
|
56
|
+
dnd: 'bg-red-500',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
size: 'md',
|
|
61
|
+
status: 'offline',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../shared/index.ts'
|
|
2
|
+
import { generateId } from '../shared/index.ts'
|
|
3
|
+
|
|
4
|
+
export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
5
|
+
export type PresenceStatus = 'online' | 'offline' | 'away' | 'busy' | 'dnd'
|
|
6
|
+
|
|
7
|
+
export interface AvatarUser {
|
|
8
|
+
/** Unique identifier */
|
|
9
|
+
id: string
|
|
10
|
+
/** Display name */
|
|
11
|
+
name: string
|
|
12
|
+
/** Avatar image URL */
|
|
13
|
+
src?: string
|
|
14
|
+
/** Online presence status */
|
|
15
|
+
status?: PresenceStatus
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AvatarGroupProps {
|
|
19
|
+
/** Array of users to display */
|
|
20
|
+
users: AvatarUser[]
|
|
21
|
+
/** Maximum number of visible avatars */
|
|
22
|
+
max?: number
|
|
23
|
+
/** Avatar size */
|
|
24
|
+
size?: AvatarSize
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface AvatarGroupAPI {
|
|
28
|
+
/** Users that are visible (within max limit) */
|
|
29
|
+
visibleUsers: AvatarUser[]
|
|
30
|
+
/** Number of overflow users */
|
|
31
|
+
overflowCount: number
|
|
32
|
+
/** All overflow users (for tooltip/popup) */
|
|
33
|
+
overflowUsers: AvatarUser[]
|
|
34
|
+
/** ARIA props for the group container */
|
|
35
|
+
ariaProps: Partial<AccessibilityProps> & Record<string, unknown>
|
|
36
|
+
/** Get ARIA props for an individual avatar */
|
|
37
|
+
getAvatarAriaProps(user: AvatarUser): Record<string, unknown>
|
|
38
|
+
/** Get initials from a user's name */
|
|
39
|
+
getInitials(name: string): string
|
|
40
|
+
/** Get the overflow badge ARIA props */
|
|
41
|
+
overflowBadgeProps: Record<string, unknown>
|
|
42
|
+
/** Generated IDs */
|
|
43
|
+
ids: {
|
|
44
|
+
group: string
|
|
45
|
+
label: string
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const AVATAR_SIZES: Record<AvatarSize, { width: number; fontSize: number }> = {
|
|
50
|
+
xs: { width: 24, fontSize: 10 },
|
|
51
|
+
sm: { width: 32, fontSize: 12 },
|
|
52
|
+
md: { width: 40, fontSize: 14 },
|
|
53
|
+
lg: { width: 48, fontSize: 16 },
|
|
54
|
+
xl: { width: 64, fontSize: 20 },
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getInitials(name: string): string {
|
|
58
|
+
const parts = name.trim().split(/\s+/)
|
|
59
|
+
if (parts.length === 0) return ''
|
|
60
|
+
if (parts.length === 1) return parts[0].charAt(0).toUpperCase()
|
|
61
|
+
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createAvatarGroup(props: AvatarGroupProps): AvatarGroupAPI {
|
|
65
|
+
const { users, max, size = 'md' } = props
|
|
66
|
+
|
|
67
|
+
const visibleUsers = max && max > 0 ? users.slice(0, max) : users
|
|
68
|
+
const overflowUsers = max && max > 0 ? users.slice(max) : []
|
|
69
|
+
const overflowCount = overflowUsers.length
|
|
70
|
+
|
|
71
|
+
const groupId = generateId('rfr-avatar-group')
|
|
72
|
+
const labelId = generateId('rfr-avatar-group-label')
|
|
73
|
+
|
|
74
|
+
const ariaProps: Partial<AccessibilityProps> & Record<string, unknown> = {
|
|
75
|
+
role: 'group',
|
|
76
|
+
'aria-label': `${users.length} users`,
|
|
77
|
+
id: groupId,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getAvatarAriaProps(user: AvatarUser): Record<string, unknown> {
|
|
81
|
+
const label = user.status ? `${user.name} (${user.status})` : user.name
|
|
82
|
+
return {
|
|
83
|
+
role: 'img',
|
|
84
|
+
'aria-label': label,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const overflowBadgeProps: Record<string, unknown> = {
|
|
89
|
+
role: 'button',
|
|
90
|
+
'aria-label': `${overflowCount} more users`,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
visibleUsers,
|
|
95
|
+
overflowCount,
|
|
96
|
+
overflowUsers,
|
|
97
|
+
ariaProps,
|
|
98
|
+
getAvatarAriaProps,
|
|
99
|
+
getInitials,
|
|
100
|
+
overflowBadgeProps,
|
|
101
|
+
ids: {
|
|
102
|
+
group: groupId,
|
|
103
|
+
label: labelId,
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createAvatarGroup,
|
|
3
|
+
getInitials,
|
|
4
|
+
AVATAR_SIZES,
|
|
5
|
+
type AvatarGroupProps,
|
|
6
|
+
type AvatarGroupAPI,
|
|
7
|
+
type AvatarUser,
|
|
8
|
+
type AvatarSize,
|
|
9
|
+
type PresenceStatus,
|
|
10
|
+
} from './avatar-group.js'
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
avatarGroupStyles,
|
|
14
|
+
avatarVariants,
|
|
15
|
+
avatarOverflowBadgeVariants,
|
|
16
|
+
avatarImageStyles,
|
|
17
|
+
avatarPresenceDotVariants,
|
|
18
|
+
} from './avatar-group.styles.js'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cva } from '../shared/index.ts'
|
|
2
|
+
|
|
3
|
+
export const badgeVariants = cva({
|
|
4
|
+
base: 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
5
|
+
variants: {
|
|
6
|
+
variant: {
|
|
7
|
+
default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
8
|
+
primary: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
9
|
+
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
10
|
+
destructive: 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80 font-semibold',
|
|
11
|
+
outline: 'text-foreground',
|
|
12
|
+
success: 'border-transparent bg-green-500 text-white shadow hover:bg-green-500/80 font-semibold',
|
|
13
|
+
warning: 'border-transparent bg-yellow-500 text-white shadow hover:bg-yellow-500/80 font-semibold',
|
|
14
|
+
},
|
|
15
|
+
size: {
|
|
16
|
+
sm: 'px-2 py-0 text-[10px]',
|
|
17
|
+
md: 'px-2.5 py-0.5 text-xs',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default',
|
|
22
|
+
size: 'md',
|
|
23
|
+
},
|
|
24
|
+
})
|