@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,609 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { getPortalContainer } from "../../lib/scope.js";
|
|
4
|
+
import { Button } from "./button.js";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { Popover, Select as Select$1 } from "radix-ui";
|
|
7
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, XIcon } from "lucide-react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/components/ui/select.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Select — single-value dropdown over a fixed, bounded option list.
|
|
12
|
+
*
|
|
13
|
+
* Built on the Radix Select primitive with MMDS token-based styling. Size
|
|
14
|
+
* variants (default/sm/xs) are layered on via a `data-size` attribute.
|
|
15
|
+
*/
|
|
16
|
+
function Select({ ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Select$1.Root, {
|
|
18
|
+
"data-slot": "select",
|
|
19
|
+
...props
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function SelectGroup({ className, ...props }) {
|
|
23
|
+
return /* @__PURE__ */ jsx(Select$1.Group, {
|
|
24
|
+
"data-slot": "select-group",
|
|
25
|
+
className: cn("scroll-my-1 p-1", className),
|
|
26
|
+
...props
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function SelectValue({ inlineLabel, children, ...props }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(Select$1.Value, {
|
|
31
|
+
"data-slot": "select-value",
|
|
32
|
+
...props,
|
|
33
|
+
children: children != null && inlineLabel ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
|
|
34
|
+
className: "text-muted-foreground",
|
|
35
|
+
children: [inlineLabel, ": "]
|
|
36
|
+
}), children] }) : children
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function SelectTrigger({ className, size = "default", children, ...props }) {
|
|
40
|
+
return /* @__PURE__ */ jsxs(Select$1.Trigger, {
|
|
41
|
+
"data-slot": "select-trigger",
|
|
42
|
+
"data-size": size,
|
|
43
|
+
className: cn("flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md,0.375rem),10px)] data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:rounded-[min(var(--radius-md,0.375rem),8px)] data-[size=xs]:pr-1.5 data-[size=xs]:pl-2 data-[size=xs]:text-xs *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 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", className),
|
|
44
|
+
...props,
|
|
45
|
+
children: [children, /* @__PURE__ */ jsx(Select$1.Icon, {
|
|
46
|
+
asChild: true,
|
|
47
|
+
children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "pointer-events-none size-4 text-muted-foreground" })
|
|
48
|
+
})]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function SelectContent({ className, children, position = "item-aligned", align = "center", ...props }) {
|
|
52
|
+
return /* @__PURE__ */ jsx(Select$1.Portal, {
|
|
53
|
+
container: getPortalContainer(),
|
|
54
|
+
children: /* @__PURE__ */ jsxs(Select$1.Content, {
|
|
55
|
+
"data-slot": "select-content",
|
|
56
|
+
"data-align-trigger": position === "item-aligned",
|
|
57
|
+
className: cn("relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-popover ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className),
|
|
58
|
+
position,
|
|
59
|
+
align,
|
|
60
|
+
...props,
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
63
|
+
/* @__PURE__ */ jsx(Select$1.Viewport, {
|
|
64
|
+
"data-position": position,
|
|
65
|
+
className: cn("data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)", position === "popper" && ""),
|
|
66
|
+
children
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
69
|
+
]
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function SelectLabel({ className, ...props }) {
|
|
74
|
+
return /* @__PURE__ */ jsx(Select$1.Label, {
|
|
75
|
+
"data-slot": "select-label",
|
|
76
|
+
className: cn("px-1.5 py-1 text-xs text-muted-foreground", className),
|
|
77
|
+
...props
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function SelectItem({ className, children, ...props }) {
|
|
81
|
+
return /* @__PURE__ */ jsxs(Select$1.Item, {
|
|
82
|
+
"data-slot": "select-item",
|
|
83
|
+
className: cn("relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className),
|
|
84
|
+
...props,
|
|
85
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
86
|
+
className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center",
|
|
87
|
+
children: /* @__PURE__ */ jsx(Select$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" }) })
|
|
88
|
+
}), /* @__PURE__ */ jsx(Select$1.ItemText, { children })]
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function SelectSeparator({ className, ...props }) {
|
|
92
|
+
return /* @__PURE__ */ jsx(Select$1.Separator, {
|
|
93
|
+
"data-slot": "select-separator",
|
|
94
|
+
className: cn("pointer-events-none -mx-1 my-1 h-px bg-border", className),
|
|
95
|
+
...props
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function SelectScrollUpButton({ className, ...props }) {
|
|
99
|
+
return /* @__PURE__ */ jsx(Select$1.ScrollUpButton, {
|
|
100
|
+
"data-slot": "select-scroll-up-button",
|
|
101
|
+
className: cn("z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", className),
|
|
102
|
+
...props,
|
|
103
|
+
children: /* @__PURE__ */ jsx(ChevronUpIcon, {})
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function SelectScrollDownButton({ className, ...props }) {
|
|
107
|
+
return /* @__PURE__ */ jsx(Select$1.ScrollDownButton, {
|
|
108
|
+
"data-slot": "select-scroll-down-button",
|
|
109
|
+
className: cn("z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", className),
|
|
110
|
+
...props,
|
|
111
|
+
children: /* @__PURE__ */ jsx(ChevronDownIcon, {})
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
var SelectMultipleContext = React.createContext(null);
|
|
115
|
+
function useSelectMultipleContext(component) {
|
|
116
|
+
const context = React.useContext(SelectMultipleContext);
|
|
117
|
+
if (!context) throw new Error(`${component} must be used within <SelectMultiple>.`);
|
|
118
|
+
return context;
|
|
119
|
+
}
|
|
120
|
+
function SelectMultiple({ value, onValueChange, size = "default", children, open: openProp, onOpenChange, closeOnSelect = false, ...props }) {
|
|
121
|
+
const labelsRef = React.useRef(/* @__PURE__ */ new Map());
|
|
122
|
+
const [labelsVersion, forceUpdate] = React.useReducer((n) => n + 1, 0);
|
|
123
|
+
const triggerRef = React.useRef(null);
|
|
124
|
+
const contentRef = React.useRef(null);
|
|
125
|
+
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
126
|
+
const open = openProp ?? internalOpen;
|
|
127
|
+
const [triggerWidthOnOpen, setTriggerWidthOnOpen] = React.useState(void 0);
|
|
128
|
+
const setOpen = React.useCallback((next) => {
|
|
129
|
+
if (next) setTriggerWidthOnOpen(triggerRef.current?.getBoundingClientRect().width);
|
|
130
|
+
onOpenChange?.(next);
|
|
131
|
+
if (openProp === void 0) setInternalOpen(next);
|
|
132
|
+
}, [onOpenChange, openProp]);
|
|
133
|
+
React.useEffect(() => {
|
|
134
|
+
function handlePointerDown(event) {
|
|
135
|
+
const contentEl = contentRef.current;
|
|
136
|
+
if (!contentEl || contentEl.getAttribute("data-state") !== "open") return;
|
|
137
|
+
const target = event.target;
|
|
138
|
+
if (!(target instanceof Node)) return;
|
|
139
|
+
if (contentEl.contains(target)) return;
|
|
140
|
+
if (triggerRef.current?.contains(target)) return;
|
|
141
|
+
setOpen(false);
|
|
142
|
+
}
|
|
143
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
144
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
145
|
+
}, [setOpen]);
|
|
146
|
+
const registerLabel = React.useCallback((itemValue, label) => {
|
|
147
|
+
labelsRef.current.set(itemValue, label);
|
|
148
|
+
forceUpdate();
|
|
149
|
+
}, []);
|
|
150
|
+
const unregisterLabel = React.useCallback((itemValue) => {
|
|
151
|
+
labelsRef.current.delete(itemValue);
|
|
152
|
+
forceUpdate();
|
|
153
|
+
}, []);
|
|
154
|
+
const onItemSelect = React.useCallback((itemValue) => {
|
|
155
|
+
onValueChange(value.includes(itemValue) ? value.filter((v) => v !== itemValue) : [...value, itemValue]);
|
|
156
|
+
if (closeOnSelect) setOpen(false);
|
|
157
|
+
}, [
|
|
158
|
+
value,
|
|
159
|
+
onValueChange,
|
|
160
|
+
closeOnSelect,
|
|
161
|
+
setOpen
|
|
162
|
+
]);
|
|
163
|
+
const clear = React.useCallback(() => onValueChange([]), [onValueChange]);
|
|
164
|
+
const context = React.useMemo(() => ({
|
|
165
|
+
value,
|
|
166
|
+
onItemSelect,
|
|
167
|
+
clear,
|
|
168
|
+
labels: labelsRef.current,
|
|
169
|
+
registerLabel,
|
|
170
|
+
unregisterLabel,
|
|
171
|
+
size,
|
|
172
|
+
triggerRef,
|
|
173
|
+
contentRef,
|
|
174
|
+
closeOnSelect,
|
|
175
|
+
triggerWidthOnOpen
|
|
176
|
+
}), [
|
|
177
|
+
value,
|
|
178
|
+
onItemSelect,
|
|
179
|
+
clear,
|
|
180
|
+
registerLabel,
|
|
181
|
+
unregisterLabel,
|
|
182
|
+
labelsVersion,
|
|
183
|
+
size,
|
|
184
|
+
closeOnSelect,
|
|
185
|
+
triggerWidthOnOpen
|
|
186
|
+
]);
|
|
187
|
+
return /* @__PURE__ */ jsx(SelectMultipleContext.Provider, {
|
|
188
|
+
value: context,
|
|
189
|
+
children: /* @__PURE__ */ jsx(Popover.Root, {
|
|
190
|
+
"data-slot": "select-multiple",
|
|
191
|
+
open,
|
|
192
|
+
onOpenChange: setOpen,
|
|
193
|
+
...props,
|
|
194
|
+
children
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/** Shows only the first selected label — ellipsis-truncated at a character cap, applied whether or not anything else is selected, since the label alone can be too long to show whole in a `w-fit` trigger with no width of its own to truncate against — plus "+N" for the rest once there's more than one. No cap: the first label in full, still just the first. */
|
|
199
|
+
function buildMultiValueLabel(value, labels, maxChars) {
|
|
200
|
+
if (value.length === 0) return "";
|
|
201
|
+
const [first, ...rest] = value.map((v) => String(labels.get(v) ?? v));
|
|
202
|
+
const shown = maxChars !== void 0 && first.length > maxChars ? `${first.slice(0, maxChars)}…` : first;
|
|
203
|
+
return rest.length > 0 ? `${shown} +${rest.length}` : shown;
|
|
204
|
+
}
|
|
205
|
+
function SelectMultipleTrigger({ className, placeholder, disabled, maxLabelChars, inlineLabel, ...props }) {
|
|
206
|
+
const { value, labels, clear, size, triggerRef } = useSelectMultipleContext("SelectMultipleTrigger");
|
|
207
|
+
const hasValue = value.length > 0;
|
|
208
|
+
const valueLabel = buildMultiValueLabel(value, labels, maxLabelChars);
|
|
209
|
+
return /* @__PURE__ */ jsx(Popover.Trigger, {
|
|
210
|
+
disabled,
|
|
211
|
+
asChild: true,
|
|
212
|
+
...props,
|
|
213
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
214
|
+
ref: triggerRef,
|
|
215
|
+
"data-slot": "select-multiple-trigger",
|
|
216
|
+
"data-size": size,
|
|
217
|
+
"data-placeholder": hasValue ? void 0 : "",
|
|
218
|
+
role: "button",
|
|
219
|
+
"aria-haspopup": "listbox",
|
|
220
|
+
tabIndex: disabled ? -1 : 0,
|
|
221
|
+
"aria-disabled": disabled || void 0,
|
|
222
|
+
onKeyDown: (event) => {
|
|
223
|
+
if (disabled) return;
|
|
224
|
+
if (event.target !== event.currentTarget) return;
|
|
225
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
event.currentTarget.click();
|
|
228
|
+
},
|
|
229
|
+
className: cn("group flex w-fit items-center gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md,0.375rem),10px)] data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:rounded-[min(var(--radius-md,0.375rem),8px)] data-[size=xs]:pr-1.5 data-[size=xs]:pl-2 data-[size=xs]:text-xs dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className),
|
|
230
|
+
"aria-invalid": props["aria-invalid"],
|
|
231
|
+
children: [
|
|
232
|
+
/* @__PURE__ */ jsx("span", {
|
|
233
|
+
className: "min-w-0 flex-1 truncate text-left",
|
|
234
|
+
children: hasValue ? /* @__PURE__ */ jsxs(Fragment, { children: [inlineLabel && /* @__PURE__ */ jsxs("span", {
|
|
235
|
+
className: "text-muted-foreground",
|
|
236
|
+
children: [inlineLabel, ": "]
|
|
237
|
+
}), valueLabel] }) : placeholder
|
|
238
|
+
}),
|
|
239
|
+
hasValue && !disabled && /* @__PURE__ */ jsx(Button, {
|
|
240
|
+
type: "button",
|
|
241
|
+
variant: "ghost",
|
|
242
|
+
size: "xs",
|
|
243
|
+
iconOnly: true,
|
|
244
|
+
"aria-label": "Clear selection",
|
|
245
|
+
onClick: (event) => {
|
|
246
|
+
event.stopPropagation();
|
|
247
|
+
clear();
|
|
248
|
+
},
|
|
249
|
+
className: "shrink-0 text-muted-foreground",
|
|
250
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "pointer-events-none" })
|
|
251
|
+
}),
|
|
252
|
+
/* @__PURE__ */ jsx("span", {
|
|
253
|
+
role: "status",
|
|
254
|
+
className: "sr-only",
|
|
255
|
+
children: hasValue ? `${value.length} selected` : "None selected"
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ jsx(ChevronDownIcon, {
|
|
258
|
+
"aria-hidden": "true",
|
|
259
|
+
className: "size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-180"
|
|
260
|
+
})
|
|
261
|
+
]
|
|
262
|
+
})
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function SelectMultipleContent({ className, align = "start", sideOffset = 4, children, style, ...props }) {
|
|
266
|
+
const { size, contentRef, triggerWidthOnOpen } = useSelectMultipleContext("SelectMultipleContent");
|
|
267
|
+
const childArray = React.Children.toArray(children);
|
|
268
|
+
const isFooter = (child) => React.isValidElement(child) && child.type === SelectMultipleFooter;
|
|
269
|
+
const footer = childArray.filter(isFooter);
|
|
270
|
+
const items = childArray.filter((child) => !isFooter(child));
|
|
271
|
+
return /* @__PURE__ */ jsx(Popover.Portal, {
|
|
272
|
+
container: getPortalContainer(),
|
|
273
|
+
forceMount: true,
|
|
274
|
+
children: /* @__PURE__ */ jsxs(Popover.Content, {
|
|
275
|
+
ref: contentRef,
|
|
276
|
+
"data-slot": "select-multiple-content",
|
|
277
|
+
"data-size": size,
|
|
278
|
+
forceMount: true,
|
|
279
|
+
align,
|
|
280
|
+
sideOffset,
|
|
281
|
+
className: cn("z-50 max-h-(--radix-popover-content-available-height) max-w-[min(400px,var(--radix-popover-content-available-width))] min-w-[max(240px,var(--trigger-width-on-open,0px))] origin-(--radix-popover-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-popover ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[size=xs]:p-0.5 data-[state=closed]:hidden data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", className),
|
|
282
|
+
style: {
|
|
283
|
+
...triggerWidthOnOpen !== void 0 && { "--trigger-width-on-open": `${triggerWidthOnOpen}px` },
|
|
284
|
+
...style
|
|
285
|
+
},
|
|
286
|
+
...props,
|
|
287
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
288
|
+
role: "listbox",
|
|
289
|
+
"aria-multiselectable": "true",
|
|
290
|
+
className: "contents",
|
|
291
|
+
onKeyDown: (event) => {
|
|
292
|
+
if (![
|
|
293
|
+
"ArrowDown",
|
|
294
|
+
"ArrowUp",
|
|
295
|
+
"Home",
|
|
296
|
+
"End"
|
|
297
|
+
].includes(event.key)) return;
|
|
298
|
+
const options = Array.from(event.currentTarget.querySelectorAll("[role=\"option\"]:not([data-disabled])"));
|
|
299
|
+
if (options.length === 0) return;
|
|
300
|
+
const currentIndex = options.indexOf(document.activeElement);
|
|
301
|
+
event.preventDefault();
|
|
302
|
+
options[event.key === "Home" ? 0 : event.key === "End" ? options.length - 1 : event.key === "ArrowDown" ? currentIndex < 0 ? 0 : (currentIndex + 1) % options.length : currentIndex < 0 ? options.length - 1 : (currentIndex - 1 + options.length) % options.length]?.focus();
|
|
303
|
+
},
|
|
304
|
+
children: items
|
|
305
|
+
}), footer]
|
|
306
|
+
})
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Optional Cancel/Apply footer for `SelectMultipleContent` — pass a
|
|
311
|
+
* controlled `open` to `SelectMultiple` itself (see its own comment) and
|
|
312
|
+
* feed it a local pending draft instead of the real `value`/`onValueChange`
|
|
313
|
+
* while open, so picks only land for real once Apply commits that draft;
|
|
314
|
+
* Cancel just closes, discarding it. Renders as a sibling of the listbox,
|
|
315
|
+
* never inside it — see `SelectMultipleContent`'s own comment for why.
|
|
316
|
+
*/
|
|
317
|
+
function SelectMultipleFooter({ className, ...props }) {
|
|
318
|
+
const { size } = useSelectMultipleContext("SelectMultipleFooter");
|
|
319
|
+
return /* @__PURE__ */ jsx("div", {
|
|
320
|
+
"data-slot": "select-multiple-footer",
|
|
321
|
+
className: cn("mt-1 flex items-center justify-end gap-1 border-t border-border pt-1.5", size === "xs" ? "-mx-0.5 w-[calc(100%+--spacing(1))] px-0.5" : "-mx-1 w-[calc(100%+--spacing(2))] px-1", className),
|
|
322
|
+
...props
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function SelectMultipleGroup({ className, ...props }) {
|
|
326
|
+
return /* @__PURE__ */ jsx("div", {
|
|
327
|
+
"data-slot": "select-multiple-group",
|
|
328
|
+
role: "group",
|
|
329
|
+
className: cn("scroll-my-1 p-1", className),
|
|
330
|
+
...props
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function SelectMultipleLabel({ className, ...props }) {
|
|
334
|
+
return /* @__PURE__ */ jsx("div", {
|
|
335
|
+
"data-slot": "select-multiple-label",
|
|
336
|
+
className: cn("px-1.5 py-1 text-xs text-muted-foreground", className),
|
|
337
|
+
...props
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
function SelectMultipleItem({ className, children, value: itemValue, textValue, disabled, onClick, onKeyDown, ...props }) {
|
|
341
|
+
const { value, onItemSelect, registerLabel, unregisterLabel, size, closeOnSelect } = useSelectMultipleContext("SelectMultipleItem");
|
|
342
|
+
const checked = value.includes(itemValue);
|
|
343
|
+
React.useEffect(() => {
|
|
344
|
+
registerLabel(itemValue, textValue ?? (typeof children === "string" ? children : itemValue));
|
|
345
|
+
return () => unregisterLabel(itemValue);
|
|
346
|
+
}, [
|
|
347
|
+
itemValue,
|
|
348
|
+
textValue,
|
|
349
|
+
children,
|
|
350
|
+
registerLabel,
|
|
351
|
+
unregisterLabel
|
|
352
|
+
]);
|
|
353
|
+
const select = () => {
|
|
354
|
+
if (disabled) return;
|
|
355
|
+
onItemSelect(itemValue);
|
|
356
|
+
};
|
|
357
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
358
|
+
"data-slot": "select-multiple-item",
|
|
359
|
+
role: "option",
|
|
360
|
+
"aria-selected": checked,
|
|
361
|
+
"aria-disabled": disabled,
|
|
362
|
+
"data-disabled": disabled ? "" : void 0,
|
|
363
|
+
"data-size": size,
|
|
364
|
+
tabIndex: disabled ? -1 : 0,
|
|
365
|
+
className: cn("relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-1.5 pl-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-[size=sm]:py-1 data-[size=xs]:gap-1.5 data-[size=xs]:py-0.5 data-[size=xs]:text-xs data-disabled:pointer-events-none data-disabled:opacity-50", className),
|
|
366
|
+
onClick: (e) => {
|
|
367
|
+
onClick?.(e);
|
|
368
|
+
select();
|
|
369
|
+
},
|
|
370
|
+
onKeyDown: (e) => {
|
|
371
|
+
onKeyDown?.(e);
|
|
372
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
373
|
+
e.preventDefault();
|
|
374
|
+
select();
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
...props,
|
|
378
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
379
|
+
"aria-hidden": "true",
|
|
380
|
+
"data-slot": "select-multiple-item-checkbox",
|
|
381
|
+
className: cn("relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors", closeOnSelect && "rounded-full", checked && (closeOnSelect ? "border-primary" : "border-primary bg-primary text-primary-foreground"), disabled && "opacity-50"),
|
|
382
|
+
children: checked && (closeOnSelect ? /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-primary" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5" }))
|
|
383
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
384
|
+
className: "inline-flex min-w-0 flex-1 items-center gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
385
|
+
children: typeof children === "string" ? /* @__PURE__ */ jsx("span", {
|
|
386
|
+
className: "min-w-0 flex-1 truncate",
|
|
387
|
+
children
|
|
388
|
+
}) : children
|
|
389
|
+
})]
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function SelectMultipleSeparator({ className, ...props }) {
|
|
393
|
+
return /* @__PURE__ */ jsx("div", {
|
|
394
|
+
"data-slot": "select-multiple-separator",
|
|
395
|
+
className: cn("pointer-events-none -mx-1 my-1 h-px bg-border", className),
|
|
396
|
+
...props
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* WHEN TO USE
|
|
401
|
+
* - Picking one value from a short, known, bounded list (settings, filters, form fields).
|
|
402
|
+
* - Options need grouping (SelectGroup + SelectLabel) or per-item disabling.
|
|
403
|
+
*
|
|
404
|
+
* NOT WHEN
|
|
405
|
+
* - The list is long enough to need type-to-filter — use Combobox instead.
|
|
406
|
+
* - Multiple values from a list that also needs search/filter — use Combobox's multi-select mode.
|
|
407
|
+
* - Native OS picker behavior (better on mobile, zero extra JS) is preferable — use NativeSelect instead.
|
|
408
|
+
*
|
|
409
|
+
* KEY RULES
|
|
410
|
+
* - SelectTrigger's `size` is "default" | "sm" | "xs" (default "default"); controls trigger
|
|
411
|
+
* height (h-8/h-7/h-6) and text size — same default/sm/xs vocabulary as Button/Item/
|
|
412
|
+
* Attachment/Tabs, not Select-specific naming.
|
|
413
|
+
* - SelectContent portals its content; `position="item-aligned"` (default) aligns to the trigger like a native select, `position="popper"` behaves like a standard popover.
|
|
414
|
+
* - Every SelectItem needs a `value`; the check indicator renders automatically for the selected item.
|
|
415
|
+
* - Put SelectSeparator between SelectGroups, not inside one.
|
|
416
|
+
* - SelectValue with no `children` auto-fills from the selected Item's own text — that's the
|
|
417
|
+
* normal, no-`inlineLabel` usage below. For "Label: Value" (e.g. "Assignee: James"), give
|
|
418
|
+
* SelectValue both `inlineLabel` and the current value's display text as `children` yourself —
|
|
419
|
+
* the auto-fill only runs with zero children, so a label prefix can't attach to it in place.
|
|
420
|
+
* - An AI-filled value is a plain composition, not a dedicated prop, and the same shape as
|
|
421
|
+
* Input's and Textarea's: put `AILabel` in the label row as a sibling of FieldLabel — never
|
|
422
|
+
* beside or inside SelectTrigger, which is itself a `<button>` (a button inside a button is
|
|
423
|
+
* invalid HTML, and would also open the listbox on every click of the marker) — while the
|
|
424
|
+
* value still matches what AI picked. Pass AILabel `edited={value !== aiValue}` and an
|
|
425
|
+
* `onRevert` that restores it, so picking a different value turns the marker into a ghost undo
|
|
426
|
+
* button (AILabel's own override/undo morph, same as Input/Textarea/Checkbox/RadioGroup). See
|
|
427
|
+
* Forms/Select.
|
|
428
|
+
*
|
|
429
|
+
* USAGE
|
|
430
|
+
* <Select>
|
|
431
|
+
* <SelectTrigger className="w-56">
|
|
432
|
+
* <SelectValue placeholder="Select a spice" />
|
|
433
|
+
* </SelectTrigger>
|
|
434
|
+
* <SelectContent>
|
|
435
|
+
* <SelectItem value="turmeric">Turmeric</SelectItem>
|
|
436
|
+
* <SelectItem value="cardamom">Cardamom</SelectItem>
|
|
437
|
+
* </SelectContent>
|
|
438
|
+
* </Select>
|
|
439
|
+
*
|
|
440
|
+
* // Inline-labeled trigger — "Spice: Turmeric" once a value is picked, plain
|
|
441
|
+
* // placeholder ("Select a spice") while nothing is
|
|
442
|
+
* <Select value={value} onValueChange={setValue}>
|
|
443
|
+
* <SelectTrigger className="w-56">
|
|
444
|
+
* <SelectValue placeholder="Select a spice" inlineLabel="Spice">
|
|
445
|
+
* {value || undefined}
|
|
446
|
+
* </SelectValue>
|
|
447
|
+
* </SelectTrigger>
|
|
448
|
+
* <SelectContent>
|
|
449
|
+
* <SelectItem value="turmeric">Turmeric</SelectItem>
|
|
450
|
+
* <SelectItem value="cardamom">Cardamom</SelectItem>
|
|
451
|
+
* </SelectContent>
|
|
452
|
+
* </Select>
|
|
453
|
+
*
|
|
454
|
+
* // Grouped, with a disabled item
|
|
455
|
+
* <Select defaultValue="cumin">
|
|
456
|
+
* <SelectTrigger className="w-56"><SelectValue placeholder="Select a spice" /></SelectTrigger>
|
|
457
|
+
* <SelectContent>
|
|
458
|
+
* <SelectGroup>
|
|
459
|
+
* <SelectLabel>Whole</SelectLabel>
|
|
460
|
+
* <SelectItem value="cardamom">Cardamom pod</SelectItem>
|
|
461
|
+
* </SelectGroup>
|
|
462
|
+
* <SelectSeparator />
|
|
463
|
+
* <SelectGroup>
|
|
464
|
+
* <SelectLabel>Ground</SelectLabel>
|
|
465
|
+
* <SelectItem value="turmeric">Turmeric</SelectItem>
|
|
466
|
+
* <SelectItem value="saffron" disabled>Saffron (out of stock)</SelectItem>
|
|
467
|
+
* </SelectGroup>
|
|
468
|
+
* </SelectContent>
|
|
469
|
+
* </Select>
|
|
470
|
+
*
|
|
471
|
+
* ---
|
|
472
|
+
*
|
|
473
|
+
* SelectMultiple — checkbox-list multi-select, no search/filter (see the
|
|
474
|
+
* doc block above SelectMultiple's definition for why this is a separate
|
|
475
|
+
* component tree rather than a `multiple` prop on Select).
|
|
476
|
+
*
|
|
477
|
+
* WHEN TO USE (SelectMultiple)
|
|
478
|
+
* - Picking several values from a short, known, bounded list where a search box
|
|
479
|
+
* would be overkill — settings toggles, tag pickers, filter panels.
|
|
480
|
+
*
|
|
481
|
+
* NOT WHEN (SelectMultiple)
|
|
482
|
+
* - The list is long enough to need type-to-filter — use Combobox's `multiple` mode instead.
|
|
483
|
+
*
|
|
484
|
+
* KEY RULES (SelectMultiple)
|
|
485
|
+
* - `value`/`onValueChange` are required and always an array — there is no uncontrolled mode.
|
|
486
|
+
* - `size` ("default" | "sm" | "xs", default "default") is set ONCE on SelectMultiple itself,
|
|
487
|
+
* not on Trigger or Content — it flows to both via context (Content is portaled, so it's
|
|
488
|
+
* never a CSS descendant of Trigger; a `group-data-[size]` selector couldn't reach it, which
|
|
489
|
+
* is why this is context-driven instead of the group/data-attribute trick Select/Tabs use).
|
|
490
|
+
* Trigger height/text and Content/Item padding/text/gap all scale together from this one prop.
|
|
491
|
+
* - The trigger shows only the first selected item's label (auto-collected from mounted
|
|
492
|
+
* SelectMultipleItems; pass `textValue` on an item if its children aren't plain text — e.g.
|
|
493
|
+
* an item with a leading icon or a secondary description line) plus "+N" once more than one
|
|
494
|
+
* is selected — never every label listed by name. Falls back to `placeholder` when empty,
|
|
495
|
+
* plus a clear-all "x" once non-empty. Pass `maxLabelChars` on SelectMultipleTrigger to
|
|
496
|
+
* ellipsis-truncate that one label past a character cap — applies even with a single value
|
|
497
|
+
* selected, since one long label can blow out a `w-fit` trigger same as a long list would
|
|
498
|
+
* (e.g. a narrow toolbar filter trigger). Pass
|
|
499
|
+
* `inlineLabel` to prefix the non-empty value with "{inlineLabel}: " (e.g. "Assignee: James") —
|
|
500
|
+
* `placeholder` alone still covers the empty state, no prefix there.
|
|
501
|
+
* - Clicking a SelectMultipleItem toggles it and leaves the popover open — this is the whole
|
|
502
|
+
* point of the variant; it never auto-closes on select the way Select/Combobox do. Pass
|
|
503
|
+
* `closeOnSelect` on SelectMultiple to close after any pick instead — for a single-effective-
|
|
504
|
+
* choice usage (cap `value` at one entry yourself) that still wants this component's non-modal
|
|
505
|
+
* Popover behavior (label stays visible while open, rest of the page stays interactive/
|
|
506
|
+
* scrollable) instead of Select's modal one. Don't reach for this as a general Select
|
|
507
|
+
* replacement — Select's native form participation, typeahead, and modality are worth keeping
|
|
508
|
+
* for ordinary form fields; this is for the specific case where a filter/action control needs
|
|
509
|
+
* to coexist non-modally with other controls the user is actively using (see DataTable's
|
|
510
|
+
* `singleSelect` inline filter for a real example). Also swaps every SelectMultipleItem's
|
|
511
|
+
* decorative indicator from a checkbox square to a radio dot — a checkbox otherwise visually
|
|
512
|
+
* promises "pick as many as you want", which is exactly wrong once picking one closes it.
|
|
513
|
+
* - SelectMultipleGroup/SelectMultipleLabel/SelectMultipleSeparator mirror Select's grouping API.
|
|
514
|
+
* - SelectMultiple forwards Radix Popover.Root's own props (`open`/`onOpenChange`/`defaultOpen`
|
|
515
|
+
* etc.) — useful for the Apply/Cancel pattern below, where something other than a plain click
|
|
516
|
+
* needs to control when the popover closes.
|
|
517
|
+
* - SelectMultipleContent/Portal use `forceMount` and hide via `data-[state=closed]:hidden` (a plain
|
|
518
|
+
* `display:none`) instead of letting Radix unmount on close — items must stay mounted while
|
|
519
|
+
* closed so their labels are already registered for the trigger's very first render, before
|
|
520
|
+
* the popover has ever been opened. `hidden` (not `invisible`) matters here specifically:
|
|
521
|
+
* `visibility:hidden` on the inner Content still lets Radix's outer popper-position wrapper
|
|
522
|
+
* div keep its layout box, which then silently intercepts clicks meant for elements behind
|
|
523
|
+
* it; `display:none` collapses that wrapper to nothing.
|
|
524
|
+
*
|
|
525
|
+
* USAGE
|
|
526
|
+
* const [value, setValue] = React.useState<string[]>(["cardamom"])
|
|
527
|
+
* <SelectMultiple value={value} onValueChange={setValue}>
|
|
528
|
+
* <SelectMultipleTrigger className="w-56" placeholder="Select spices" />
|
|
529
|
+
* <SelectMultipleContent>
|
|
530
|
+
* <SelectMultipleItem value="turmeric">Turmeric</SelectMultipleItem>
|
|
531
|
+
* <SelectMultipleItem value="cardamom">Cardamom</SelectMultipleItem>
|
|
532
|
+
* <SelectMultipleItem value="chili">Chili</SelectMultipleItem>
|
|
533
|
+
* </SelectMultipleContent>
|
|
534
|
+
* </SelectMultiple>
|
|
535
|
+
*
|
|
536
|
+
* // Dense popover — one prop scales trigger height AND item padding/text together
|
|
537
|
+
* <SelectMultiple value={value} onValueChange={setValue} size="xs">
|
|
538
|
+
* <SelectMultipleTrigger className="w-48" placeholder="Select spices" />
|
|
539
|
+
* <SelectMultipleContent>...</SelectMultipleContent>
|
|
540
|
+
* </SelectMultiple>
|
|
541
|
+
*
|
|
542
|
+
* // With an icon or a secondary description line — SelectMultipleItem's children is any
|
|
543
|
+
* // ReactNode; pass `textValue` so the trigger's comma-list still shows plain text
|
|
544
|
+
* <SelectMultipleItem value="cardamom" textValue="Cardamom">
|
|
545
|
+
* <LeafIcon />
|
|
546
|
+
* <span className="flex flex-col">
|
|
547
|
+
* Cardamom
|
|
548
|
+
* <span className="text-xs text-muted-foreground">Whole pods</span>
|
|
549
|
+
* </span>
|
|
550
|
+
* </SelectMultipleItem>
|
|
551
|
+
*
|
|
552
|
+
* // With search — filter by hiding non-matches, NOT by unmounting them: an unmounted
|
|
553
|
+
* // SelectMultipleItem unregisters its label, so a selected-but-filtered-out item would
|
|
554
|
+
* // fall back to showing its raw value in the trigger instead of its real label.
|
|
555
|
+
* const [query, setQuery] = React.useState("")
|
|
556
|
+
* <SelectMultipleContent>
|
|
557
|
+
* <Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search..." className="mb-1" />
|
|
558
|
+
* {spices.map((spice) => (
|
|
559
|
+
* <SelectMultipleItem
|
|
560
|
+
* key={spice}
|
|
561
|
+
* value={spice}
|
|
562
|
+
* className={cn(!spice.toLowerCase().includes(query.toLowerCase()) && "hidden")}
|
|
563
|
+
* >
|
|
564
|
+
* {spice}
|
|
565
|
+
* </SelectMultipleItem>
|
|
566
|
+
* ))}
|
|
567
|
+
* </SelectMultipleContent>
|
|
568
|
+
*
|
|
569
|
+
* // "Add option" (creatable) — the consumer already owns the list of items being mapped
|
|
570
|
+
* // over, so a no-results affordance is just appending to that list, same as any
|
|
571
|
+
* // Combobox-style creatable pattern; SelectMultiple needs no API for this.
|
|
572
|
+
* {query && !spices.some((s) => s.toLowerCase() === query.toLowerCase()) && (
|
|
573
|
+
* <button onClick={() => { setSpices((prev) => [...prev, query]); setValue((prev) => [...prev, query]) }}>
|
|
574
|
+
* Add "{query}"
|
|
575
|
+
* </button>
|
|
576
|
+
* )}
|
|
577
|
+
*
|
|
578
|
+
* // With a footer (Cancel | Apply) — stage picks in a local draft, only commit on Apply;
|
|
579
|
+
* // Cancel just closes without touching the real value. Uses the forwarded `open` prop.
|
|
580
|
+
* const [open, setOpen] = React.useState(false)
|
|
581
|
+
* const [applied, setApplied] = React.useState<string[]>([])
|
|
582
|
+
* const [draft, setDraft] = React.useState<string[]>(applied)
|
|
583
|
+
* <SelectMultiple
|
|
584
|
+
* value={draft}
|
|
585
|
+
* onValueChange={setDraft}
|
|
586
|
+
* open={open}
|
|
587
|
+
* onOpenChange={(next) => { if (next) setDraft(applied); setOpen(next) }}
|
|
588
|
+
* >
|
|
589
|
+
* <SelectMultipleTrigger className="w-56" placeholder="Select spices" />
|
|
590
|
+
* <SelectMultipleContent>
|
|
591
|
+
* {spices.map((spice) => <SelectMultipleItem key={spice} value={spice}>{spice}</SelectMultipleItem>)}
|
|
592
|
+
* <SelectMultipleSeparator />
|
|
593
|
+
* <div className="flex justify-end gap-1 p-1">
|
|
594
|
+
* <Button size="sm" variant="ghost" onClick={() => { setDraft(applied); setOpen(false) }}>Cancel</Button>
|
|
595
|
+
* <Button size="sm" onClick={() => { setApplied(draft); setOpen(false) }}>Apply</Button>
|
|
596
|
+
* </div>
|
|
597
|
+
* </SelectMultipleContent>
|
|
598
|
+
* </SelectMultiple>
|
|
599
|
+
*
|
|
600
|
+
* // "Select all" — a plain composition using the same Checkbox, no dedicated API:
|
|
601
|
+
* <Checkbox
|
|
602
|
+
* checked={value.length === 0 ? false : value.length === allValues.length ? true : "indeterminate"}
|
|
603
|
+
* onCheckedChange={(c) => setValue(c ? allValues : [])}
|
|
604
|
+
* />
|
|
605
|
+
*/
|
|
606
|
+
//#endregion
|
|
607
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectMultiple, SelectMultipleContent, SelectMultipleFooter, SelectMultipleGroup, SelectMultipleItem, SelectMultipleLabel, SelectMultipleSeparator, SelectMultipleTrigger, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue };
|
|
608
|
+
|
|
609
|
+
//# sourceMappingURL=select.js.map
|