@inui/design-system 0.0.0-stage → 1.22.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/README.md +360 -2
- package/dist/components/ui/accordion.d.ts +44 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/accordion.js +86 -0
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/ui/ai-avatar.d.ts +46 -0
- package/dist/components/ui/ai-avatar.d.ts.map +1 -0
- package/dist/components/ui/ai-avatar.js +43 -0
- package/dist/components/ui/ai-avatar.js.map +1 -0
- package/dist/components/ui/ai-label.d.ts +118 -0
- package/dist/components/ui/ai-label.d.ts.map +1 -0
- package/dist/components/ui/ai-label.js +184 -0
- package/dist/components/ui/ai-label.js.map +1 -0
- package/dist/components/ui/ai-sparkle.d.ts +91 -0
- package/dist/components/ui/ai-sparkle.d.ts.map +1 -0
- package/dist/components/ui/ai-sparkle.js +200 -0
- package/dist/components/ui/ai-sparkle.js.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +79 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.js +147 -0
- package/dist/components/ui/alert-dialog.js.map +1 -0
- package/dist/components/ui/alert.d.ts +71 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/alert.js +108 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/aspect-ratio.d.ts +30 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.js +40 -0
- package/dist/components/ui/aspect-ratio.js.map +1 -0
- package/dist/components/ui/attachment.d.ts +74 -0
- package/dist/components/ui/attachment.d.ts.map +1 -0
- package/dist/components/ui/attachment.js +142 -0
- package/dist/components/ui/attachment.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +82 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +123 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +130 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +226 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +43 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.js +98 -0
- package/dist/components/ui/breadcrumb.js.map +1 -0
- package/dist/components/ui/browser-tabs.d.ts +218 -0
- package/dist/components/ui/browser-tabs.d.ts.map +1 -0
- package/dist/components/ui/browser-tabs.js +528 -0
- package/dist/components/ui/browser-tabs.js.map +1 -0
- package/dist/components/ui/bubble.d.ts +80 -0
- package/dist/components/ui/bubble.d.ts.map +1 -0
- package/dist/components/ui/bubble.js +235 -0
- package/dist/components/ui/bubble.js.map +1 -0
- package/dist/components/ui/button-group.d.ts +60 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button-group.js +89 -0
- package/dist/components/ui/button-group.js.map +1 -0
- package/dist/components/ui/button.d.ts +157 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +144 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/calendar.d.ts +57 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/calendar.js +163 -0
- package/dist/components/ui/calendar.js.map +1 -0
- package/dist/components/ui/card.d.ts +96 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +131 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/carousel.d.ts +86 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/carousel.js +207 -0
- package/dist/components/ui/carousel.js.map +1 -0
- package/dist/components/ui/checkbox.d.ts +54 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/checkbox.js +78 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/collapsible.d.ts +45 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +65 -0
- package/dist/components/ui/collapsible.js.map +1 -0
- package/dist/components/ui/combobox.d.ts +111 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/combobox.js +264 -0
- package/dist/components/ui/combobox.js.map +1 -0
- package/dist/components/ui/command.d.ts +71 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/command.js +133 -0
- package/dist/components/ui/command.js.map +1 -0
- package/dist/components/ui/context-menu.d.ts +70 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/context-menu.js +163 -0
- package/dist/components/ui/context-menu.js.map +1 -0
- package/dist/components/ui/count-badge.d.ts +40 -0
- package/dist/components/ui/count-badge.d.ts.map +1 -0
- package/dist/components/ui/count-badge.js +43 -0
- package/dist/components/ui/count-badge.js.map +1 -0
- package/dist/components/ui/data-table.d.ts +1026 -0
- package/dist/components/ui/data-table.d.ts.map +1 -0
- package/dist/components/ui/data-table.js +3423 -0
- package/dist/components/ui/data-table.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +73 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +145 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/direction.d.ts +35 -0
- package/dist/components/ui/direction.d.ts.map +1 -0
- package/dist/components/ui/direction.js +35 -0
- package/dist/components/ui/direction.js.map +1 -0
- package/dist/components/ui/drawer.d.ts +53 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/drawer.js +115 -0
- package/dist/components/ui/drawer.js.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +75 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +173 -0
- package/dist/components/ui/dropdown-menu.js.map +1 -0
- package/dist/components/ui/dropzone.d.ts +141 -0
- package/dist/components/ui/dropzone.d.ts.map +1 -0
- package/dist/components/ui/dropzone.js +257 -0
- package/dist/components/ui/dropzone.js.map +1 -0
- package/dist/components/ui/empty.d.ts +94 -0
- package/dist/components/ui/empty.d.ts.map +1 -0
- package/dist/components/ui/empty.js +149 -0
- package/dist/components/ui/empty.js.map +1 -0
- package/dist/components/ui/field.d.ts +122 -0
- package/dist/components/ui/field.d.ts.map +1 -0
- package/dist/components/ui/field.js +254 -0
- package/dist/components/ui/field.js.map +1 -0
- package/dist/components/ui/hover-card.d.ts +51 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/hover-card.js +101 -0
- package/dist/components/ui/hover-card.js.map +1 -0
- package/dist/components/ui/input-group.d.ts +62 -0
- package/dist/components/ui/input-group.d.ts.map +1 -0
- package/dist/components/ui/input-group.js +115 -0
- package/dist/components/ui/input-group.js.map +1 -0
- package/dist/components/ui/input-otp.d.ts +52 -0
- package/dist/components/ui/input-otp.d.ts.map +1 -0
- package/dist/components/ui/input-otp.js +89 -0
- package/dist/components/ui/input-otp.js.map +1 -0
- package/dist/components/ui/input.d.ts +47 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +47 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/item.d.ts +74 -0
- package/dist/components/ui/item.d.ts.map +1 -0
- package/dist/components/ui/item.js +176 -0
- package/dist/components/ui/item.js.map +1 -0
- package/dist/components/ui/kbd.d.ts +41 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +58 -0
- package/dist/components/ui/kbd.js.map +1 -0
- package/dist/components/ui/key-value-pair.d.ts +56 -0
- package/dist/components/ui/key-value-pair.d.ts.map +1 -0
- package/dist/components/ui/key-value-pair.js +110 -0
- package/dist/components/ui/key-value-pair.js.map +1 -0
- package/dist/components/ui/label.d.ts +83 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +85 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/marker.d.ts +54 -0
- package/dist/components/ui/marker.d.ts.map +1 -0
- package/dist/components/ui/marker.js +79 -0
- package/dist/components/ui/marker.js.map +1 -0
- package/dist/components/ui/menubar.d.ts +72 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/menubar.js +174 -0
- package/dist/components/ui/menubar.js.map +1 -0
- package/dist/components/ui/message-scroller.d.ts +53 -0
- package/dist/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/components/ui/message-scroller.js +95 -0
- package/dist/components/ui/message-scroller.js.map +1 -0
- package/dist/components/ui/message.d.ts +63 -0
- package/dist/components/ui/message.d.ts.map +1 -0
- package/dist/components/ui/message.js +92 -0
- package/dist/components/ui/message.js.map +1 -0
- package/dist/components/ui/meta-list.d.ts +55 -0
- package/dist/components/ui/meta-list.d.ts.map +1 -0
- package/dist/components/ui/meta-list.js +75 -0
- package/dist/components/ui/meta-list.js.map +1 -0
- package/dist/components/ui/native-select.d.ts +51 -0
- package/dist/components/ui/native-select.d.ts.map +1 -0
- package/dist/components/ui/native-select.js +75 -0
- package/dist/components/ui/native-select.js.map +1 -0
- package/dist/components/ui/navigation-menu.d.ts +56 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.js +116 -0
- package/dist/components/ui/navigation-menu.js.map +1 -0
- package/dist/components/ui/page-header.d.ts +223 -0
- package/dist/components/ui/page-header.d.ts.map +1 -0
- package/dist/components/ui/page-header.js +233 -0
- package/dist/components/ui/page-header.js.map +1 -0
- package/dist/components/ui/pagination.d.ts +68 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/pagination.js +145 -0
- package/dist/components/ui/pagination.js.map +1 -0
- package/dist/components/ui/popover.d.ts +61 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/popover.js +144 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/progress.d.ts +35 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/progress.js +46 -0
- package/dist/components/ui/progress.js.map +1 -0
- package/dist/components/ui/questionnaire.d.ts +92 -0
- package/dist/components/ui/questionnaire.d.ts.map +1 -0
- package/dist/components/ui/questionnaire.js +277 -0
- package/dist/components/ui/questionnaire.js.map +1 -0
- package/dist/components/ui/radio-group.d.ts +50 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/radio-group.js +65 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/resizable.d.ts +44 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/resizable.js +73 -0
- package/dist/components/ui/resizable.js.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +55 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +72 -0
- package/dist/components/ui/scroll-area.js.map +1 -0
- package/dist/components/ui/select.d.ts +274 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +609 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/separator.d.ts +31 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +38 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/sheet.d.ts +59 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sheet.js +128 -0
- package/dist/components/ui/sheet.js.map +1 -0
- package/dist/components/ui/sidebar.d.ts +166 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/sidebar.js +512 -0
- package/dist/components/ui/sidebar.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +35 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeleton.js +46 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/slider.d.ts +39 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/slider.js +75 -0
- package/dist/components/ui/slider.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +56 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/sonner.js +96 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/components/ui/spinner.d.ts +37 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/spinner.js +51 -0
- package/dist/components/ui/spinner.js.map +1 -0
- package/dist/components/ui/stepper.d.ts +84 -0
- package/dist/components/ui/stepper.d.ts.map +1 -0
- package/dist/components/ui/stepper.js +145 -0
- package/dist/components/ui/stepper.js.map +1 -0
- package/dist/components/ui/switch.d.ts +36 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/switch.js +44 -0
- package/dist/components/ui/switch.js.map +1 -0
- package/dist/components/ui/table.d.ts +80 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/table.js +130 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +87 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +128 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +35 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/textarea.js +38 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/components/ui/time-picker.d.ts +58 -0
- package/dist/components/ui/time-picker.d.ts.map +1 -0
- package/dist/components/ui/time-picker.js +188 -0
- package/dist/components/ui/time-picker.js.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +52 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.js +94 -0
- package/dist/components/ui/toggle-group.js.map +1 -0
- package/dist/components/ui/toggle.d.ts +50 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/toggle.js +70 -0
- package/dist/components/ui/toggle.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +51 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +78 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/hooks/use-dark-mode.d.ts +2 -0
- package/dist/hooks/use-dark-mode.d.ts.map +1 -0
- package/dist/hooks/use-dark-mode.js +36 -0
- package/dist/hooks/use-dark-mode.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +20 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -0
- package/dist/lib/scope.d.ts +64 -0
- package/dist/lib/scope.d.ts.map +1 -0
- package/dist/lib/scope.js +74 -0
- package/dist/lib/scope.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +11 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/theme-tokens.css +537 -0
- package/dist/theme.css +417 -0
- package/package.json +103 -3
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attachment — file attachment row with upload state, for chat messages and composers.
|
|
3
|
+
*
|
|
4
|
+
* A card-like row (or vertical tile) with a media/icon slot, title,
|
|
5
|
+
* description, and action buttons for one file. `state` drives the upload
|
|
6
|
+
* affordance: dashed border while idle, shimmering title while
|
|
7
|
+
* uploading/processing, destructive tint on error. AttachmentGroup lays out
|
|
8
|
+
* several as a horizontally-scrolling strip. AttachmentTrigger is an
|
|
9
|
+
* invisible full-cover button for drop-zone / file-picker interactions.
|
|
10
|
+
*/
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { type VariantProps } from "class-variance-authority";
|
|
13
|
+
import { Button, type TextButtonSize } from "../../components/ui/button";
|
|
14
|
+
declare const attachmentVariants: (props?: ({
|
|
15
|
+
size?: "sm" | "default" | "xs" | null | undefined;
|
|
16
|
+
orientation?: "horizontal" | "vertical" | null | undefined;
|
|
17
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
18
|
+
declare function Attachment({ className, state, size, orientation, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentVariants> & {
|
|
19
|
+
state?: "idle" | "uploading" | "processing" | "error" | "done";
|
|
20
|
+
}): React.JSX.Element;
|
|
21
|
+
declare const attachmentMediaVariants: (props?: ({
|
|
22
|
+
variant?: "image" | "icon" | null | undefined;
|
|
23
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
24
|
+
declare function AttachmentMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>): React.JSX.Element;
|
|
25
|
+
declare function AttachmentContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
26
|
+
declare function AttachmentTitle({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
27
|
+
declare function AttachmentDescription({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
28
|
+
declare function AttachmentActions({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
29
|
+
declare function AttachmentAction({ className, variant, size, ...props }: Omit<React.ComponentProps<typeof Button>, "size" | "aria-label" | "iconOnly" | "asChild"> & {
|
|
30
|
+
/** Height step of the icon-only button; it is always square (`iconOnly`). */
|
|
31
|
+
size?: TextButtonSize;
|
|
32
|
+
"aria-label": string;
|
|
33
|
+
}): React.JSX.Element;
|
|
34
|
+
declare function AttachmentTrigger({ className, asChild, type, ...props }: React.ComponentProps<"button"> & {
|
|
35
|
+
asChild?: boolean;
|
|
36
|
+
}): React.JSX.Element;
|
|
37
|
+
declare function AttachmentGroup({ className, tabIndex, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
38
|
+
export { Attachment, AttachmentGroup, AttachmentMedia, AttachmentContent, AttachmentTitle, AttachmentDescription, AttachmentActions, AttachmentAction, AttachmentTrigger, };
|
|
39
|
+
/**
|
|
40
|
+
* WHEN TO USE
|
|
41
|
+
* - Files attached to a chat message or composer
|
|
42
|
+
* - Upload queues that need per-file progress/state and a remove action
|
|
43
|
+
*
|
|
44
|
+
* NOT WHEN
|
|
45
|
+
* - A plain native file picker with no per-file UI — use Input type="file"
|
|
46
|
+
* - Image browsing meant as a gallery rather than an attachment list
|
|
47
|
+
* - Plain download links with no upload lifecycle
|
|
48
|
+
*
|
|
49
|
+
* KEY RULES
|
|
50
|
+
* - state: idle, uploading, processing, error, done (default "done") — "idle" renders a dashed border (drop-zone look)
|
|
51
|
+
* - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment
|
|
52
|
+
* - orientation: horizontal (default, row) or vertical (column tile, media fills the width)
|
|
53
|
+
* - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in "done"/"idle" states
|
|
54
|
+
* - AttachmentTitle shimmers automatically in "uploading"/"processing" states — no extra prop needed
|
|
55
|
+
* - AttachmentAction defaults to variant="ghost" size="xs" iconOnly — always pass aria-label, it's icon-only
|
|
56
|
+
* - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable
|
|
57
|
+
*
|
|
58
|
+
* USAGE
|
|
59
|
+
* <Attachment state="uploading">
|
|
60
|
+
* <AttachmentMedia variant="icon"><FileTextIcon /></AttachmentMedia>
|
|
61
|
+
* <AttachmentContent>
|
|
62
|
+
* <AttachmentTitle>theme.css</AttachmentTitle>
|
|
63
|
+
* <AttachmentDescription>6.3 KB</AttachmentDescription>
|
|
64
|
+
* </AttachmentContent>
|
|
65
|
+
* <AttachmentActions>
|
|
66
|
+
* <AttachmentAction aria-label="Remove attachment"><XIcon /></AttachmentAction>
|
|
67
|
+
* </AttachmentActions>
|
|
68
|
+
* </Attachment>
|
|
69
|
+
*
|
|
70
|
+
* <AttachmentGroup>
|
|
71
|
+
* {files.map((f) => <Attachment key={f.name}>...</Attachment>)}
|
|
72
|
+
* </AttachmentGroup>
|
|
73
|
+
*/
|
|
74
|
+
//# sourceMappingURL=attachment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../../src/components/ui/attachment.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,OAAO,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEpE,QAAA,MAAM,kBAAkB;;;8EAgBvB,CAAA;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,KAAc,EACd,IAAgB,EAChB,WAA0B,EAC1B,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAC5B,YAAY,CAAC,OAAO,kBAAkB,CAAC,GAAG;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAA;CAC/D,qBAWF;AAED,QAAA,MAAM,uBAAuB;;8EAc5B,CAAA;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,OAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,uBAAuB,CAAC,qBAS5E;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAW9B;AAED,iBAAS,qBAAqB,CAAC,EAC7B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAY9B;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,OAAO,EACP,IAAW,EACX,GAAG,KAAK,EACT,EAAE,IAAI,CACL,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EACnC,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAC/C,GAAG;IACF,6EAA6E;IAC7E,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,qBAWA;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAe,EACf,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAWA;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,QAAY,EACZ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAc7B;AAED,OAAO,EACL,UAAU,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { Button } from "./button.js";
|
|
3
|
+
import "react";
|
|
4
|
+
import { Slot } from "radix-ui";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
//#region src/components/ui/attachment.tsx
|
|
8
|
+
var attachmentVariants = cva("group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-3 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed", { variants: {
|
|
9
|
+
size: {
|
|
10
|
+
default: "gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2",
|
|
11
|
+
sm: "gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5",
|
|
12
|
+
xs: "gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1"
|
|
13
|
+
},
|
|
14
|
+
orientation: {
|
|
15
|
+
horizontal: "min-w-40 items-center",
|
|
16
|
+
vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30"
|
|
17
|
+
}
|
|
18
|
+
} });
|
|
19
|
+
function Attachment({ className, state = "done", size = "default", orientation = "horizontal", ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsx("div", {
|
|
21
|
+
"data-slot": "attachment",
|
|
22
|
+
"data-state": state,
|
|
23
|
+
"data-size": size,
|
|
24
|
+
"data-orientation": orientation,
|
|
25
|
+
className: cn(attachmentVariants({
|
|
26
|
+
size,
|
|
27
|
+
orientation
|
|
28
|
+
}), className),
|
|
29
|
+
...props
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
var attachmentMediaVariants = cva("relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5", {
|
|
33
|
+
variants: { variant: {
|
|
34
|
+
icon: "",
|
|
35
|
+
image: "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
|
|
36
|
+
} },
|
|
37
|
+
defaultVariants: { variant: "icon" }
|
|
38
|
+
});
|
|
39
|
+
function AttachmentMedia({ className, variant = "icon", ...props }) {
|
|
40
|
+
return /* @__PURE__ */ jsx("div", {
|
|
41
|
+
"data-slot": "attachment-media",
|
|
42
|
+
"data-variant": variant,
|
|
43
|
+
className: cn(attachmentMediaVariants({ variant }), className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function AttachmentContent({ className, ...props }) {
|
|
48
|
+
return /* @__PURE__ */ jsx("div", {
|
|
49
|
+
"data-slot": "attachment-content",
|
|
50
|
+
className: cn("max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1", className),
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function AttachmentTitle({ className, ...props }) {
|
|
55
|
+
return /* @__PURE__ */ jsx("span", {
|
|
56
|
+
"data-slot": "attachment-title",
|
|
57
|
+
className: cn("block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer", className),
|
|
58
|
+
...props
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function AttachmentDescription({ className, ...props }) {
|
|
62
|
+
return /* @__PURE__ */ jsx("span", {
|
|
63
|
+
"data-slot": "attachment-description",
|
|
64
|
+
className: cn("mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80", "max-w-full", className),
|
|
65
|
+
...props
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function AttachmentActions({ className, ...props }) {
|
|
69
|
+
return /* @__PURE__ */ jsx("div", {
|
|
70
|
+
"data-slot": "attachment-actions",
|
|
71
|
+
className: cn("relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1", className),
|
|
72
|
+
...props
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function AttachmentAction({ className, variant, size = "xs", ...props }) {
|
|
76
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
77
|
+
"data-slot": "attachment-action",
|
|
78
|
+
variant: variant ?? "ghost",
|
|
79
|
+
size,
|
|
80
|
+
iconOnly: true,
|
|
81
|
+
className: cn(className),
|
|
82
|
+
...props
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function AttachmentTrigger({ className, asChild = false, type, ...props }) {
|
|
86
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
87
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
88
|
+
"data-slot": "attachment-trigger",
|
|
89
|
+
type: asChild ? void 0 : type ?? "button",
|
|
90
|
+
className: cn("absolute inset-0 z-10 outline-none", className),
|
|
91
|
+
...props
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function AttachmentGroup({ className, tabIndex = 0, ...props }) {
|
|
95
|
+
return /* @__PURE__ */ jsx("div", {
|
|
96
|
+
"data-slot": "attachment-group",
|
|
97
|
+
role: "region",
|
|
98
|
+
"aria-label": "Attachments",
|
|
99
|
+
tabIndex,
|
|
100
|
+
className: cn("flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start", className),
|
|
101
|
+
...props
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* WHEN TO USE
|
|
106
|
+
* - Files attached to a chat message or composer
|
|
107
|
+
* - Upload queues that need per-file progress/state and a remove action
|
|
108
|
+
*
|
|
109
|
+
* NOT WHEN
|
|
110
|
+
* - A plain native file picker with no per-file UI — use Input type="file"
|
|
111
|
+
* - Image browsing meant as a gallery rather than an attachment list
|
|
112
|
+
* - Plain download links with no upload lifecycle
|
|
113
|
+
*
|
|
114
|
+
* KEY RULES
|
|
115
|
+
* - state: idle, uploading, processing, error, done (default "done") — "idle" renders a dashed border (drop-zone look)
|
|
116
|
+
* - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment
|
|
117
|
+
* - orientation: horizontal (default, row) or vertical (column tile, media fills the width)
|
|
118
|
+
* - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in "done"/"idle" states
|
|
119
|
+
* - AttachmentTitle shimmers automatically in "uploading"/"processing" states — no extra prop needed
|
|
120
|
+
* - AttachmentAction defaults to variant="ghost" size="xs" iconOnly — always pass aria-label, it's icon-only
|
|
121
|
+
* - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable
|
|
122
|
+
*
|
|
123
|
+
* USAGE
|
|
124
|
+
* <Attachment state="uploading">
|
|
125
|
+
* <AttachmentMedia variant="icon"><FileTextIcon /></AttachmentMedia>
|
|
126
|
+
* <AttachmentContent>
|
|
127
|
+
* <AttachmentTitle>theme.css</AttachmentTitle>
|
|
128
|
+
* <AttachmentDescription>6.3 KB</AttachmentDescription>
|
|
129
|
+
* </AttachmentContent>
|
|
130
|
+
* <AttachmentActions>
|
|
131
|
+
* <AttachmentAction aria-label="Remove attachment"><XIcon /></AttachmentAction>
|
|
132
|
+
* </AttachmentActions>
|
|
133
|
+
* </Attachment>
|
|
134
|
+
*
|
|
135
|
+
* <AttachmentGroup>
|
|
136
|
+
* {files.map((f) => <Attachment key={f.name}>...</Attachment>)}
|
|
137
|
+
* </AttachmentGroup>
|
|
138
|
+
*/
|
|
139
|
+
//#endregion
|
|
140
|
+
export { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger };
|
|
141
|
+
|
|
142
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","names":[],"sources":["../../../src/components/ui/attachment.tsx"],"sourcesContent":["/**\n * Attachment — file attachment row with upload state, for chat messages and composers.\n *\n * A card-like row (or vertical tile) with a media/icon slot, title,\n * description, and action buttons for one file. `state` drives the upload\n * affordance: dashed border while idle, shimmering title while\n * uploading/processing, destructive tint on error. AttachmentGroup lays out\n * several as a horizontally-scrolling strip. AttachmentTrigger is an\n * invisible full-cover button for drop-zone / file-picker interactions.\n */\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button, type TextButtonSize } from \"@/components/ui/button\"\n\nconst attachmentVariants = cva(\n \"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-3 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed\",\n {\n variants: {\n size: {\n default:\n \"gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2\",\n sm: \"gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5\",\n xs: \"gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1\",\n },\n orientation: {\n horizontal: \"min-w-40 items-center\",\n vertical: \"w-24 flex-col has-data-[slot=attachment-content]:w-30\",\n },\n },\n }\n)\n\nfunction Attachment({\n className,\n state = \"done\",\n size = \"default\",\n orientation = \"horizontal\",\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof attachmentVariants> & {\n state?: \"idle\" | \"uploading\" | \"processing\" | \"error\" | \"done\"\n }) {\n return (\n <div\n data-slot=\"attachment\"\n data-state={state}\n data-size={size}\n data-orientation={orientation}\n className={cn(attachmentVariants({ size, orientation }), className)}\n {...props}\n />\n )\n}\n\nconst attachmentMediaVariants = cva(\n \"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5\",\n {\n variants: {\n variant: {\n icon: \"\",\n image:\n \"opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"icon\",\n },\n }\n)\n\nfunction AttachmentMedia({\n className,\n variant = \"icon\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof attachmentMediaVariants>) {\n return (\n <div\n data-slot=\"attachment-media\"\n data-variant={variant}\n className={cn(attachmentMediaVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-content\"\n className={cn(\n \"max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentTitle({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-title\"\n className={cn(\n \"block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentDescription({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-description\"\n className={cn(\n \"mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80\",\n \"max-w-full\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentActions({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-actions\"\n className={cn(\n \"relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentAction({\n className,\n variant,\n size = \"xs\",\n ...props\n}: Omit<\n React.ComponentProps<typeof Button>,\n \"size\" | \"aria-label\" | \"iconOnly\" | \"asChild\"\n> & {\n /** Height step of the icon-only button; it is always square (`iconOnly`). */\n size?: TextButtonSize\n \"aria-label\": string\n}) {\n return (\n <Button\n data-slot=\"attachment-action\"\n variant={variant ?? \"ghost\"}\n size={size}\n iconOnly\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentTrigger({\n className,\n asChild = false,\n type,\n ...props\n}: React.ComponentProps<\"button\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"button\"\n\n return (\n <Comp\n data-slot=\"attachment-trigger\"\n type={asChild ? undefined : (type ?? \"button\")}\n className={cn(\"absolute inset-0 z-10 outline-none\", className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentGroup({\n className,\n tabIndex = 0,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-group\"\n role=\"region\"\n aria-label=\"Attachments\"\n tabIndex={tabIndex}\n className={cn(\n \"flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Attachment,\n AttachmentGroup,\n AttachmentMedia,\n AttachmentContent,\n AttachmentTitle,\n AttachmentDescription,\n AttachmentActions,\n AttachmentAction,\n AttachmentTrigger,\n}\n\n/**\n * WHEN TO USE\n * - Files attached to a chat message or composer\n * - Upload queues that need per-file progress/state and a remove action\n *\n * NOT WHEN\n * - A plain native file picker with no per-file UI — use Input type=\"file\"\n * - Image browsing meant as a gallery rather than an attachment list\n * - Plain download links with no upload lifecycle\n *\n * KEY RULES\n * - state: idle, uploading, processing, error, done (default \"done\") — \"idle\" renders a dashed border (drop-zone look)\n * - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment\n * - orientation: horizontal (default, row) or vertical (column tile, media fills the width)\n * - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in \"done\"/\"idle\" states\n * - AttachmentTitle shimmers automatically in \"uploading\"/\"processing\" states — no extra prop needed\n * - AttachmentAction defaults to variant=\"ghost\" size=\"xs\" iconOnly — always pass aria-label, it's icon-only\n * - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable\n *\n * USAGE\n * <Attachment state=\"uploading\">\n * <AttachmentMedia variant=\"icon\"><FileTextIcon /></AttachmentMedia>\n * <AttachmentContent>\n * <AttachmentTitle>theme.css</AttachmentTitle>\n * <AttachmentDescription>6.3 KB</AttachmentDescription>\n * </AttachmentContent>\n * <AttachmentActions>\n * <AttachmentAction aria-label=\"Remove attachment\"><XIcon /></AttachmentAction>\n * </AttachmentActions>\n * </Attachment>\n *\n * <AttachmentGroup>\n * {files.map((f) => <Attachment key={f.name}>...</Attachment>)}\n * </AttachmentGroup>\n */\n"],"mappings":";;;;;;;AAkBA,IAAM,qBAAqB,IACzB,ySACA,EACE,UAAU;CACR,MAAM;EACJ,SACE;EACF,IAAI;EACJ,IAAI;CACN;CACA,aAAa;EACX,YAAY;EACZ,UAAU;CACZ;AACF,EACF,CACF;AAEA,SAAS,WAAW,EAClB,WACA,QAAQ,QACR,OAAO,WACP,cAAc,cACd,GAAG,SAIA;CACH,OACE,oBAAC,OAAD;EACE,aAAU;EACV,cAAY;EACZ,aAAW;EACX,oBAAkB;EAClB,WAAW,GAAG,mBAAmB;GAAE;GAAM;EAAY,CAAC,GAAG,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAEA,IAAM,0BAA0B,IAC9B,orBACA;CACE,UAAU,EACR,SAAS;EACP,MAAM;EACN,OACE;CACJ,EACF;CACA,iBAAiB,EACf,SAAS,OACX;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,UAAU,QACV,GAAG,SAC0E;CAC7E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,GAAG,wBAAwB,EAAE,QAAQ,CAAC,GAAG,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,6FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,WACA,GAAG,SAC4B;CAC/B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,kJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4B;CAC/B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,uHACA,cACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,6PACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,SACA,OAAO,MACP,GAAG,SAQF;CACD,OACE,oBAAC,QAAD;EACE,aAAU;EACV,SAAS,WAAW;EACd;EACN,UAAA;EACA,WAAW,GAAG,SAAS;EACvB,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,UAAU,OACV,MACA,GAAG,SAGF;CACD,MAAM,OAAO,UAAU,KAAK,OAAO;CAEnC,OACE,oBAAC,MAAD;EACE,aAAU;EACV,MAAM,UAAU,KAAA,IAAa,QAAQ;EACrC,WAAW,GAAG,sCAAsC,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,WACA,WAAW,GACX,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,cAAW;EACD;EACV,WAAW,GACT,sMACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar — person/entity image with initials fallback.
|
|
3
|
+
*
|
|
4
|
+
* Built on the Radix Avatar primitive. A `size` prop ("default" | "sm" |
|
|
5
|
+
* "lg") also rescales AvatarFallback text and AvatarBadge via a shared
|
|
6
|
+
* `data-size` attribute, so sizing never needs className overrides.
|
|
7
|
+
*/
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
10
|
+
declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
|
|
11
|
+
size?: "default" | "sm" | "lg";
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
declare function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>): React.JSX.Element;
|
|
14
|
+
declare function AvatarFallback({ className, colorSeed, children, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback> & {
|
|
15
|
+
/**
|
|
16
|
+
* A stable identity string (name, user id, email) hashed to one of the
|
|
17
|
+
* 6 chart colors. Defaults to the fallback's own text (usually
|
|
18
|
+
* initials) when omitted, so a plain `<AvatarFallback>AL</AvatarFallback>`
|
|
19
|
+
* is already colored — there's no neutral/grey fallback for text content.
|
|
20
|
+
* Pass it explicitly when the visible text isn't a stable per-identity
|
|
21
|
+
* string (e.g. it's always "?"), or when it differs from the real identity
|
|
22
|
+
* key you want the color derived from.
|
|
23
|
+
*/
|
|
24
|
+
colorSeed?: string;
|
|
25
|
+
}): React.JSX.Element;
|
|
26
|
+
declare function AvatarBadge({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
27
|
+
declare function AvatarGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
28
|
+
declare function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
29
|
+
export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge, };
|
|
30
|
+
/**
|
|
31
|
+
* WHEN TO USE
|
|
32
|
+
* - Representing a person or organization visually — profile pictures,
|
|
33
|
+
* comment authors, member lists.
|
|
34
|
+
* - AvatarGroup + AvatarGroupCount for a set of collaborators with a
|
|
35
|
+
* "+N" overflow count.
|
|
36
|
+
* - AvatarBadge for a presence dot (online/away/status) on the corner.
|
|
37
|
+
*
|
|
38
|
+
* NOT WHEN
|
|
39
|
+
* - Generic iconography with no identity meaning — use a Lucide icon.
|
|
40
|
+
* - Decorative or content imagery — Avatar is identity-specific.
|
|
41
|
+
* - A numeric unread/notification count — use CountBadge, not AvatarBadge
|
|
42
|
+
* (AvatarBadge is a plain dot with no built-in number formatting).
|
|
43
|
+
*
|
|
44
|
+
* KEY RULES
|
|
45
|
+
* - Prefer the `size` prop ("default" | "sm" | "lg") over a raw
|
|
46
|
+
* `size-*` className — it keeps AvatarFallback's text size and
|
|
47
|
+
* AvatarBadge's dot size in sync via `data-size`. A raw className
|
|
48
|
+
* override (e.g. `size-14`) changes only the Avatar's own dimensions,
|
|
49
|
+
* not its children's.
|
|
50
|
+
* - AvatarFallback renders only once AvatarImage fails or is still
|
|
51
|
+
* loading — always pair an AvatarImage with a fallback.
|
|
52
|
+
* - AvatarFallback hashes to one of 6 chart colors so each identity gets a
|
|
53
|
+
* stable, distinct fallback — never the flat neutral bg-muted. The hash
|
|
54
|
+
* seed defaults to the fallback's own text content (usually initials), so
|
|
55
|
+
* plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass
|
|
56
|
+
* `colorSeed` explicitly only when the visible text isn't a stable
|
|
57
|
+
* per-identity string, or should key off something other than itself
|
|
58
|
+
* - Avatar itself has no border/ring — that's AvatarGroup's job (a
|
|
59
|
+
* background-colored ring for overlap separation), not Avatar's
|
|
60
|
+
* - AvatarGroup expects each child to be a `data-slot="avatar"` element
|
|
61
|
+
* (i.e. an actual `<Avatar>`) — it styles overlap and ring via that
|
|
62
|
+
* attribute selector, not by wrapping arbitrary children.
|
|
63
|
+
*
|
|
64
|
+
* USAGE
|
|
65
|
+
* <Avatar>
|
|
66
|
+
* <AvatarImage src="/user.png" alt="Ada Lovelace" />
|
|
67
|
+
* <AvatarFallback>AL</AvatarFallback>
|
|
68
|
+
* </Avatar>
|
|
69
|
+
*
|
|
70
|
+
* <Avatar size="lg">
|
|
71
|
+
* <AvatarImage src="/user.png" alt="Ada Lovelace" />
|
|
72
|
+
* <AvatarFallback>AL</AvatarFallback>
|
|
73
|
+
* <AvatarBadge className="bg-success" />
|
|
74
|
+
* </Avatar>
|
|
75
|
+
*
|
|
76
|
+
* <AvatarGroup>
|
|
77
|
+
* <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>
|
|
78
|
+
* <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>
|
|
79
|
+
* <AvatarGroupCount>+4</AvatarGroupCount>
|
|
80
|
+
* </AvatarGroup>
|
|
81
|
+
*/
|
|
82
|
+
//# sourceMappingURL=avatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/avatar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,UAAU,CAAA;AAIpD,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrD,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAA;CAC/B,qBAYA;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAWpD;AA4CD,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,QAAQ,CAAC,GAAG;IACzD;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,qBAkBA;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAczE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,WAAW,GACZ,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Avatar as Avatar$1 } from "radix-ui";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/ui/avatar.tsx
|
|
6
|
+
function Avatar({ className, size = "default", ...props }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Avatar$1.Root, {
|
|
8
|
+
"data-slot": "avatar",
|
|
9
|
+
"data-size": size,
|
|
10
|
+
className: cn("group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6", className),
|
|
11
|
+
...props
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function AvatarImage({ className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(Avatar$1.Image, {
|
|
16
|
+
"data-slot": "avatar-image",
|
|
17
|
+
className: cn("aspect-square size-full rounded-full object-cover", className),
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
var AVATAR_FALLBACK_COLOR_VARIANTS = [
|
|
22
|
+
"bg-[oklch(from_var(--color-chart-1)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-1)_0.88_calc(c*0.6)_h)]",
|
|
23
|
+
"bg-[oklch(from_var(--color-chart-3)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-3)_0.88_calc(c*0.6)_h)]",
|
|
24
|
+
"bg-[oklch(from_var(--color-chart-4)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-4)_0.88_calc(c*0.6)_h)]",
|
|
25
|
+
"bg-[oklch(from_var(--color-chart-6)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-6)_0.88_calc(c*0.6)_h)]",
|
|
26
|
+
"bg-[oklch(from_var(--color-chart-7)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-7)_0.88_calc(c*0.6)_h)]",
|
|
27
|
+
"bg-[oklch(from_var(--color-chart-8)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-8)_0.88_calc(c*0.6)_h)]"
|
|
28
|
+
];
|
|
29
|
+
/** djb2-ish string hash — deterministic, so the same seed always lands on the same swatch. */
|
|
30
|
+
function hashSeedToColorIndex(seed) {
|
|
31
|
+
let hash = 0;
|
|
32
|
+
for (let i = 0; i < seed.length; i++) {
|
|
33
|
+
hash = (hash << 5) - hash + seed.charCodeAt(i);
|
|
34
|
+
hash |= 0;
|
|
35
|
+
}
|
|
36
|
+
return Math.abs(hash) % AVATAR_FALLBACK_COLOR_VARIANTS.length;
|
|
37
|
+
}
|
|
38
|
+
function AvatarFallback({ className, colorSeed, children, ...props }) {
|
|
39
|
+
const seed = colorSeed ?? (typeof children === "string" ? children : void 0);
|
|
40
|
+
return /* @__PURE__ */ jsx(Avatar$1.Fallback, {
|
|
41
|
+
"data-slot": "avatar-fallback",
|
|
42
|
+
className: cn("flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs", seed ? AVATAR_FALLBACK_COLOR_VARIANTS[hashSeedToColorIndex(seed)] : "bg-muted text-muted-foreground", className),
|
|
43
|
+
...props,
|
|
44
|
+
children
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function AvatarBadge({ className, ...props }) {
|
|
48
|
+
return /* @__PURE__ */ jsx("span", {
|
|
49
|
+
"data-slot": "avatar-badge",
|
|
50
|
+
className: cn("absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className),
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function AvatarGroup({ className, ...props }) {
|
|
55
|
+
return /* @__PURE__ */ jsx("div", {
|
|
56
|
+
"data-slot": "avatar-group",
|
|
57
|
+
className: cn("group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", className),
|
|
58
|
+
...props
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function AvatarGroupCount({ className, ...props }) {
|
|
62
|
+
return /* @__PURE__ */ jsx("div", {
|
|
63
|
+
"data-slot": "avatar-group-count",
|
|
64
|
+
className: cn("relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className),
|
|
65
|
+
...props
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* WHEN TO USE
|
|
70
|
+
* - Representing a person or organization visually — profile pictures,
|
|
71
|
+
* comment authors, member lists.
|
|
72
|
+
* - AvatarGroup + AvatarGroupCount for a set of collaborators with a
|
|
73
|
+
* "+N" overflow count.
|
|
74
|
+
* - AvatarBadge for a presence dot (online/away/status) on the corner.
|
|
75
|
+
*
|
|
76
|
+
* NOT WHEN
|
|
77
|
+
* - Generic iconography with no identity meaning — use a Lucide icon.
|
|
78
|
+
* - Decorative or content imagery — Avatar is identity-specific.
|
|
79
|
+
* - A numeric unread/notification count — use CountBadge, not AvatarBadge
|
|
80
|
+
* (AvatarBadge is a plain dot with no built-in number formatting).
|
|
81
|
+
*
|
|
82
|
+
* KEY RULES
|
|
83
|
+
* - Prefer the `size` prop ("default" | "sm" | "lg") over a raw
|
|
84
|
+
* `size-*` className — it keeps AvatarFallback's text size and
|
|
85
|
+
* AvatarBadge's dot size in sync via `data-size`. A raw className
|
|
86
|
+
* override (e.g. `size-14`) changes only the Avatar's own dimensions,
|
|
87
|
+
* not its children's.
|
|
88
|
+
* - AvatarFallback renders only once AvatarImage fails or is still
|
|
89
|
+
* loading — always pair an AvatarImage with a fallback.
|
|
90
|
+
* - AvatarFallback hashes to one of 6 chart colors so each identity gets a
|
|
91
|
+
* stable, distinct fallback — never the flat neutral bg-muted. The hash
|
|
92
|
+
* seed defaults to the fallback's own text content (usually initials), so
|
|
93
|
+
* plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass
|
|
94
|
+
* `colorSeed` explicitly only when the visible text isn't a stable
|
|
95
|
+
* per-identity string, or should key off something other than itself
|
|
96
|
+
* - Avatar itself has no border/ring — that's AvatarGroup's job (a
|
|
97
|
+
* background-colored ring for overlap separation), not Avatar's
|
|
98
|
+
* - AvatarGroup expects each child to be a `data-slot="avatar"` element
|
|
99
|
+
* (i.e. an actual `<Avatar>`) — it styles overlap and ring via that
|
|
100
|
+
* attribute selector, not by wrapping arbitrary children.
|
|
101
|
+
*
|
|
102
|
+
* USAGE
|
|
103
|
+
* <Avatar>
|
|
104
|
+
* <AvatarImage src="/user.png" alt="Ada Lovelace" />
|
|
105
|
+
* <AvatarFallback>AL</AvatarFallback>
|
|
106
|
+
* </Avatar>
|
|
107
|
+
*
|
|
108
|
+
* <Avatar size="lg">
|
|
109
|
+
* <AvatarImage src="/user.png" alt="Ada Lovelace" />
|
|
110
|
+
* <AvatarFallback>AL</AvatarFallback>
|
|
111
|
+
* <AvatarBadge className="bg-success" />
|
|
112
|
+
* </Avatar>
|
|
113
|
+
*
|
|
114
|
+
* <AvatarGroup>
|
|
115
|
+
* <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>
|
|
116
|
+
* <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>
|
|
117
|
+
* <AvatarGroupCount>+4</AvatarGroupCount>
|
|
118
|
+
* </AvatarGroup>
|
|
119
|
+
*/
|
|
120
|
+
//#endregion
|
|
121
|
+
export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.js","names":[],"sources":["../../../src/components/ui/avatar.tsx"],"sourcesContent":["/**\n * Avatar — person/entity image with initials fallback.\n *\n * Built on the Radix Avatar primitive. A `size` prop (\"default\" | \"sm\" |\n * \"lg\") also rescales AvatarFallback text and AvatarBadge via a shared\n * `data-size` attribute, so sizing never needs className overrides.\n */\n\nimport * as React from \"react\"\nimport { Avatar as AvatarPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Avatar({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\n size?: \"default\" | \"sm\" | \"lg\"\n}) {\n return (\n <AvatarPrimitive.Root\n data-slot=\"avatar\"\n data-size={size}\n className={cn(\n \"group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarImage({\n className,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n return (\n <AvatarPrimitive.Image\n data-slot=\"avatar-image\"\n className={cn(\n \"aspect-square size-full rounded-full object-cover\",\n className\n )}\n {...props}\n />\n )\n}\n\n/*\n * One static class string per chart color, not a template literal — Tailwind's\n * scanner only picks up complete class names that appear literally in source.\n * bg: a subtle tint of the color; text: a dark shade of that SAME color,\n * not a flat neutral ink — via the same CSS relative-color trick Bubble's\n * \"tinted\" variant already uses: keep the chart color's hue, pull the\n * background toward a light pastel (dark mode: a dark pastel) and the text\n * toward a dark, moderately saturated shade of that hue (dark mode: a light\n * one) instead of full-strength swatch + neutral ink.\n *\n * Only 6 of the 8 chart hues, not all 8: chart-1/3/4/6/7/8 (orange, indigo,\n * lime, pink, teal, fuchsia) — dropping chart-2 (violet) and chart-5 (cyan),\n * the two that sit closest to a kept hue (violet is 20.8° from indigo; cyan\n * is 39.5° from teal) and are therefore the most redundant to cut. Worst gap\n * in the kept 6 is 36.8° (pink to fuchsia) — not the >=45° this used to\n * clear before chart-1..8 was reconstructed from the Accent 1-8 primitives\n * (see theme-tokens.css), but the best any 6-of-8 subset of these\n * particular hues can do; re-verified via brute force over all 28\n * combinations, not assumed. Once pulled this light and this desaturated\n * for an avatar fill, hue is nearly all that's left to tell colors apart,\n * so even a \"close enough\" pair here reads as more similar than it would\n * at chart's full saturation.\n */\nconst AVATAR_FALLBACK_COLOR_VARIANTS = [\n \"bg-[oklch(from_var(--color-chart-1)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-1)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-3)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-3)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-4)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-4)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-6)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-6)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-7)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-7)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-8)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-8)_0.88_calc(c*0.6)_h)]\",\n]\n\n/** djb2-ish string hash — deterministic, so the same seed always lands on the same swatch. */\nfunction hashSeedToColorIndex(seed: string) {\n let hash = 0\n for (let i = 0; i < seed.length; i++) {\n hash = (hash << 5) - hash + seed.charCodeAt(i)\n hash |= 0\n }\n return Math.abs(hash) % AVATAR_FALLBACK_COLOR_VARIANTS.length\n}\n\nfunction AvatarFallback({\n className,\n colorSeed,\n children,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback> & {\n /**\n * A stable identity string (name, user id, email) hashed to one of the\n * 6 chart colors. Defaults to the fallback's own text (usually\n * initials) when omitted, so a plain `<AvatarFallback>AL</AvatarFallback>`\n * is already colored — there's no neutral/grey fallback for text content.\n * Pass it explicitly when the visible text isn't a stable per-identity\n * string (e.g. it's always \"?\"), or when it differs from the real identity\n * key you want the color derived from.\n */\n colorSeed?: string\n}) {\n const seed =\n colorSeed ?? (typeof children === \"string\" ? children : undefined)\n return (\n <AvatarPrimitive.Fallback\n data-slot=\"avatar-fallback\"\n className={cn(\n \"flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs\",\n seed\n ? AVATAR_FALLBACK_COLOR_VARIANTS[hashSeedToColorIndex(seed)]\n : \"bg-muted text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n </AvatarPrimitive.Fallback>\n )\n}\n\nfunction AvatarBadge({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"avatar-badge\"\n className={cn(\n \"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none\",\n \"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden\",\n \"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2\",\n \"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group\"\n className={cn(\n \"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroupCount({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group-count\"\n className={cn(\n \"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Avatar,\n AvatarImage,\n AvatarFallback,\n AvatarGroup,\n AvatarGroupCount,\n AvatarBadge,\n}\n\n/**\n * WHEN TO USE\n * - Representing a person or organization visually — profile pictures,\n * comment authors, member lists.\n * - AvatarGroup + AvatarGroupCount for a set of collaborators with a\n * \"+N\" overflow count.\n * - AvatarBadge for a presence dot (online/away/status) on the corner.\n *\n * NOT WHEN\n * - Generic iconography with no identity meaning — use a Lucide icon.\n * - Decorative or content imagery — Avatar is identity-specific.\n * - A numeric unread/notification count — use CountBadge, not AvatarBadge\n * (AvatarBadge is a plain dot with no built-in number formatting).\n *\n * KEY RULES\n * - Prefer the `size` prop (\"default\" | \"sm\" | \"lg\") over a raw\n * `size-*` className — it keeps AvatarFallback's text size and\n * AvatarBadge's dot size in sync via `data-size`. A raw className\n * override (e.g. `size-14`) changes only the Avatar's own dimensions,\n * not its children's.\n * - AvatarFallback renders only once AvatarImage fails or is still\n * loading — always pair an AvatarImage with a fallback.\n * - AvatarFallback hashes to one of 6 chart colors so each identity gets a\n * stable, distinct fallback — never the flat neutral bg-muted. The hash\n * seed defaults to the fallback's own text content (usually initials), so\n * plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass\n * `colorSeed` explicitly only when the visible text isn't a stable\n * per-identity string, or should key off something other than itself\n * - Avatar itself has no border/ring — that's AvatarGroup's job (a\n * background-colored ring for overlap separation), not Avatar's\n * - AvatarGroup expects each child to be a `data-slot=\"avatar\"` element\n * (i.e. an actual `<Avatar>`) — it styles overlap and ring via that\n * attribute selector, not by wrapping arbitrary children.\n *\n * USAGE\n * <Avatar>\n * <AvatarImage src=\"/user.png\" alt=\"Ada Lovelace\" />\n * <AvatarFallback>AL</AvatarFallback>\n * </Avatar>\n *\n * <Avatar size=\"lg\">\n * <AvatarImage src=\"/user.png\" alt=\"Ada Lovelace\" />\n * <AvatarFallback>AL</AvatarFallback>\n * <AvatarBadge className=\"bg-success\" />\n * </Avatar>\n *\n * <AvatarGroup>\n * <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>\n * <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>\n * <AvatarGroupCount>+4</AvatarGroupCount>\n * </AvatarGroup>\n */\n"],"mappings":";;;;;AAaA,SAAS,OAAO,EACd,WACA,OAAO,WACP,GAAG,SAGF;CACD,OACE,oBAAC,SAAgB,MAAjB;EACE,aAAU;EACV,aAAW;EACX,WAAW,GACT,oHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EACnB,WACA,GAAG,SACkD;CACrD,OACE,oBAAC,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GACT,qDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAyBA,IAAM,iCAAiC;CACrC;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAS,qBAAqB,MAAc;CAC1C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,QAAQ,QAAQ,KAAK,OAAO,KAAK,WAAW,CAAC;EAC7C,QAAQ;CACV;CACA,OAAO,KAAK,IAAI,IAAI,IAAI,+BAA+B;AACzD;AAEA,SAAS,eAAe,EACtB,WACA,WACA,UACA,GAAG,SAYF;CACD,MAAM,OACJ,cAAc,OAAO,aAAa,WAAW,WAAW,KAAA;CAC1D,OACE,oBAAC,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,uGACA,OACI,+BAA+B,qBAAqB,IAAI,KACxD,kCACJ,SACF;EACA,GAAI;EAEH;CACuB,CAAA;AAE9B;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAuC;CAC1E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,4KACA,iFACA,6FACA,iFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,uGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,4VACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge — inline status/category/count label.
|
|
3
|
+
*
|
|
4
|
+
* cva-driven span, non-interactive by default. Styled on two axes — `tone`
|
|
5
|
+
* (what it means) × `emphasis` (how loudly it's drawn) — with the old single
|
|
6
|
+
* `variant` list kept as a deprecated alias.
|
|
7
|
+
*/
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { type VariantProps } from "class-variance-authority";
|
|
10
|
+
declare const badgeVariants: (props?: ({
|
|
11
|
+
tone?: "default" | "secondary" | "destructive" | null | undefined;
|
|
12
|
+
emphasis?: "outline" | "ghost" | "filled" | null | undefined;
|
|
13
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
14
|
+
type BadgeTone = NonNullable<VariantProps<typeof badgeVariants>["tone"]>;
|
|
15
|
+
type BadgeEmphasis = NonNullable<VariantProps<typeof badgeVariants>["emphasis"]>;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated The single `variant` list mixed two axes (what the badge means
|
|
18
|
+
* and how loudly it's drawn). Use `tone` + `emphasis` instead. Still accepted
|
|
19
|
+
* so existing consumers render unchanged: default -> filled default,
|
|
20
|
+
* secondary -> filled secondary, destructive -> filled destructive,
|
|
21
|
+
* outline -> outline default, ghost -> ghost default. `link` (an interaction
|
|
22
|
+
* affordance on a non-interactive label) has no new-axis equivalent and just
|
|
23
|
+
* keeps its old underline look.
|
|
24
|
+
*/
|
|
25
|
+
type BadgeLegacyVariant = "default" | "secondary" | "destructive" | "outline" | "ghost" | "link";
|
|
26
|
+
declare function Badge({ className, tone, emphasis, variant, asChild, truncate, maxWidth, style, children, title, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
27
|
+
asChild?: boolean;
|
|
28
|
+
/** Cuts a label that's too long for its space off with an ellipsis instead of overflowing. Pair with `maxWidth` (or a width from the parent) — without one the badge just sizes to its text. Not applied with `asChild`. */
|
|
29
|
+
truncate?: boolean;
|
|
30
|
+
/** Caps the badge's width (a number is px, or any CSS size) and implies `truncate`. */
|
|
31
|
+
maxWidth?: number | string;
|
|
32
|
+
/** @deprecated use `tone` + `emphasis` */
|
|
33
|
+
variant?: BadgeLegacyVariant;
|
|
34
|
+
}): React.JSX.Element;
|
|
35
|
+
export { Badge, badgeVariants };
|
|
36
|
+
export type { BadgeTone, BadgeEmphasis };
|
|
37
|
+
/**
|
|
38
|
+
* WHEN TO USE
|
|
39
|
+
* - A status, category, count, or tag shown inline with other content
|
|
40
|
+
* (row status, list tag, small metadata chip).
|
|
41
|
+
* - An operational-status indicator (active, failed, expiring, pending) —
|
|
42
|
+
* emphasis="outline" with a small colored icon, not a filled badge. This
|
|
43
|
+
* is Badge's status-indicator convention; there's no separate component
|
|
44
|
+
* for it.
|
|
45
|
+
*
|
|
46
|
+
* NOT WHEN
|
|
47
|
+
* - Interactive filters or removable tags — those need their own
|
|
48
|
+
* click/remove handling, which Badge doesn't provide.
|
|
49
|
+
* - An action — use Button.
|
|
50
|
+
* - Long text — Badge is sized and padded for short labels only. When a user-supplied label might run long anyway (a role or tag name), cap it with `maxWidth` / `truncate`.
|
|
51
|
+
*
|
|
52
|
+
* KEY RULES
|
|
53
|
+
* - `truncate` / `maxWidth` ellipsize a long label and show the full text as a native `title`; icons are untouched. They don't apply with `asChild`.
|
|
54
|
+
* - Non-interactive by default; pass `asChild` to render as an `<a>` when
|
|
55
|
+
* the badge itself needs to link somewhere.
|
|
56
|
+
* - Two axes, not one list. tone: default | secondary | destructive — what the
|
|
57
|
+
* label means. emphasis: filled | outline | ghost — how loudly it's drawn.
|
|
58
|
+
* Every tone×emphasis pair is styled; omit both for a filled default badge.
|
|
59
|
+
* The old single `variant` prop (default, secondary, destructive, outline,
|
|
60
|
+
* ghost, link) still renders identically but is deprecated — it folded the
|
|
61
|
+
* two axes into one list. `link` has no new-axis equivalent: a Badge is
|
|
62
|
+
* non-interactive, so an underlined link look belongs on Button/anchor.
|
|
63
|
+
* - Custom semantic colors (success/warning/alert/info) aren't separate
|
|
64
|
+
* variants — apply the token utility directly, using each status's
|
|
65
|
+
* subtle `-light`/`-text` pair (not the solid `-foreground` pairing,
|
|
66
|
+
* which reads too loud for an inline tag), e.g. `className="bg-success-light
|
|
67
|
+
* text-success-text"`.
|
|
68
|
+
* - Status-indicator convention: emphasis="outline" + a leading icon colored
|
|
69
|
+
* with the matching semantic token, `data-icon="inline-start"`. Fixed
|
|
70
|
+
* icon/color pairing, don't substitute other icons for these:
|
|
71
|
+
* success -> CheckIcon text-success
|
|
72
|
+
* alert -> XIcon text-alert (text-destructive for a true error, not just "alert")
|
|
73
|
+
* warning -> TriangleAlertIcon text-warning
|
|
74
|
+
* info -> InfoIcon text-info
|
|
75
|
+
* default -> PenLineIcon text-muted-foreground
|
|
76
|
+
* - Flush status-indicator variant: the same icon/color pairing above, but
|
|
77
|
+
* `emphasis="ghost"` (no border, no fill) plus
|
|
78
|
+
* `className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"`
|
|
79
|
+
* — the padding overrides zero out what `emphasis="outline"` needs for
|
|
80
|
+
* its own chip look but this doesn't, and `hover:bg-transparent` drops
|
|
81
|
+
* `ghost`'s subtle hover highlight (meant for when Badge is `asChild` as
|
|
82
|
+
* a real link), which a flush, non-interactive status doesn't need. For
|
|
83
|
+
* a status that needs to sit flush against other plain content instead
|
|
84
|
+
* of reading as its own separate chip: a `KeyValuePairValue` slot, a
|
|
85
|
+
* table cell (especially one with a `MetaList` underneath, where a
|
|
86
|
+
* padded chip would misalign against the MetaList's own flush left/right
|
|
87
|
+
* edges), or right-aligned in a flex row next to one.
|
|
88
|
+
* - An AI-assigned status/tag is a plain composition, not a variant: keep the Badge exactly
|
|
89
|
+
* as the status calls for and put `AILabel` (size="sm" — never the opt-in icon-only "xs" by
|
|
90
|
+
* default) beside it in an `inline-flex` span. Never restyle the Badge itself
|
|
91
|
+
* with the AI gradient — that would be indistinguishable from Button's AI Chip
|
|
92
|
+
* (variant="ai" rounded-full), and the two must read apart: the Chip is an action, a Badge
|
|
93
|
+
* is not. See AI/Badge.
|
|
94
|
+
*
|
|
95
|
+
* USAGE
|
|
96
|
+
* <Badge>Default</Badge>
|
|
97
|
+
* <Badge tone="destructive">Overdue</Badge>
|
|
98
|
+
* <Badge tone="secondary" emphasis="ghost">Draft</Badge>
|
|
99
|
+
* <Badge className="bg-success-light text-success-text">Success</Badge>
|
|
100
|
+
* <Badge><CheckIcon />Verified</Badge>
|
|
101
|
+
* <Badge maxWidth={120}>Regional Clinical Operations Lead</Badge>
|
|
102
|
+
*
|
|
103
|
+
* // Status indicator convention
|
|
104
|
+
* <Badge emphasis="outline">
|
|
105
|
+
* <CheckIcon className="text-success" data-icon="inline-start" />
|
|
106
|
+
* Active
|
|
107
|
+
* </Badge>
|
|
108
|
+
* <Badge emphasis="outline">
|
|
109
|
+
* <XIcon className="text-alert" data-icon="inline-start" />
|
|
110
|
+
* Failed
|
|
111
|
+
* </Badge>
|
|
112
|
+
* <Badge emphasis="outline">
|
|
113
|
+
* <TriangleAlertIcon className="text-warning" data-icon="inline-start" />
|
|
114
|
+
* Expiring soon
|
|
115
|
+
* </Badge>
|
|
116
|
+
* <Badge emphasis="outline">
|
|
117
|
+
* <PenLineIcon className="text-muted-foreground" data-icon="inline-start" />
|
|
118
|
+
* Draft
|
|
119
|
+
* </Badge>
|
|
120
|
+
*
|
|
121
|
+
* // Flush status indicator — KVP value, table cell, or right-aligned next to a MetaList
|
|
122
|
+
* <Badge
|
|
123
|
+
* emphasis="ghost"
|
|
124
|
+
* className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"
|
|
125
|
+
* >
|
|
126
|
+
* <CheckIcon className="text-success" data-icon="inline-start" />
|
|
127
|
+
* Active
|
|
128
|
+
* </Badge>
|
|
129
|
+
*/
|
|
130
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/components/ui/badge.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE,QAAA,MAAM,aAAa;;;8EA8ElB,CAAA;AAED,KAAK,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AACxE,KAAK,aAAa,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;AAChF;;;;;;;;GAQG;AACH,KAAK,kBAAkB,GACrB,SAAS,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAaxE,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,OAAe,EACf,QAAgB,EAChB,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAC7B,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4NAA4N;IAC5N,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,0CAA0C;IAC1C,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAC7B,qBAiDF;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA;AAC/B,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG"}
|