@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,89 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { Separator as Separator$1 } from "./separator.js";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
//#region src/components/ui/button-group.tsx
|
|
7
|
+
/**
|
|
8
|
+
* ButtonGroup — joins adjacent buttons into one segmented control.
|
|
9
|
+
*
|
|
10
|
+
* A plain flex container (`role="group"`) that strips inner borders/radii so
|
|
11
|
+
* a row (or column) of Buttons reads as a single control. ButtonGroupText
|
|
12
|
+
* and ButtonGroupSeparator are the non-interactive-affix and divider
|
|
13
|
+
* sub-parts.
|
|
14
|
+
*/
|
|
15
|
+
var buttonGroupVariants = cva("group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", {
|
|
16
|
+
variants: { orientation: {
|
|
17
|
+
horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg!",
|
|
18
|
+
vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg!"
|
|
19
|
+
} },
|
|
20
|
+
defaultVariants: { orientation: "horizontal" }
|
|
21
|
+
});
|
|
22
|
+
function ButtonGroup({ className, orientation, ...props }) {
|
|
23
|
+
return /* @__PURE__ */ jsx("div", {
|
|
24
|
+
role: "group",
|
|
25
|
+
"data-slot": "button-group",
|
|
26
|
+
"data-orientation": orientation,
|
|
27
|
+
className: cn(buttonGroupVariants({ orientation }), className),
|
|
28
|
+
...props
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function ButtonGroupText({ className, asChild = false, ...props }) {
|
|
32
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
33
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
34
|
+
className: cn("flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", className),
|
|
35
|
+
...props
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function ButtonGroupSeparator({ className, orientation = "vertical", ...props }) {
|
|
39
|
+
return /* @__PURE__ */ jsx(Separator$1, {
|
|
40
|
+
"data-slot": "button-group-separator",
|
|
41
|
+
orientation,
|
|
42
|
+
className: cn("relative self-stretch bg-input data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto", className),
|
|
43
|
+
...props
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* WHEN TO USE
|
|
48
|
+
* - Segmented view switchers (Day / Week / Month) rendered as adjacent Buttons
|
|
49
|
+
* - Split buttons: a primary action followed by a menu-trigger button, separated by ButtonGroupSeparator
|
|
50
|
+
* - An input with an attached prefix/suffix action (e.g. a URL scheme label + input + copy button)
|
|
51
|
+
*
|
|
52
|
+
* NOT WHEN
|
|
53
|
+
* - Actions that aren't visually or functionally related — use separate Buttons with normal spacing
|
|
54
|
+
* - A single action — use Button directly
|
|
55
|
+
* - Exclusive selection of one value from a set — use ToggleGroup type="single"
|
|
56
|
+
*
|
|
57
|
+
* KEY RULES
|
|
58
|
+
* - orientation: horizontal (default) | vertical — controls which edges collapse
|
|
59
|
+
* - Children must be direct DOM siblings (Button, Input, ButtonGroupText, ButtonGroupSeparator, a nested
|
|
60
|
+
* ButtonGroup, or a Select) — the border/radius-collapsing CSS only targets immediate children
|
|
61
|
+
* - ButtonGroupText renders a static, non-interactive affix — it isn't a button and takes no onClick
|
|
62
|
+
* - ButtonGroupSeparator defaults to a vertical divider — pass orientation="horizontal" inside a
|
|
63
|
+
* vertical ButtonGroup
|
|
64
|
+
* - role="group" is applied automatically; add aria-label when the group's purpose isn't clear from
|
|
65
|
+
* its visible content
|
|
66
|
+
*
|
|
67
|
+
* USAGE
|
|
68
|
+
* <ButtonGroup>
|
|
69
|
+
* <Button variant="outline">Day</Button>
|
|
70
|
+
* <Button variant="outline">Week</Button>
|
|
71
|
+
* <Button variant="outline">Month</Button>
|
|
72
|
+
* </ButtonGroup>
|
|
73
|
+
*
|
|
74
|
+
* <ButtonGroup>
|
|
75
|
+
* <Button><ShareIcon />Share</Button>
|
|
76
|
+
* <ButtonGroupSeparator />
|
|
77
|
+
* <Button iconOnly aria-label="More share options"><ChevronDownIcon /></Button>
|
|
78
|
+
* </ButtonGroup>
|
|
79
|
+
*
|
|
80
|
+
* <ButtonGroup>
|
|
81
|
+
* <ButtonGroupText>https://</ButtonGroupText>
|
|
82
|
+
* <Input placeholder="example.com" />
|
|
83
|
+
* <Button variant="outline" iconOnly aria-label="Copy URL"><CopyIcon /></Button>
|
|
84
|
+
* </ButtonGroup>
|
|
85
|
+
*/
|
|
86
|
+
//#endregion
|
|
87
|
+
export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=button-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-group.js","names":[],"sources":["../../../src/components/ui/button-group.tsx"],"sourcesContent":["/**\n * ButtonGroup — joins adjacent buttons into one segmented control.\n *\n * A plain flex container (`role=\"group\"`) that strips inner borders/radii so\n * a row (or column) of Buttons reads as a single control. ButtonGroupText\n * and ButtonGroupSeparator are the non-interactive-affix and divider\n * sub-parts.\n */\n\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Separator } from \"@/components/ui/separator\"\n\nconst buttonGroupVariants = cva(\n \"group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg!\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg!\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"div\"\n\n return (\n <Comp\n className={cn(\n \"flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"relative self-stretch bg-input data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n}\n\n/**\n * WHEN TO USE\n * - Segmented view switchers (Day / Week / Month) rendered as adjacent Buttons\n * - Split buttons: a primary action followed by a menu-trigger button, separated by ButtonGroupSeparator\n * - An input with an attached prefix/suffix action (e.g. a URL scheme label + input + copy button)\n *\n * NOT WHEN\n * - Actions that aren't visually or functionally related — use separate Buttons with normal spacing\n * - A single action — use Button directly\n * - Exclusive selection of one value from a set — use ToggleGroup type=\"single\"\n *\n * KEY RULES\n * - orientation: horizontal (default) | vertical — controls which edges collapse\n * - Children must be direct DOM siblings (Button, Input, ButtonGroupText, ButtonGroupSeparator, a nested\n * ButtonGroup, or a Select) — the border/radius-collapsing CSS only targets immediate children\n * - ButtonGroupText renders a static, non-interactive affix — it isn't a button and takes no onClick\n * - ButtonGroupSeparator defaults to a vertical divider — pass orientation=\"horizontal\" inside a\n * vertical ButtonGroup\n * - role=\"group\" is applied automatically; add aria-label when the group's purpose isn't clear from\n * its visible content\n *\n * USAGE\n * <ButtonGroup>\n * <Button variant=\"outline\">Day</Button>\n * <Button variant=\"outline\">Week</Button>\n * <Button variant=\"outline\">Month</Button>\n * </ButtonGroup>\n *\n * <ButtonGroup>\n * <Button><ShareIcon />Share</Button>\n * <ButtonGroupSeparator />\n * <Button iconOnly aria-label=\"More share options\"><ChevronDownIcon /></Button>\n * </ButtonGroup>\n *\n * <ButtonGroup>\n * <ButtonGroupText>https://</ButtonGroupText>\n * <Input placeholder=\"example.com\" />\n * <Button variant=\"outline\" iconOnly aria-label=\"Copy URL\"><CopyIcon /></Button>\n * </ButtonGroup>\n */\n"],"mappings":";;;;;;;;;;;;;;AAeA,IAAM,sBAAsB,IAC1B,+SACA;CACE,UAAU,EACR,aAAa;EACX,YACE;EACF,UACE;CACJ,EACF;CACA,iBAAiB,EACf,aAAa,aACf;AACF,CACF;AAEA,SAAS,YAAY,EACnB,WACA,aACA,GAAG,SACsE;CACzE,OACE,oBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,oBAAkB;EAClB,WAAW,GAAG,oBAAoB,EAAE,YAAY,CAAC,GAAG,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,WACA,UAAU,OACV,GAAG,SAGF;CACD,MAAM,OAAO,UAAU,KAAK,OAAO;CAEnC,OACE,oBAAC,MAAD;EACE,WAAW,GACT,kJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,qBAAqB,EAC5B,WACA,cAAc,YACd,GAAG,SACsC;CACzC,OACE,oBAAC,aAAD;EACE,aAAU;EACG;EACb,WAAW,GACT,gLACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button — action trigger.
|
|
3
|
+
*
|
|
4
|
+
* A cva-driven `<button>` (or the child element, via `asChild`/Slot) with
|
|
5
|
+
* seven color variants and eight sizes, four of them icon-only squares.
|
|
6
|
+
* Includes xs and sm size steps plus `iconOnly`,
|
|
7
|
+
* an `ai` variant for AI-powered actions, plus a
|
|
8
|
+
* `data-icon="inline-start"|"inline-end"` attribute consumers put on a child
|
|
9
|
+
* icon so the size's padding self-adjusts on that side instead of needing a
|
|
10
|
+
* manual gap/margin per usage.
|
|
11
|
+
*
|
|
12
|
+
* `variant="ai"` marks genuine AI involvement only, never decoration or
|
|
13
|
+
* emphasis — see manifest.json's `ai_presence` convention for the full rule
|
|
14
|
+
* and every current AI-treatment recipe (this variant, the AI Icon Button
|
|
15
|
+
* and AI Chip recipes below, the AI Card recipe, DataTable's row tint, and
|
|
16
|
+
* AILabel for the accessible explainability entry point specifically).
|
|
17
|
+
*/
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { type VariantProps } from "class-variance-authority";
|
|
20
|
+
declare const buttonVariants: (props?: ({
|
|
21
|
+
variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | "ai" | null | undefined;
|
|
22
|
+
size?: "sm" | "lg" | "default" | "xs" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
23
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
24
|
+
type TextButtonSize = "default" | "xs" | "sm" | "lg";
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Icon-only is not a size — it's a shape. Use `iconOnly` with a
|
|
27
|
+
* plain size instead (`size="xs" iconOnly` in place of `size="icon-xs"`).
|
|
28
|
+
* These values still render identically so existing consumers keep working.
|
|
29
|
+
*/
|
|
30
|
+
type IconOnlyButtonSize = "icon" | "icon-xs" | "icon-sm" | "icon-lg";
|
|
31
|
+
/**
|
|
32
|
+
* `aria-label` is required whenever the button is icon-only (`iconOnly`, or
|
|
33
|
+
* one of the deprecated icon-* sizes) — there's no visible text for a screen
|
|
34
|
+
* reader to fall back on. Enforced as a type, not just documented, so
|
|
35
|
+
* omitting it is a build error instead of a silent accessibility gap. If a
|
|
36
|
+
* consumer already gives the button its name another way (e.g. a
|
|
37
|
+
* visually-hidden text child), pass `aria-label` too — redundant with that,
|
|
38
|
+
* but harmless, and it's what satisfies the type.
|
|
39
|
+
*
|
|
40
|
+
* Exempted when `asChild` is true: Slot renders the child element in the
|
|
41
|
+
* button's place, so the accessible name (visible text, its own aria-label,
|
|
42
|
+
* whatever) comes from that child, not from anything passed to `Button` here.
|
|
43
|
+
*/
|
|
44
|
+
type ButtonProps = Omit<React.ComponentProps<"button">, "aria-label"> & {
|
|
45
|
+
variant?: VariantProps<typeof buttonVariants>["variant"];
|
|
46
|
+
} & ({
|
|
47
|
+
asChild: true;
|
|
48
|
+
size?: TextButtonSize | IconOnlyButtonSize;
|
|
49
|
+
iconOnly?: boolean;
|
|
50
|
+
"aria-label"?: string;
|
|
51
|
+
} | {
|
|
52
|
+
asChild?: false;
|
|
53
|
+
/** Square, icon-only button at the given `size` step — no text, so `aria-label` is required. */
|
|
54
|
+
iconOnly: true;
|
|
55
|
+
size?: TextButtonSize;
|
|
56
|
+
"aria-label": string;
|
|
57
|
+
} | {
|
|
58
|
+
asChild?: false;
|
|
59
|
+
iconOnly?: false;
|
|
60
|
+
/** @deprecated use `iconOnly` with a text size */
|
|
61
|
+
size: IconOnlyButtonSize;
|
|
62
|
+
"aria-label": string;
|
|
63
|
+
} | {
|
|
64
|
+
asChild?: false;
|
|
65
|
+
iconOnly?: false;
|
|
66
|
+
size?: TextButtonSize;
|
|
67
|
+
"aria-label"?: string;
|
|
68
|
+
});
|
|
69
|
+
declare function Button({ className, variant, size, iconOnly, asChild, ...props }: ButtonProps): React.JSX.Element;
|
|
70
|
+
export { Button, buttonVariants };
|
|
71
|
+
export type { IconOnlyButtonSize, TextButtonSize };
|
|
72
|
+
/**
|
|
73
|
+
* WHEN TO USE
|
|
74
|
+
* - Form submission, navigation, state changes, primary/secondary CTAs
|
|
75
|
+
* - Icon-only actions — `iconOnly` at the matching size, not a text size with a bare icon
|
|
76
|
+
*
|
|
77
|
+
* NOT WHEN
|
|
78
|
+
* - An inline text hyperlink — use an anchor, or variant="link"
|
|
79
|
+
* - Icon-only without an aria-label — screen readers get nothing to announce
|
|
80
|
+
* - A non-interactive status indicator — use Badge
|
|
81
|
+
*
|
|
82
|
+
* KEY RULES
|
|
83
|
+
* - variant: default | outline | secondary | ghost | destructive | link | ai (default "default")
|
|
84
|
+
* - size: default | xs | sm | lg (default "default") — how tall the button is
|
|
85
|
+
* - iconOnly: a square, text-less button at that same size step (h-8 -> 8x8 at default, and so on).
|
|
86
|
+
* Two separate axes on purpose: icon-only is a shape, not a size, so `size="sm" iconOnly` and
|
|
87
|
+
* `size="sm"` line up in the same row. `aria-label` is required whenever `iconOnly` is set —
|
|
88
|
+
* enforced at the type level. The old `size="icon" | "icon-xs" | "icon-sm" | "icon-lg"` values
|
|
89
|
+
* still render identically but are deprecated aliases; don't write new code with them.
|
|
90
|
+
* - asChild renders the child element via Slot instead of a <button> — for wrapping an <a> or router Link
|
|
91
|
+
* - A leading/trailing icon needs data-icon="inline-start" / "inline-end" on the icon element so the
|
|
92
|
+
* size's built-in padding collapses correctly on that side
|
|
93
|
+
* - Only one destructive-intent button per confirming action — don't pair with a second destructive button
|
|
94
|
+
* - variant="ai" marks an action as AI-powered with the AI Gradient — a gold-to-pink wash
|
|
95
|
+
* (--color-ai-wash / --color-ai-grad-from) that deepens on hover/active.
|
|
96
|
+
* Add `AISparkle` (from ai-sparkle.tsx) as a leading icon via data-icon="inline-start" for the
|
|
97
|
+
* "with sparkle" emphasis — there's no separate prop for it, it's the same icon-slot convention
|
|
98
|
+
* as any other button
|
|
99
|
+
* - An icon-only "AI Icon Button" is variant="ai" with `iconOnly`, same persistent gradient and
|
|
100
|
+
* hover/active states as the text "AI Button" — not variant="ghost" with the gradient added
|
|
101
|
+
* only on hover. The AI Gradient background is what signals "AI" here, so the icon itself is
|
|
102
|
+
* free: AISparkle alone (a pure "Ask AI" trigger with no other icon), or any domain icon
|
|
103
|
+
* (BotIcon, SendIcon, whatever fits the action) plus a small AISparkle corner accent for
|
|
104
|
+
* emphasis — same background either way. For the corner-accent version, put it INSIDE the
|
|
105
|
+
* button itself (className="relative" on the Button, AISparkle absolutely placed at
|
|
106
|
+
* top-1 right-1, size-3) — not a sibling overhanging the outer edge, which risks getting
|
|
107
|
+
* clipped by a cramped ancestor's overflow-hidden (e.g. a Sidecar panel). top-1/right-1 lands
|
|
108
|
+
* it overlapping the centered icon's own corner by about 4px at a default icon-size button.
|
|
109
|
+
* - An "AI Chip" is variant="ai" at a small size with a rounded-full override — Badge can't be used
|
|
110
|
+
* here because it's non-interactive and this needs to stay clickable
|
|
111
|
+
* - A plain "Chip" (e.g. a removable applied-filter pill) is variant="outline" at size="sm" with
|
|
112
|
+
* the same rounded-full override, plus a trailing remove icon via data-icon="inline-end" —
|
|
113
|
+
* again Button, not Badge, because the whole pill is clickable (e.g. to remove itself)
|
|
114
|
+
* - An "Expanded Button" (full width) is `className="w-full"` — Button never adds its own margin
|
|
115
|
+
* or width logic, so the gutter around it always comes from whatever surface it's on (a Card's
|
|
116
|
+
* own padding, a Dialog/Sheet footer's own inset), never from the button itself
|
|
117
|
+
*
|
|
118
|
+
* USAGE
|
|
119
|
+
* <Button variant="destructive" onClick={handleDelete}>Delete</Button>
|
|
120
|
+
* <Button iconOnly aria-label="Add"><PlusIcon /></Button>
|
|
121
|
+
* <Button size="sm" iconOnly aria-label="Add"><PlusIcon /></Button>
|
|
122
|
+
* <Button variant="outline">
|
|
123
|
+
* Continue
|
|
124
|
+
* <ArrowRightIcon data-icon="inline-end" />
|
|
125
|
+
* </Button>
|
|
126
|
+
*
|
|
127
|
+
* // AI Button — default and "with sparkle"
|
|
128
|
+
* <Button variant="ai">Summarize</Button>
|
|
129
|
+
* <Button variant="ai">
|
|
130
|
+
* <AISparkle data-icon="inline-start" />
|
|
131
|
+
* Summarize
|
|
132
|
+
* </Button>
|
|
133
|
+
*
|
|
134
|
+
* // AI Icon Button — AISparkle alone, a pure "Ask AI" trigger
|
|
135
|
+
* <Button variant="ai" iconOnly aria-label="Ask AI">
|
|
136
|
+
* <AISparkle />
|
|
137
|
+
* </Button>
|
|
138
|
+
*
|
|
139
|
+
* // AI Icon Button — a domain icon instead, same AI Gradient background, corner sparkle inside the button
|
|
140
|
+
* <Button variant="ai" iconOnly aria-label="Ask AI" className="relative">
|
|
141
|
+
* <BotIcon />
|
|
142
|
+
* <AISparkle className="absolute top-1 right-1 size-3" />
|
|
143
|
+
* </Button>
|
|
144
|
+
*
|
|
145
|
+
* // AI Chip — a small rounded-full action chip, not a Badge (needs to stay clickable)
|
|
146
|
+
* <Button variant="ai" size="xs" className="rounded-full">
|
|
147
|
+
* <AISparkle data-icon="inline-start" />
|
|
148
|
+
* Ask Sara
|
|
149
|
+
* </Button>
|
|
150
|
+
*
|
|
151
|
+
* // Chip — a removable pill (e.g. an applied filter), icon trails the label
|
|
152
|
+
* <Button variant="outline" size="sm" className="rounded-full" onClick={handleRemove}>
|
|
153
|
+
* Status: Paid
|
|
154
|
+
* <XIcon data-icon="inline-end" />
|
|
155
|
+
* </Button>
|
|
156
|
+
*/
|
|
157
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/components/ui/button.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE,QAAA,MAAM,cAAc;;;8EAkDnB,CAAA;AAED,KAAK,cAAc,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AACpD;;;;GAIG;AACH,KAAK,kBAAkB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;AAYpE;;;;;;;;;;;;GAYG;AACH,KAAK,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,GAAG;IACtE,OAAO,CAAC,EAAE,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC,SAAS,CAAC,CAAA;CACzD,GAAG,CACE;IACE,OAAO,EAAE,IAAI,CAAA;IACb,IAAI,CAAC,EAAE,cAAc,GAAG,kBAAkB,CAAA;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GACD;IACE,OAAO,CAAC,EAAE,KAAK,CAAA;IACf,gGAAgG;IAChG,QAAQ,EAAE,IAAI,CAAA;IACd,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,GACD;IACE,OAAO,CAAC,EAAE,KAAK,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,kDAAkD;IAClD,IAAI,EAAE,kBAAkB,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;CACrB,GACD;IACE,OAAO,CAAC,EAAE,KAAK,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CACJ,CAAA;AAEH,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,QAAgB,EAChB,OAAe,EACf,GAAG,KAAK,EACT,EAAE,WAAW,qBAiBb;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AACjC,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
//#region src/components/ui/button.tsx
|
|
7
|
+
var buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform] outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active focus-visible:border-primary-foreground",
|
|
11
|
+
outline: "border-border hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
13
|
+
ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
14
|
+
destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
15
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
16
|
+
ai: "bg-gradient-to-r from-ai-wash/20 to-ai-grad-from/20 text-foreground hover:from-ai-wash/28 hover:to-ai-grad-from/28 active:from-ai-wash/36 active:to-ai-grad-from/36 aria-expanded:from-ai-wash/28 aria-expanded:to-ai-grad-from/28"
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
20
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md,0.375rem),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
21
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md,0.375rem),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
22
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
23
|
+
icon: "size-8",
|
|
24
|
+
"icon-xs": "size-6 rounded-[min(var(--radius-md,0.375rem),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
|
25
|
+
"icon-sm": "size-7 rounded-[min(var(--radius-md,0.375rem),12px)] in-data-[slot=button-group]:rounded-lg",
|
|
26
|
+
"icon-lg": "size-9"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
size: "default"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
var ICON_ONLY_SIZE = {
|
|
35
|
+
default: "icon",
|
|
36
|
+
xs: "icon-xs",
|
|
37
|
+
sm: "icon-sm",
|
|
38
|
+
lg: "icon-lg"
|
|
39
|
+
};
|
|
40
|
+
function Button({ className, variant = "default", size = "default", iconOnly = false, asChild = false, ...props }) {
|
|
41
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
42
|
+
const resolvedSize = iconOnly && size in ICON_ONLY_SIZE ? ICON_ONLY_SIZE[size] : size;
|
|
43
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
44
|
+
"data-slot": "button",
|
|
45
|
+
"data-variant": variant,
|
|
46
|
+
"data-size": resolvedSize,
|
|
47
|
+
"data-icon-only": iconOnly || resolvedSize !== size ? true : void 0,
|
|
48
|
+
className: cn(buttonVariants({
|
|
49
|
+
variant,
|
|
50
|
+
size: resolvedSize,
|
|
51
|
+
className
|
|
52
|
+
})),
|
|
53
|
+
...props
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* WHEN TO USE
|
|
58
|
+
* - Form submission, navigation, state changes, primary/secondary CTAs
|
|
59
|
+
* - Icon-only actions — `iconOnly` at the matching size, not a text size with a bare icon
|
|
60
|
+
*
|
|
61
|
+
* NOT WHEN
|
|
62
|
+
* - An inline text hyperlink — use an anchor, or variant="link"
|
|
63
|
+
* - Icon-only without an aria-label — screen readers get nothing to announce
|
|
64
|
+
* - A non-interactive status indicator — use Badge
|
|
65
|
+
*
|
|
66
|
+
* KEY RULES
|
|
67
|
+
* - variant: default | outline | secondary | ghost | destructive | link | ai (default "default")
|
|
68
|
+
* - size: default | xs | sm | lg (default "default") — how tall the button is
|
|
69
|
+
* - iconOnly: a square, text-less button at that same size step (h-8 -> 8x8 at default, and so on).
|
|
70
|
+
* Two separate axes on purpose: icon-only is a shape, not a size, so `size="sm" iconOnly` and
|
|
71
|
+
* `size="sm"` line up in the same row. `aria-label` is required whenever `iconOnly` is set —
|
|
72
|
+
* enforced at the type level. The old `size="icon" | "icon-xs" | "icon-sm" | "icon-lg"` values
|
|
73
|
+
* still render identically but are deprecated aliases; don't write new code with them.
|
|
74
|
+
* - asChild renders the child element via Slot instead of a <button> — for wrapping an <a> or router Link
|
|
75
|
+
* - A leading/trailing icon needs data-icon="inline-start" / "inline-end" on the icon element so the
|
|
76
|
+
* size's built-in padding collapses correctly on that side
|
|
77
|
+
* - Only one destructive-intent button per confirming action — don't pair with a second destructive button
|
|
78
|
+
* - variant="ai" marks an action as AI-powered with the AI Gradient — a gold-to-pink wash
|
|
79
|
+
* (--color-ai-wash / --color-ai-grad-from) that deepens on hover/active.
|
|
80
|
+
* Add `AISparkle` (from ai-sparkle.tsx) as a leading icon via data-icon="inline-start" for the
|
|
81
|
+
* "with sparkle" emphasis — there's no separate prop for it, it's the same icon-slot convention
|
|
82
|
+
* as any other button
|
|
83
|
+
* - An icon-only "AI Icon Button" is variant="ai" with `iconOnly`, same persistent gradient and
|
|
84
|
+
* hover/active states as the text "AI Button" — not variant="ghost" with the gradient added
|
|
85
|
+
* only on hover. The AI Gradient background is what signals "AI" here, so the icon itself is
|
|
86
|
+
* free: AISparkle alone (a pure "Ask AI" trigger with no other icon), or any domain icon
|
|
87
|
+
* (BotIcon, SendIcon, whatever fits the action) plus a small AISparkle corner accent for
|
|
88
|
+
* emphasis — same background either way. For the corner-accent version, put it INSIDE the
|
|
89
|
+
* button itself (className="relative" on the Button, AISparkle absolutely placed at
|
|
90
|
+
* top-1 right-1, size-3) — not a sibling overhanging the outer edge, which risks getting
|
|
91
|
+
* clipped by a cramped ancestor's overflow-hidden (e.g. a Sidecar panel). top-1/right-1 lands
|
|
92
|
+
* it overlapping the centered icon's own corner by about 4px at a default icon-size button.
|
|
93
|
+
* - An "AI Chip" is variant="ai" at a small size with a rounded-full override — Badge can't be used
|
|
94
|
+
* here because it's non-interactive and this needs to stay clickable
|
|
95
|
+
* - A plain "Chip" (e.g. a removable applied-filter pill) is variant="outline" at size="sm" with
|
|
96
|
+
* the same rounded-full override, plus a trailing remove icon via data-icon="inline-end" —
|
|
97
|
+
* again Button, not Badge, because the whole pill is clickable (e.g. to remove itself)
|
|
98
|
+
* - An "Expanded Button" (full width) is `className="w-full"` — Button never adds its own margin
|
|
99
|
+
* or width logic, so the gutter around it always comes from whatever surface it's on (a Card's
|
|
100
|
+
* own padding, a Dialog/Sheet footer's own inset), never from the button itself
|
|
101
|
+
*
|
|
102
|
+
* USAGE
|
|
103
|
+
* <Button variant="destructive" onClick={handleDelete}>Delete</Button>
|
|
104
|
+
* <Button iconOnly aria-label="Add"><PlusIcon /></Button>
|
|
105
|
+
* <Button size="sm" iconOnly aria-label="Add"><PlusIcon /></Button>
|
|
106
|
+
* <Button variant="outline">
|
|
107
|
+
* Continue
|
|
108
|
+
* <ArrowRightIcon data-icon="inline-end" />
|
|
109
|
+
* </Button>
|
|
110
|
+
*
|
|
111
|
+
* // AI Button — default and "with sparkle"
|
|
112
|
+
* <Button variant="ai">Summarize</Button>
|
|
113
|
+
* <Button variant="ai">
|
|
114
|
+
* <AISparkle data-icon="inline-start" />
|
|
115
|
+
* Summarize
|
|
116
|
+
* </Button>
|
|
117
|
+
*
|
|
118
|
+
* // AI Icon Button — AISparkle alone, a pure "Ask AI" trigger
|
|
119
|
+
* <Button variant="ai" iconOnly aria-label="Ask AI">
|
|
120
|
+
* <AISparkle />
|
|
121
|
+
* </Button>
|
|
122
|
+
*
|
|
123
|
+
* // AI Icon Button — a domain icon instead, same AI Gradient background, corner sparkle inside the button
|
|
124
|
+
* <Button variant="ai" iconOnly aria-label="Ask AI" className="relative">
|
|
125
|
+
* <BotIcon />
|
|
126
|
+
* <AISparkle className="absolute top-1 right-1 size-3" />
|
|
127
|
+
* </Button>
|
|
128
|
+
*
|
|
129
|
+
* // AI Chip — a small rounded-full action chip, not a Badge (needs to stay clickable)
|
|
130
|
+
* <Button variant="ai" size="xs" className="rounded-full">
|
|
131
|
+
* <AISparkle data-icon="inline-start" />
|
|
132
|
+
* Ask Sara
|
|
133
|
+
* </Button>
|
|
134
|
+
*
|
|
135
|
+
* // Chip — a removable pill (e.g. an applied filter), icon trails the label
|
|
136
|
+
* <Button variant="outline" size="sm" className="rounded-full" onClick={handleRemove}>
|
|
137
|
+
* Status: Paid
|
|
138
|
+
* <XIcon data-icon="inline-end" />
|
|
139
|
+
* </Button>
|
|
140
|
+
*/
|
|
141
|
+
//#endregion
|
|
142
|
+
export { Button, buttonVariants };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","names":[],"sources":["../../../src/components/ui/button.tsx"],"sourcesContent":["/**\n * Button — action trigger.\n *\n * A cva-driven `<button>` (or the child element, via `asChild`/Slot) with\n * seven color variants and eight sizes, four of them icon-only squares.\n * Includes xs and sm size steps plus `iconOnly`,\n * an `ai` variant for AI-powered actions, plus a\n * `data-icon=\"inline-start\"|\"inline-end\"` attribute consumers put on a child\n * icon so the size's padding self-adjusts on that side instead of needing a\n * manual gap/margin per usage.\n *\n * `variant=\"ai\"` marks genuine AI involvement only, never decoration or\n * emphasis — see manifest.json's `ai_presence` convention for the full rule\n * and every current AI-treatment recipe (this variant, the AI Icon Button\n * and AI Chip recipes below, the AI Card recipe, DataTable's row tint, and\n * AILabel for the accessible explainability entry point specifically).\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\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform] outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n // focus-visible:border-primary-foreground overrides the base\n // recipe's border-ring specifically for this variant: ring-ring is\n // a deeper step of primary by design (blue-950 next to blue-900),\n // so on this variant alone the focus border sits directly against\n // a fill just one step away from its own color — computed contrast\n // is ~1.3:1 light / ~1.06:1 dark, far under 1.4.11's 3:1 floor.\n // primary-foreground is already contrast-verified against bg-primary\n // itself (the same pairing text sits on, checked at build time by\n // scripts/check-foreground-contrast.mjs), so reusing it here is a\n // real fix, not a new unverified color. The outward ring-3\n // ring-ring/50 box-shadow is untouched — it lands on whatever\n // surface surrounds the button, not on the button's own fill, and\n // that comparison already clears 3:1.\n default:\n \"bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active focus-visible:border-primary-foreground\",\n outline:\n \"border-border hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n ai: \"bg-gradient-to-r from-ai-wash/20 to-ai-grad-from/20 text-foreground hover:from-ai-wash/28 hover:to-ai-grad-from/28 active:from-ai-wash/36 active:to-ai-grad-from/36 aria-expanded:from-ai-wash/28 aria-expanded:to-ai-grad-from/28\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md,0.375rem),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-[min(var(--radius-md,0.375rem),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md,0.375rem),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-7 rounded-[min(var(--radius-md,0.375rem),12px)] in-data-[slot=button-group]:rounded-lg\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\ntype TextButtonSize = \"default\" | \"xs\" | \"sm\" | \"lg\"\n/**\n * @deprecated Icon-only is not a size — it's a shape. Use `iconOnly` with a\n * plain size instead (`size=\"xs\" iconOnly` in place of `size=\"icon-xs\"`).\n * These values still render identically so existing consumers keep working.\n */\ntype IconOnlyButtonSize = \"icon\" | \"icon-xs\" | \"icon-sm\" | \"icon-lg\"\n\n// `iconOnly` + a text size resolves to the square cva size of the same\n// step. The cva keeps the icon-* keys as its implementation detail; the\n// public vocabulary is size (how tall) x iconOnly (square, no text).\nconst ICON_ONLY_SIZE: Record<TextButtonSize, IconOnlyButtonSize> = {\n default: \"icon\",\n xs: \"icon-xs\",\n sm: \"icon-sm\",\n lg: \"icon-lg\",\n}\n\n/**\n * `aria-label` is required whenever the button is icon-only (`iconOnly`, or\n * one of the deprecated icon-* sizes) — there's no visible text for a screen\n * reader to fall back on. Enforced as a type, not just documented, so\n * omitting it is a build error instead of a silent accessibility gap. If a\n * consumer already gives the button its name another way (e.g. a\n * visually-hidden text child), pass `aria-label` too — redundant with that,\n * but harmless, and it's what satisfies the type.\n *\n * Exempted when `asChild` is true: Slot renders the child element in the\n * button's place, so the accessible name (visible text, its own aria-label,\n * whatever) comes from that child, not from anything passed to `Button` here.\n */\ntype ButtonProps = Omit<React.ComponentProps<\"button\">, \"aria-label\"> & {\n variant?: VariantProps<typeof buttonVariants>[\"variant\"]\n} & (\n | {\n asChild: true\n size?: TextButtonSize | IconOnlyButtonSize\n iconOnly?: boolean\n \"aria-label\"?: string\n }\n | {\n asChild?: false\n /** Square, icon-only button at the given `size` step — no text, so `aria-label` is required. */\n iconOnly: true\n size?: TextButtonSize\n \"aria-label\": string\n }\n | {\n asChild?: false\n iconOnly?: false\n /** @deprecated use `iconOnly` with a text size */\n size: IconOnlyButtonSize\n \"aria-label\": string\n }\n | {\n asChild?: false\n iconOnly?: false\n size?: TextButtonSize\n \"aria-label\"?: string\n }\n )\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n iconOnly = false,\n asChild = false,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\"\n const resolvedSize =\n iconOnly && size in ICON_ONLY_SIZE\n ? ICON_ONLY_SIZE[size as TextButtonSize]\n : size\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={resolvedSize}\n data-icon-only={iconOnly || resolvedSize !== size ? true : undefined}\n className={cn(buttonVariants({ variant, size: resolvedSize, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\nexport type { IconOnlyButtonSize, TextButtonSize }\n\n/**\n * WHEN TO USE\n * - Form submission, navigation, state changes, primary/secondary CTAs\n * - Icon-only actions — `iconOnly` at the matching size, not a text size with a bare icon\n *\n * NOT WHEN\n * - An inline text hyperlink — use an anchor, or variant=\"link\"\n * - Icon-only without an aria-label — screen readers get nothing to announce\n * - A non-interactive status indicator — use Badge\n *\n * KEY RULES\n * - variant: default | outline | secondary | ghost | destructive | link | ai (default \"default\")\n * - size: default | xs | sm | lg (default \"default\") — how tall the button is\n * - iconOnly: a square, text-less button at that same size step (h-8 -> 8x8 at default, and so on).\n * Two separate axes on purpose: icon-only is a shape, not a size, so `size=\"sm\" iconOnly` and\n * `size=\"sm\"` line up in the same row. `aria-label` is required whenever `iconOnly` is set —\n * enforced at the type level. The old `size=\"icon\" | \"icon-xs\" | \"icon-sm\" | \"icon-lg\"` values\n * still render identically but are deprecated aliases; don't write new code with them.\n * - asChild renders the child element via Slot instead of a <button> — for wrapping an <a> or router Link\n * - A leading/trailing icon needs data-icon=\"inline-start\" / \"inline-end\" on the icon element so the\n * size's built-in padding collapses correctly on that side\n * - Only one destructive-intent button per confirming action — don't pair with a second destructive button\n * - variant=\"ai\" marks an action as AI-powered with the AI Gradient — a gold-to-pink wash\n * (--color-ai-wash / --color-ai-grad-from) that deepens on hover/active.\n * Add `AISparkle` (from ai-sparkle.tsx) as a leading icon via data-icon=\"inline-start\" for the\n * \"with sparkle\" emphasis — there's no separate prop for it, it's the same icon-slot convention\n * as any other button\n * - An icon-only \"AI Icon Button\" is variant=\"ai\" with `iconOnly`, same persistent gradient and\n * hover/active states as the text \"AI Button\" — not variant=\"ghost\" with the gradient added\n * only on hover. The AI Gradient background is what signals \"AI\" here, so the icon itself is\n * free: AISparkle alone (a pure \"Ask AI\" trigger with no other icon), or any domain icon\n * (BotIcon, SendIcon, whatever fits the action) plus a small AISparkle corner accent for\n * emphasis — same background either way. For the corner-accent version, put it INSIDE the\n * button itself (className=\"relative\" on the Button, AISparkle absolutely placed at\n * top-1 right-1, size-3) — not a sibling overhanging the outer edge, which risks getting\n * clipped by a cramped ancestor's overflow-hidden (e.g. a Sidecar panel). top-1/right-1 lands\n * it overlapping the centered icon's own corner by about 4px at a default icon-size button.\n * - An \"AI Chip\" is variant=\"ai\" at a small size with a rounded-full override — Badge can't be used\n * here because it's non-interactive and this needs to stay clickable\n * - A plain \"Chip\" (e.g. a removable applied-filter pill) is variant=\"outline\" at size=\"sm\" with\n * the same rounded-full override, plus a trailing remove icon via data-icon=\"inline-end\" —\n * again Button, not Badge, because the whole pill is clickable (e.g. to remove itself)\n * - An \"Expanded Button\" (full width) is `className=\"w-full\"` — Button never adds its own margin\n * or width logic, so the gutter around it always comes from whatever surface it's on (a Card's\n * own padding, a Dialog/Sheet footer's own inset), never from the button itself\n *\n * USAGE\n * <Button variant=\"destructive\" onClick={handleDelete}>Delete</Button>\n * <Button iconOnly aria-label=\"Add\"><PlusIcon /></Button>\n * <Button size=\"sm\" iconOnly aria-label=\"Add\"><PlusIcon /></Button>\n * <Button variant=\"outline\">\n * Continue\n * <ArrowRightIcon data-icon=\"inline-end\" />\n * </Button>\n *\n * // AI Button — default and \"with sparkle\"\n * <Button variant=\"ai\">Summarize</Button>\n * <Button variant=\"ai\">\n * <AISparkle data-icon=\"inline-start\" />\n * Summarize\n * </Button>\n *\n * // AI Icon Button — AISparkle alone, a pure \"Ask AI\" trigger\n * <Button variant=\"ai\" iconOnly aria-label=\"Ask AI\">\n * <AISparkle />\n * </Button>\n *\n * // AI Icon Button — a domain icon instead, same AI Gradient background, corner sparkle inside the button\n * <Button variant=\"ai\" iconOnly aria-label=\"Ask AI\" className=\"relative\">\n * <BotIcon />\n * <AISparkle className=\"absolute top-1 right-1 size-3\" />\n * </Button>\n *\n * // AI Chip — a small rounded-full action chip, not a Badge (needs to stay clickable)\n * <Button variant=\"ai\" size=\"xs\" className=\"rounded-full\">\n * <AISparkle data-icon=\"inline-start\" />\n * Ask Sara\n * </Button>\n *\n * // Chip — a removable pill (e.g. an applied filter), icon trails the label\n * <Button variant=\"outline\" size=\"sm\" className=\"rounded-full\" onClick={handleRemove}>\n * Status: Paid\n * <XIcon data-icon=\"inline-end\" />\n * </Button>\n */\n"],"mappings":";;;;;;AAwBA,IAAM,iBAAiB,IACrB,qpBACA;CACE,UAAU;EACR,SAAS;GAcP,SACE;GACF,SACE;GACF,WACE;GACF,OACE;GACF,aACE;GACF,MAAM;GACN,IAAI;EACN;EACA,MAAM;GACJ,SACE;GACF,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,MAAM;GACN,WACE;GACF,WACE;GACF,WAAW;EACb;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAaA,IAAM,iBAA6D;CACjE,SAAS;CACT,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AA8CA,SAAS,OAAO,EACd,WACA,UAAU,WACV,OAAO,WACP,WAAW,OACX,UAAU,OACV,GAAG,SACW;CACd,MAAM,OAAO,UAAU,KAAK,OAAO;CACnC,MAAM,eACJ,YAAY,QAAQ,iBAChB,eAAe,QACf;CAEN,OACE,oBAAC,MAAD;EACE,aAAU;EACV,gBAAc;EACd,aAAW;EACX,kBAAgB,YAAY,iBAAiB,OAAO,OAAO,KAAA;EAC3D,WAAW,GAAG,eAAe;GAAE;GAAS,MAAM;GAAc;EAAU,CAAC,CAAC;EACxE,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar — inline calendar grid for date selection.
|
|
3
|
+
*
|
|
4
|
+
* MMDS supplies classNames, a custom day button (CalendarDayButton), and
|
|
5
|
+
* chevron icons over the react-day-picker date-grid engine.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { DayPicker, type DayButton, type Locale } from "react-day-picker";
|
|
9
|
+
import { Button } from "../../components/ui/button";
|
|
10
|
+
declare function Calendar({ className, classNames, showOutsideDays, captionLayout, buttonVariant, locale, formatters, components, ...props }: React.ComponentProps<typeof DayPicker> & {
|
|
11
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
declare function CalendarDayButton({ className, day, modifiers, locale, ...props }: React.ComponentProps<typeof DayButton> & {
|
|
14
|
+
locale?: Partial<Locale>;
|
|
15
|
+
}): React.JSX.Element;
|
|
16
|
+
export { Calendar, CalendarDayButton };
|
|
17
|
+
/**
|
|
18
|
+
* WHEN TO USE
|
|
19
|
+
* - A persistent, always-visible calendar view for picking dates.
|
|
20
|
+
* - Inside a Popover behind a trigger button, to form a date-picker field.
|
|
21
|
+
*
|
|
22
|
+
* NOT WHEN
|
|
23
|
+
* - Displaying a fixed, non-editable date — just render text.
|
|
24
|
+
* - Only month/year granularity is needed, not full day selection.
|
|
25
|
+
*
|
|
26
|
+
* KEY RULES
|
|
27
|
+
* - `mode` is a required discriminator: "single" | "multiple" | "range" — it determines the type of `selected`/`onSelect` (Date, Date[], or DateRange).
|
|
28
|
+
* - `numberOfMonths` renders more than one month side by side, commonly paired with mode="range".
|
|
29
|
+
* - `disabled` accepts matchers, e.g. `{ dayOfWeek: [0, 6] }` to block weekends.
|
|
30
|
+
* - `defaultMonth` sets the initially visible month without controlling selection.
|
|
31
|
+
* - `captionLayout="dropdown"` swaps the month/year label for jump-to dropdowns (defaults to a
|
|
32
|
+
* 100-year range with no extra props) — the fast-navigation pattern for something like a date
|
|
33
|
+
* of birth; override the range via `startMonth`/`endMonth` (plain `Date`s) if a form needs one.
|
|
34
|
+
* - There is no dedicated DatePicker component — it's always this Calendar composed inside a
|
|
35
|
+
* Popover, with the trigger's label built from whatever's selected, per the USAGE example below.
|
|
36
|
+
*
|
|
37
|
+
* USAGE
|
|
38
|
+
* // Single date
|
|
39
|
+
* <Calendar mode="single" selected={date} onSelect={setDate} className="rounded-xl border" />
|
|
40
|
+
*
|
|
41
|
+
* // Range across two months
|
|
42
|
+
* <Calendar mode="range" selected={range} onSelect={setRange} numberOfMonths={2} className="rounded-xl border" />
|
|
43
|
+
*
|
|
44
|
+
* // Month/year dropdown captions instead of a plain label — fast navigation to a far month
|
|
45
|
+
* <Calendar mode="single" selected={date} onSelect={setDate} captionLayout="dropdown" className="rounded-xl border" />
|
|
46
|
+
*
|
|
47
|
+
* // Inside a Popover, as a date-picker field
|
|
48
|
+
* <Popover>
|
|
49
|
+
* <PopoverTrigger asChild>
|
|
50
|
+
* <Button variant="outline">{date ? date.toLocaleDateString() : "Pick a date"}</Button>
|
|
51
|
+
* </PopoverTrigger>
|
|
52
|
+
* <PopoverContent className="w-auto p-0">
|
|
53
|
+
* <Calendar mode="single" selected={date} onSelect={setDate} />
|
|
54
|
+
* </PopoverContent>
|
|
55
|
+
* </Popover>
|
|
56
|
+
*/
|
|
57
|
+
//# sourceMappingURL=calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/calendar.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,SAAS,EAET,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,MAAM,EAAkB,MAAM,wBAAwB,CAAA;AAO/D,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,UAAU,EACV,eAAsB,EACtB,aAAuB,EACvB,aAAuB,EACvB,MAAM,EACN,UAAU,EACV,UAAU,EACV,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,GAAG;IAC1C,aAAa,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC,SAAS,CAAC,CAAA;CAC/D,qBA6JA;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,EACH,SAAS,EACT,MAAM,EACN,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,qBAqCvE;AAED,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAA;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG"}
|