@ai-matrx/design-system 0.1.1 → 0.3.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/dist/index.cjs ADDED
@@ -0,0 +1,1955 @@
1
+ "use client";
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ Badge: () => Badge,
35
+ BasicInput: () => BasicInput,
36
+ BottomSheet: () => BottomSheet,
37
+ BottomSheetBody: () => BottomSheetBody,
38
+ BottomSheetFooter: () => BottomSheetFooter,
39
+ BottomSheetHeader: () => BottomSheetHeader,
40
+ Button: () => Button,
41
+ Command: () => Command,
42
+ CommandDialog: () => CommandDialog,
43
+ CommandEmpty: () => CommandEmpty,
44
+ CommandGroup: () => CommandGroup,
45
+ CommandInput: () => CommandInput,
46
+ CommandItem: () => CommandItem,
47
+ CommandList: () => CommandList,
48
+ CommandSeparator: () => CommandSeparator,
49
+ CommandShortcut: () => CommandShortcut,
50
+ CreatablePicker: () => CreatablePicker,
51
+ DEFAULT_SCORE_THRESHOLDS: () => DEFAULT_SCORE_THRESHOLDS,
52
+ EditableLabel: () => EditableLabel,
53
+ EnterInput: () => EnterInput,
54
+ Input: () => Input,
55
+ InputWithPrefix: () => InputWithPrefix,
56
+ Label: () => Label,
57
+ OverflowToolbar: () => OverflowToolbar,
58
+ Popover: () => Popover,
59
+ PopoverAnchor: () => PopoverAnchor,
60
+ PopoverContent: () => PopoverContent,
61
+ PopoverTrigger: () => PopoverTrigger,
62
+ PortalContainerProvider: () => PortalContainerProvider,
63
+ RadixDialogModalProvider: () => RadixDialogModalProvider,
64
+ ScoreRing: () => ScoreRing,
65
+ SegmentedControl: () => SegmentedControl,
66
+ Select: () => Select,
67
+ SelectContent: () => SelectContent,
68
+ SelectGroup: () => SelectGroup,
69
+ SelectItem: () => SelectItem,
70
+ SelectLabel: () => SelectLabel,
71
+ SelectScrollDownButton: () => SelectScrollDownButton,
72
+ SelectScrollUpButton: () => SelectScrollUpButton,
73
+ SelectSeparator: () => SelectSeparator,
74
+ SelectTrigger: () => SelectTrigger,
75
+ SelectValue: () => SelectValue,
76
+ Separator: () => Separator2,
77
+ Sheet: () => Sheet,
78
+ SheetClose: () => SheetClose,
79
+ SheetContent: () => SheetContent,
80
+ SheetDescription: () => SheetDescription,
81
+ SheetFooter: () => SheetFooter,
82
+ SheetHeader: () => SheetHeader,
83
+ SheetOverlay: () => SheetOverlay,
84
+ SheetPortal: () => SheetPortal,
85
+ SheetTitle: () => SheetTitle,
86
+ SheetTrigger: () => SheetTrigger,
87
+ Skeleton: () => Skeleton,
88
+ TabbedBottomSheet: () => TabbedBottomSheet,
89
+ badgeVariants: () => badgeVariants,
90
+ buttonVariants: () => buttonVariants,
91
+ cn: () => cn,
92
+ scoreAccentBgClasses: () => scoreAccentBgClasses,
93
+ scoreRingColorClasses: () => scoreRingColorClasses,
94
+ selectTriggerVariants: () => selectTriggerVariants,
95
+ sheetVariants: () => sheetVariants,
96
+ usePortalContainer: () => usePortalContainer,
97
+ useRadixDialogModal: () => useRadixDialogModal,
98
+ useScrollFade: () => useScrollFade
99
+ });
100
+ module.exports = __toCommonJS(src_exports);
101
+
102
+ // src/badge.tsx
103
+ var import_class_variance_authority = require("class-variance-authority");
104
+
105
+ // src/cn.ts
106
+ var import_clsx = require("clsx");
107
+ var import_tailwind_merge = require("tailwind-merge");
108
+ function cn(...inputs) {
109
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
110
+ }
111
+
112
+ // src/badge.tsx
113
+ var import_jsx_runtime = require("react/jsx-runtime");
114
+ var badgeVariants = (0, import_class_variance_authority.cva)(
115
+ "inline-flex items-center rounded-md border px-2 py-0.5 text-[11px] font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-0",
116
+ {
117
+ variants: {
118
+ variant: {
119
+ default: "border-transparent bg-primary/15 text-primary",
120
+ secondary: "border-transparent bg-secondary text-secondary-foreground",
121
+ destructive: "border-transparent bg-destructive/15 text-destructive",
122
+ outline: "border-border text-foreground",
123
+ success: "border-transparent bg-success/15 text-success",
124
+ warning: "border-transparent bg-warning/15 text-warning",
125
+ info: "border-blue-200 bg-blue-100 text-blue-800",
126
+ error: "border-transparent bg-red-500/15 text-red-700 dark:text-red-400",
127
+ neutral: "border-border bg-muted text-muted-foreground"
128
+ }
129
+ },
130
+ defaultVariants: {
131
+ variant: "default"
132
+ }
133
+ }
134
+ );
135
+ function Badge({ className, variant, ...props }) {
136
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn(badgeVariants({ variant }), className), ...props });
137
+ }
138
+
139
+ // src/bottom-sheet.tsx
140
+ var import_react_visually_hidden = require("@radix-ui/react-visually-hidden");
141
+ var React2 = __toESM(require("react"), 1);
142
+ var import_vaul = require("vaul");
143
+
144
+ // src/icons.tsx
145
+ var import_jsx_runtime2 = require("react/jsx-runtime");
146
+ function lucideProps(props) {
147
+ return {
148
+ xmlns: "http://www.w3.org/2000/svg",
149
+ viewBox: "0 0 24 24",
150
+ fill: "none",
151
+ stroke: "currentColor",
152
+ strokeWidth: 2,
153
+ strokeLinecap: "round",
154
+ strokeLinejoin: "round",
155
+ "aria-hidden": true,
156
+ ...props
157
+ };
158
+ }
159
+ function Loader2Icon(props) {
160
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
161
+ }
162
+ function ChevronLeftIcon(props) {
163
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m15 18-6-6 6-6" }) });
164
+ }
165
+ function ChevronRightIcon(props) {
166
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 18 6-6-6-6" }) });
167
+ }
168
+ function MoreHorizontalIcon(props) {
169
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "1" }),
171
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "19", cy: "12", r: "1" }),
172
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5", cy: "12", r: "1" })
173
+ ] });
174
+ }
175
+ function LucideCheckIcon(props) {
176
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...lucideProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 6 9 17l-5-5" }) });
177
+ }
178
+ function ChevronsUpDownIcon(props) {
179
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m7 15 5 5 5-5" }),
181
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m7 9 5-5 5 5" })
182
+ ] });
183
+ }
184
+ function ExternalLinkIcon(props) {
185
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
186
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M15 3h6v6" }),
187
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 14 21 3" }),
188
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
189
+ ] });
190
+ }
191
+ function LockIcon(props) {
192
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
193
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { width: "18", height: "11", x: "3", y: "11", rx: "2", ry: "2" }),
194
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
195
+ ] });
196
+ }
197
+ function PlusIcon(props) {
198
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
199
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M5 12h14" }),
200
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 5v14" })
201
+ ] });
202
+ }
203
+ function XIcon(props) {
204
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
205
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 6 6 18" }),
206
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 6 12 12" })
207
+ ] });
208
+ }
209
+ function radixProps(props) {
210
+ return {
211
+ xmlns: "http://www.w3.org/2000/svg",
212
+ viewBox: "0 0 15 15",
213
+ width: 15,
214
+ height: 15,
215
+ fill: "none",
216
+ "aria-hidden": true,
217
+ ...props
218
+ };
219
+ }
220
+ function MagnifyingGlassIcon(props) {
221
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
222
+ "path",
223
+ {
224
+ d: "M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z",
225
+ fill: "currentColor",
226
+ fillRule: "evenodd",
227
+ clipRule: "evenodd"
228
+ }
229
+ ) });
230
+ }
231
+ function CheckIcon(props) {
232
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
233
+ "path",
234
+ {
235
+ d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
236
+ fill: "currentColor",
237
+ fillRule: "evenodd",
238
+ clipRule: "evenodd"
239
+ }
240
+ ) });
241
+ }
242
+ function RadixChevronDownIcon(props) {
243
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
244
+ "path",
245
+ {
246
+ d: "M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z",
247
+ fill: "currentColor",
248
+ fillRule: "evenodd",
249
+ clipRule: "evenodd"
250
+ }
251
+ ) });
252
+ }
253
+ function RadixChevronUpIcon(props) {
254
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
255
+ "path",
256
+ {
257
+ d: "M3.13523 8.84197C3.3241 9.04343 3.64052 9.05363 3.84197 8.86477L7.5 5.43536L11.158 8.86477C11.3595 9.05363 11.6759 9.04343 11.8648 8.84197C12.0536 8.64051 12.0434 8.32409 11.842 8.13523L7.84197 4.38523C7.64964 4.20492 7.35036 4.20492 7.15803 4.38523L3.15803 8.13523C2.95657 8.32409 2.94637 8.64051 3.13523 8.84197Z",
258
+ fill: "currentColor",
259
+ fillRule: "evenodd",
260
+ clipRule: "evenodd"
261
+ }
262
+ ) });
263
+ }
264
+ function Cross2Icon(props) {
265
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
266
+ "svg",
267
+ {
268
+ xmlns: "http://www.w3.org/2000/svg",
269
+ viewBox: "0 0 15 15",
270
+ fill: "none",
271
+ "aria-hidden": true,
272
+ ...props,
273
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
274
+ "path",
275
+ {
276
+ d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z",
277
+ fill: "currentColor",
278
+ fillRule: "evenodd",
279
+ clipRule: "evenodd"
280
+ }
281
+ )
282
+ }
283
+ );
284
+ }
285
+
286
+ // src/radix-dialog-modal-context.tsx
287
+ var React = __toESM(require("react"), 1);
288
+ var import_jsx_runtime3 = require("react/jsx-runtime");
289
+ var RadixDialogModalContext = React.createContext(true);
290
+ function RadixDialogModalProvider({
291
+ children,
292
+ modal
293
+ }) {
294
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
295
+ }
296
+ function useRadixDialogModal() {
297
+ return React.useContext(RadixDialogModalContext);
298
+ }
299
+
300
+ // src/bottom-sheet.tsx
301
+ var import_jsx_runtime4 = require("react/jsx-runtime");
302
+ var DrawerRoot = ({
303
+ children,
304
+ shouldScaleBackground = true,
305
+ ...props
306
+ }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RadixDialogModalProvider, { modal: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
307
+ import_vaul.Drawer.Root,
308
+ {
309
+ modal: true,
310
+ shouldScaleBackground,
311
+ ...props,
312
+ children
313
+ }
314
+ ) });
315
+ DrawerRoot.displayName = "DrawerRoot";
316
+ var DrawerContentPrimitive = React2.forwardRef(({ ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Content, { ...props, ref, "aria-modal": "true" }));
317
+ DrawerContentPrimitive.displayName = "DrawerContentPrimitive";
318
+ function BottomSheet({
319
+ open,
320
+ onOpenChange,
321
+ title = "Bottom Sheet",
322
+ size = "adaptive",
323
+ surface = "glass",
324
+ contentClassName,
325
+ children
326
+ }) {
327
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DrawerRoot, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_vaul.Drawer.Portal, { children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
329
+ import_vaul.Drawer.Overlay,
330
+ {
331
+ className: cn("fixed inset-0 z-50 bg-black/80", "fixed inset-0 z-50"),
332
+ style: { background: "rgba(0, 0, 0, 0.08)" }
333
+ }
334
+ ),
335
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
336
+ DrawerContentPrimitive,
337
+ {
338
+ className: cn(
339
+ "fixed inset-x-0 bottom-0 z-50 mt-24 flex flex-col rounded-t-2xl overflow-hidden",
340
+ size === "full" ? "h-[92dvh]" : "min-h-[60dvh] max-h-[90dvh]",
341
+ surface === "solid" && "border border-b-0 border-border bg-background shadow-2xl",
342
+ contentClassName
343
+ ),
344
+ style: surface === "glass" ? {
345
+ background: "var(--matrx-glass-bg)",
346
+ backdropFilter: "blur(20px) saturate(180%)",
347
+ WebkitBackdropFilter: "blur(20px) saturate(180%)",
348
+ border: "1px solid var(--matrx-glass-border-color)",
349
+ borderBottom: "none"
350
+ } : void 0,
351
+ children: [
352
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_visually_hidden.VisuallyHidden, { children: [
353
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Title, { children: title }),
354
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_vaul.Drawer.Description, { children: "Bottom sheet panel." })
355
+ ] }),
356
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "mx-auto mt-3 mb-1 h-1.5 w-10 rounded-full bg-muted-foreground/30 flex-shrink-0" }),
357
+ children
358
+ ]
359
+ }
360
+ )
361
+ ] }) });
362
+ }
363
+ function BottomSheetHeader({
364
+ title,
365
+ showBack = false,
366
+ onBack,
367
+ trailing
368
+ }) {
369
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center px-2 pt-1 pb-2 flex-shrink-0 min-h-[44px]", children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-[44px] flex items-center justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
371
+ "button",
372
+ {
373
+ onClick: onBack,
374
+ className: cn(
375
+ "h-8 w-8 rounded-full matrx-glass-thin-border flex items-center justify-center transition-all active:scale-95",
376
+ showBack ? "opacity-100" : "opacity-0 pointer-events-none"
377
+ ),
378
+ "aria-hidden": !showBack,
379
+ tabIndex: showBack ? 0 : -1,
380
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeftIcon, { className: "h-4 w-4 text-foreground" })
381
+ }
382
+ ) }),
383
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-[17px] font-semibold flex-1 text-center truncate", children: title }),
384
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-[44px] flex items-center justify-end", children: trailing })
385
+ ] });
386
+ }
387
+ function BottomSheetBody({ children, className }) {
388
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
389
+ "div",
390
+ {
391
+ className: cn(
392
+ // min-h-0 is load-bearing: without it a flex child's min-height:auto
393
+ // floors it at content height and the body grows instead of scrolling.
394
+ "min-h-0 flex-1 overflow-y-auto overscroll-contain pb-safe",
395
+ className
396
+ ),
397
+ children
398
+ }
399
+ );
400
+ }
401
+ function BottomSheetFooter({
402
+ children,
403
+ className
404
+ }) {
405
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
406
+ "div",
407
+ {
408
+ className: cn(
409
+ "flex-shrink-0 px-4 py-3 pb-safe border-t border-white/[0.06]",
410
+ className
411
+ ),
412
+ children
413
+ }
414
+ );
415
+ }
416
+
417
+ // src/button.tsx
418
+ var import_react_slot = require("@radix-ui/react-slot");
419
+ var import_class_variance_authority2 = require("class-variance-authority");
420
+ var React3 = __toESM(require("react"), 1);
421
+ var import_jsx_runtime5 = require("react/jsx-runtime");
422
+ var buttonVariants = (0, import_class_variance_authority2.cva)(
423
+ "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
424
+ {
425
+ variants: {
426
+ variant: {
427
+ default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
428
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
429
+ outline: "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground",
430
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
431
+ ghost: "hover:bg-accent hover:text-accent-foreground",
432
+ link: "text-primary underline-offset-4 hover:underline",
433
+ subtle: "border border-transparent bg-muted/50 text-foreground hover:border-border hover:bg-muted"
434
+ },
435
+ size: {
436
+ default: "h-9 px-4 py-2",
437
+ sm: "h-8 rounded-md px-3 text-xs",
438
+ lg: "h-10 rounded-md px-6",
439
+ icon: "h-9 w-9",
440
+ "icon-sm": "h-7 w-7"
441
+ }
442
+ },
443
+ defaultVariants: {
444
+ variant: "default",
445
+ size: "default"
446
+ }
447
+ }
448
+ );
449
+ var Button = React3.forwardRef(
450
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
451
+ const Component = asChild ? import_react_slot.Slot : "button";
452
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
453
+ Component,
454
+ {
455
+ className: cn(buttonVariants({ variant, size, className })),
456
+ ref,
457
+ ...props
458
+ }
459
+ );
460
+ }
461
+ );
462
+ Button.displayName = "Button";
463
+
464
+ // src/command.tsx
465
+ var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
466
+ var import_cmdk = require("cmdk");
467
+ var React5 = __toESM(require("react"), 1);
468
+
469
+ // src/portal-container.tsx
470
+ var React4 = __toESM(require("react"), 1);
471
+ var import_jsx_runtime6 = require("react/jsx-runtime");
472
+ var PortalContainerContext = React4.createContext(
473
+ void 0
474
+ );
475
+ function PortalContainerProvider({
476
+ container,
477
+ children
478
+ }) {
479
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
480
+ }
481
+ function usePortalContainer(explicit) {
482
+ const injected = React4.useContext(PortalContainerContext);
483
+ if (explicit !== void 0) {
484
+ return explicit ?? void 0;
485
+ }
486
+ return injected ?? void 0;
487
+ }
488
+
489
+ // src/command.tsx
490
+ var import_jsx_runtime7 = require("react/jsx-runtime");
491
+ var Command = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
492
+ import_cmdk.Command,
493
+ {
494
+ ref,
495
+ className: cn(
496
+ "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
497
+ className
498
+ ),
499
+ ...props
500
+ }
501
+ ));
502
+ Command.displayName = import_cmdk.Command.displayName;
503
+ var MOBILE_BREAKPOINT = 768;
504
+ function useIsMobile() {
505
+ const [isMobile, setIsMobile] = React5.useState(false);
506
+ const [hasMounted, setHasMounted] = React5.useState(false);
507
+ React5.useEffect(() => {
508
+ setHasMounted(true);
509
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
510
+ const onChange = () => {
511
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
512
+ };
513
+ onChange();
514
+ mql.addEventListener("change", onChange);
515
+ return () => mql.removeEventListener("change", onChange);
516
+ }, []);
517
+ if (!hasMounted) {
518
+ return false;
519
+ }
520
+ return isMobile;
521
+ }
522
+ var DIALOG_DESKTOP_CLASSES = "fixed left-[50%] top-[50%] z-[10000] grid min-w-0 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg";
523
+ var DIALOG_MOBILE_SHEET_CLASSES = "fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] translate-x-0 translate-y-0 gap-4 overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full duration-200 rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom";
524
+ var DIALOG_MOBILE_SHEET_OVERRIDE = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-x-0 translate-y-0 w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
525
+ var CommandDialogContent = React5.forwardRef(({ className, children, container, ...props }, ref) => {
526
+ const isMobile = useIsMobile();
527
+ const isModal = useRadixDialogModal();
528
+ const portalContainer = usePortalContainer(container);
529
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogPrimitive.Portal, { container: portalContainer, children: [
530
+ isModal ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
531
+ DialogPrimitive.Overlay,
532
+ {
533
+ className: "fixed inset-0 z-[10000] bg-black/20 dark:bg-black/30 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
534
+ }
535
+ ) : null,
536
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
537
+ DialogPrimitive.Content,
538
+ {
539
+ ref,
540
+ "aria-modal": isModal || void 0,
541
+ "aria-describedby": void 0,
542
+ className: cn(
543
+ isMobile ? DIALOG_MOBILE_SHEET_CLASSES : DIALOG_DESKTOP_CLASSES,
544
+ className,
545
+ isMobile && DIALOG_MOBILE_SHEET_OVERRIDE,
546
+ !isModal && "z-[900]"
547
+ ),
548
+ ...props,
549
+ children: [
550
+ children,
551
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogPrimitive.Close, { className: "absolute right-2 top-4 flex h-10 w-10 items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground sm:right-4", children: [
552
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(XIcon, { className: "h-4 w-4" }),
553
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "sr-only", children: "Close" })
554
+ ] })
555
+ ]
556
+ }
557
+ )
558
+ ] });
559
+ });
560
+ CommandDialogContent.displayName = "CommandDialogContent";
561
+ var CommandDialog = ({
562
+ children,
563
+ container,
564
+ ...props
565
+ }) => {
566
+ const modal = props.modal ?? true;
567
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogPrimitive.Root, { ...props, modal, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
568
+ CommandDialogContent,
569
+ {
570
+ className: "overflow-hidden p-0",
571
+ ...container !== void 0 ? { container } : {},
572
+ children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogPrimitive.Title, { className: "sr-only" }),
574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Command, { className: "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children })
575
+ ]
576
+ }
577
+ ) }) });
578
+ };
579
+ var CommandInput = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center border-b px-3", "cmdk-input-wrapper": "", children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MagnifyingGlassIcon, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
582
+ import_cmdk.Command.Input,
583
+ {
584
+ ref,
585
+ className: cn(
586
+ "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
587
+ className
588
+ ),
589
+ ...props
590
+ }
591
+ )
592
+ ] }));
593
+ CommandInput.displayName = import_cmdk.Command.Input.displayName;
594
+ var CommandList = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
595
+ import_cmdk.Command.List,
596
+ {
597
+ ref,
598
+ className: cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
599
+ ...props
600
+ }
601
+ ));
602
+ CommandList.displayName = import_cmdk.Command.List.displayName;
603
+ var CommandEmpty = React5.forwardRef((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
604
+ import_cmdk.Command.Empty,
605
+ {
606
+ ref,
607
+ className: "py-6 text-center text-sm",
608
+ ...props
609
+ }
610
+ ));
611
+ CommandEmpty.displayName = import_cmdk.Command.Empty.displayName;
612
+ var CommandGroup = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
613
+ import_cmdk.Command.Group,
614
+ {
615
+ ref,
616
+ className: cn(
617
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
618
+ className
619
+ ),
620
+ ...props
621
+ }
622
+ ));
623
+ CommandGroup.displayName = import_cmdk.Command.Group.displayName;
624
+ var CommandSeparator = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
625
+ import_cmdk.Command.Separator,
626
+ {
627
+ ref,
628
+ className: cn("-mx-1 h-px bg-border", className),
629
+ ...props
630
+ }
631
+ ));
632
+ CommandSeparator.displayName = import_cmdk.Command.Separator.displayName;
633
+ var CommandItem = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
634
+ import_cmdk.Command.Item,
635
+ {
636
+ ref,
637
+ className: cn(
638
+ "relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
639
+ className
640
+ ),
641
+ ...props
642
+ }
643
+ ));
644
+ CommandItem.displayName = import_cmdk.Command.Item.displayName;
645
+ var CommandShortcut = ({
646
+ className,
647
+ ...props
648
+ }) => {
649
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
650
+ "span",
651
+ {
652
+ className: cn(
653
+ "ml-auto text-xs tracking-widest text-muted-foreground",
654
+ className
655
+ ),
656
+ ...props
657
+ }
658
+ );
659
+ };
660
+ CommandShortcut.displayName = "CommandShortcut";
661
+
662
+ // src/creatable-picker.tsx
663
+ var import_react = require("react");
664
+
665
+ // src/popover.tsx
666
+ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
667
+ var React6 = __toESM(require("react"), 1);
668
+ var import_jsx_runtime8 = require("react/jsx-runtime");
669
+ var Popover = PopoverPrimitive.Root;
670
+ var PopoverTrigger = PopoverPrimitive.Trigger;
671
+ var PopoverAnchor = PopoverPrimitive.Anchor;
672
+ var PopoverContent = React6.forwardRef(
673
+ ({ className, align = "center", sideOffset = 4, container, ...props }, ref) => {
674
+ const portalContainer = usePortalContainer(container);
675
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
676
+ PopoverPrimitive.Content,
677
+ {
678
+ ref,
679
+ align,
680
+ sideOffset,
681
+ className: cn(
682
+ // Cap to the viewport space Radix measured and scroll — a popover taller
683
+ // than the screen must never trap the user with unreachable content.
684
+ // z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
685
+ // z, DOM portal order decides, so a dialog opened FROM a popover stacks
686
+ // above it, and a popover opened from a dialog still stacks above the
687
+ // dialog. z-[10001] buried dialogs behind fullscreen popovers.
688
+ "z-[10000] w-72 max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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",
689
+ className
690
+ ),
691
+ ...props
692
+ }
693
+ ) });
694
+ }
695
+ );
696
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
697
+
698
+ // src/creatable-picker.tsx
699
+ var import_jsx_runtime9 = require("react/jsx-runtime");
700
+ function article(noun) {
701
+ return /^[aeiou]/i.test(noun.trim()) ? `an ${noun}` : `a ${noun}`;
702
+ }
703
+ function CreatablePicker({
704
+ value,
705
+ options,
706
+ onSelect,
707
+ placeholder,
708
+ searchPlaceholder,
709
+ noun,
710
+ onCreate,
711
+ onCreateRequiresMore,
712
+ disabled,
713
+ loading,
714
+ className,
715
+ triggerClassName,
716
+ emptyLabel = "No match.",
717
+ ariaLabel,
718
+ lockedNote,
719
+ lockedAction,
720
+ createExtra,
721
+ manageAction,
722
+ footerActions,
723
+ renderSelected,
724
+ size = "sm"
725
+ }) {
726
+ const [open, setOpen] = (0, import_react.useState)(false);
727
+ const [query, setQuery] = (0, import_react.useState)("");
728
+ const [busy, setBusy] = (0, import_react.useState)(false);
729
+ const inputRef = (0, import_react.useRef)(null);
730
+ const [needsName, setNeedsName] = (0, import_react.useState)(false);
731
+ const selected = options.find((option) => option.value === value) ?? null;
732
+ const groups = [];
733
+ for (const option of options) {
734
+ const last = groups[groups.length - 1];
735
+ if (last && last.heading === option.group) last.options.push(option);
736
+ else
737
+ groups.push(
738
+ option.group === void 0 ? { options: [option] } : { heading: option.group, options: [option] }
739
+ );
740
+ }
741
+ const typed = query.trim();
742
+ const exactMatch = options.some(
743
+ (option) => option.label.toLowerCase() === typed.toLowerCase()
744
+ );
745
+ const canCreate = Boolean(onCreate ?? onCreateRequiresMore) && !lockedNote;
746
+ const close = () => {
747
+ setOpen(false);
748
+ setQuery("");
749
+ setNeedsName(false);
750
+ };
751
+ const create = async (text) => {
752
+ const name = text.trim();
753
+ if (busy) return;
754
+ if (onCreateRequiresMore) {
755
+ close();
756
+ onCreateRequiresMore(name);
757
+ return;
758
+ }
759
+ if (!onCreate) return;
760
+ if (!name) {
761
+ setNeedsName(true);
762
+ inputRef.current?.focus();
763
+ return;
764
+ }
765
+ setBusy(true);
766
+ try {
767
+ const next = await onCreate(name);
768
+ if (next) onSelect(next);
769
+ close();
770
+ } finally {
771
+ setBusy(false);
772
+ }
773
+ };
774
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Popover, { open, onOpenChange: (next) => next ? setOpen(true) : close(), children: [
775
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PopoverTrigger, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
776
+ "button",
777
+ {
778
+ type: "button",
779
+ "aria-label": ariaLabel ?? placeholder,
780
+ className: cn(
781
+ "flex w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 text-left shadow-xs transition-colors",
782
+ "hover:border-primary/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
783
+ "disabled:cursor-not-allowed disabled:opacity-50",
784
+ size === "sm" ? "h-8 text-xs" : "h-9 text-sm",
785
+ className,
786
+ triggerClassName
787
+ ),
788
+ children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 flex-1 truncate", children: selected ? renderSelected ?? selected.render ?? selected.label : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-muted-foreground", children: loading ? "Loading\u2026" : placeholder }) }),
790
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChevronsUpDownIcon, { className: "size-3.5 shrink-0 opacity-50" })
791
+ ]
792
+ }
793
+ ) }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PopoverContent, { align: "start", className: "w-[--radix-popover-trigger-width] min-w-56 p-0", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
795
+ Command,
796
+ {
797
+ filter: (itemValue, search, keywords) => {
798
+ const haystack = `${itemValue} ${keywords?.join(" ") ?? ""}`.toLowerCase();
799
+ return haystack.includes(search.toLowerCase()) ? 1 : 0;
800
+ },
801
+ children: [
802
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
803
+ CommandInput,
804
+ {
805
+ ref: inputRef,
806
+ value: query,
807
+ onValueChange: (next) => {
808
+ setQuery(next);
809
+ if (next.trim()) setNeedsName(false);
810
+ },
811
+ placeholder: searchPlaceholder ?? `Search or add ${article(noun)}\u2026`
812
+ }
813
+ ),
814
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(CommandList, { children: [
815
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CommandEmpty, { children: emptyLabel }),
816
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
817
+ CommandGroup,
818
+ {
819
+ ...group.heading === void 0 ? {} : { heading: group.heading },
820
+ children: group.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
821
+ CommandItem,
822
+ {
823
+ value: option.label,
824
+ ...option.keywords ? { keywords: [option.keywords] } : {},
825
+ onSelect: () => {
826
+ onSelect(option.value);
827
+ close();
828
+ },
829
+ className: "gap-2 text-xs",
830
+ children: [
831
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
832
+ LucideCheckIcon,
833
+ {
834
+ className: cn(
835
+ "size-3.5 shrink-0",
836
+ option.value === value ? "opacity-100" : "opacity-0"
837
+ )
838
+ }
839
+ ),
840
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 flex-1 truncate", children: option.render ?? option.label }),
841
+ option.hint ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: option.hint }) : null
842
+ ]
843
+ },
844
+ option.value
845
+ ))
846
+ },
847
+ group.heading ?? "__ungrouped__"
848
+ ))
849
+ ] }),
850
+ canCreate ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1 border-t border-border p-1", children: [
851
+ createExtra && typed && !exactMatch ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "px-1 pt-0.5", children: typeof createExtra === "function" ? createExtra(typed) : createExtra }) : null,
852
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
853
+ "button",
854
+ {
855
+ type: "button",
856
+ disabled: busy,
857
+ onClick: () => void create(typed),
858
+ className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50",
859
+ children: [
860
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Loader2Icon, { className: "size-3.5 shrink-0 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PlusIcon, { className: "size-3.5 shrink-0" }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 truncate", children: typed && !exactMatch ? `Create \u201C${typed}\u201D` : `Add ${article(noun)}\u2026` })
862
+ ]
863
+ }
864
+ ),
865
+ needsName ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "px-2 pb-0.5 text-[11px] leading-snug text-muted-foreground", children: [
866
+ "Type the name of the ",
867
+ noun,
868
+ " you want to add \u2014 then this creates it."
869
+ ] }) : null
870
+ ] }) : null,
871
+ footerActions?.length || manageAction ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-0.5 border-t border-border p-1", children: [
872
+ footerActions?.map((action) => {
873
+ const Icon2 = action.icon;
874
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
875
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
876
+ "button",
877
+ {
878
+ type: "button",
879
+ onClick: () => {
880
+ close();
881
+ action.onSelect();
882
+ },
883
+ className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
884
+ children: [
885
+ Icon2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon2, { className: "size-3.5 shrink-0" }) : null,
886
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 truncate", children: action.label })
887
+ ]
888
+ }
889
+ ),
890
+ action.note ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "px-2 pb-1 text-[10px] leading-snug text-muted-foreground", children: action.note }) : null
891
+ ] }, action.label);
892
+ }),
893
+ manageAction ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
894
+ "a",
895
+ {
896
+ href: manageAction.href,
897
+ target: "_blank",
898
+ rel: "noopener noreferrer",
899
+ onClick: close,
900
+ className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
901
+ children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ExternalLinkIcon, { className: "size-3.5 shrink-0" }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 truncate", children: manageAction.label })
904
+ ]
905
+ }
906
+ ) : null
907
+ ] }) : null,
908
+ lockedNote ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "space-y-1 border-t border-border p-2", children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "flex gap-1.5 text-[11px] leading-snug text-muted-foreground", children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LockIcon, { className: "mt-px size-3 shrink-0" }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: lockedNote })
912
+ ] }),
913
+ lockedAction ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
914
+ "button",
915
+ {
916
+ type: "button",
917
+ onClick: () => {
918
+ close();
919
+ lockedAction.onSelect();
920
+ },
921
+ className: "flex w-full items-center gap-2 rounded-sm px-1 py-1 text-left text-xs font-medium text-primary transition-colors hover:bg-accent",
922
+ children: [
923
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PlusIcon, { className: "size-3.5 shrink-0" }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "min-w-0 truncate", children: lockedAction.label })
925
+ ]
926
+ }
927
+ ) : null
928
+ ] }) : null
929
+ ]
930
+ }
931
+ ) })
932
+ ] });
933
+ }
934
+
935
+ // src/editable-label.tsx
936
+ var import_react2 = require("react");
937
+ var import_jsx_runtime10 = require("react/jsx-runtime");
938
+ function EditableLabel({
939
+ value,
940
+ onCommit,
941
+ commitMode = "optimistic",
942
+ validate,
943
+ emptyFallback,
944
+ maxLength = 120,
945
+ activation = "click",
946
+ editing: editingProp,
947
+ onEditingChange,
948
+ selectOnEdit = true,
949
+ placeholder,
950
+ ariaLabel = "Name",
951
+ truncate = true,
952
+ className,
953
+ displayClassName,
954
+ inputClassName
955
+ }) {
956
+ const controlled = activation === "controlled";
957
+ const [internalEditing, setInternalEditing] = (0, import_react2.useState)(false);
958
+ const editing = controlled ? !!editingProp : internalEditing;
959
+ const [draft, setDraft] = (0, import_react2.useState)(value);
960
+ const [error, setError] = (0, import_react2.useState)(null);
961
+ const [busy, setBusy] = (0, import_react2.useState)(false);
962
+ const inputRef = (0, import_react2.useRef)(null);
963
+ (0, import_react2.useEffect)(() => {
964
+ if (!editing) setDraft(value);
965
+ }, [value, editing]);
966
+ (0, import_react2.useEffect)(() => {
967
+ if (editing && inputRef.current) {
968
+ inputRef.current.focus();
969
+ if (selectOnEdit) inputRef.current.select();
970
+ }
971
+ }, [editing, selectOnEdit]);
972
+ const setEditing = (0, import_react2.useCallback)(
973
+ (next) => {
974
+ if (controlled) {
975
+ onEditingChange?.(next);
976
+ } else {
977
+ setInternalEditing(next);
978
+ onEditingChange?.(next);
979
+ }
980
+ },
981
+ [controlled, onEditingChange]
982
+ );
983
+ const startEdit = (0, import_react2.useCallback)(() => {
984
+ setDraft(value);
985
+ setError(null);
986
+ setEditing(true);
987
+ }, [value, setEditing]);
988
+ const cancel = (0, import_react2.useCallback)(() => {
989
+ setDraft(value);
990
+ setError(null);
991
+ setBusy(false);
992
+ setEditing(false);
993
+ }, [value, setEditing]);
994
+ const commit = (0, import_react2.useCallback)(() => {
995
+ if (busy) return;
996
+ const trimmed = draft.trim();
997
+ const next = trimmed || emptyFallback;
998
+ if (next === void 0) {
999
+ cancel();
1000
+ return;
1001
+ }
1002
+ const validationError = validate?.(next) ?? null;
1003
+ if (validationError) {
1004
+ setError(validationError);
1005
+ return;
1006
+ }
1007
+ if (next === value) {
1008
+ setEditing(false);
1009
+ setError(null);
1010
+ return;
1011
+ }
1012
+ if (commitMode === "await") {
1013
+ const result2 = onCommit(next);
1014
+ if (result2 instanceof Promise) {
1015
+ setBusy(true);
1016
+ result2.then(() => {
1017
+ setBusy(false);
1018
+ setEditing(false);
1019
+ }).catch(() => {
1020
+ setBusy(false);
1021
+ });
1022
+ return;
1023
+ }
1024
+ setEditing(false);
1025
+ return;
1026
+ }
1027
+ setEditing(false);
1028
+ setError(null);
1029
+ const result = onCommit(next);
1030
+ if (result instanceof Promise) result.catch(() => {
1031
+ });
1032
+ }, [
1033
+ busy,
1034
+ draft,
1035
+ emptyFallback,
1036
+ validate,
1037
+ value,
1038
+ commitMode,
1039
+ onCommit,
1040
+ cancel,
1041
+ setEditing
1042
+ ]);
1043
+ if (editing) {
1044
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: cn("relative flex min-w-0 flex-1 items-center", className), children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1046
+ "input",
1047
+ {
1048
+ ref: inputRef,
1049
+ type: "text",
1050
+ value: draft,
1051
+ disabled: busy,
1052
+ placeholder,
1053
+ onChange: (e) => {
1054
+ setDraft(e.target.value);
1055
+ if (error) setError(null);
1056
+ },
1057
+ onBlur: commit,
1058
+ onClick: (e) => e.stopPropagation(),
1059
+ onDoubleClick: (e) => e.stopPropagation(),
1060
+ onKeyDown: (e) => {
1061
+ if (e.key === "Enter") {
1062
+ e.preventDefault();
1063
+ e.stopPropagation();
1064
+ commit();
1065
+ } else if (e.key === "Escape") {
1066
+ e.preventDefault();
1067
+ e.stopPropagation();
1068
+ cancel();
1069
+ } else if (e.key === " ") {
1070
+ e.stopPropagation();
1071
+ }
1072
+ },
1073
+ maxLength,
1074
+ "aria-label": ariaLabel,
1075
+ "aria-invalid": error ? true : void 0,
1076
+ className: cn(
1077
+ "w-full min-w-0 rounded-sm bg-transparent px-1 outline-none",
1078
+ "text-base md:text-sm",
1079
+ "focus:bg-background focus:ring-1 focus:ring-ring",
1080
+ busy && "opacity-60",
1081
+ inputClassName
1082
+ )
1083
+ }
1084
+ ),
1085
+ busy && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Loader2Icon, { className: "absolute right-1 h-3.5 w-3.5 animate-spin text-muted-foreground" }),
1086
+ error && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "absolute left-0 top-full mt-0.5 whitespace-nowrap text-xs text-destructive", children: error })
1087
+ ] });
1088
+ }
1089
+ if (controlled) return null;
1090
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1091
+ "button",
1092
+ {
1093
+ type: "button",
1094
+ onClick: activation === "click" ? (e) => {
1095
+ e.stopPropagation();
1096
+ startEdit();
1097
+ } : void 0,
1098
+ onDoubleClick: activation === "doubleClick" ? (e) => {
1099
+ e.stopPropagation();
1100
+ startEdit();
1101
+ } : void 0,
1102
+ onKeyDown: (e) => {
1103
+ if (e.key === "Enter" || e.key === " ") {
1104
+ e.preventDefault();
1105
+ e.stopPropagation();
1106
+ startEdit();
1107
+ }
1108
+ },
1109
+ title: activation === "doubleClick" ? "Double-click to rename" : "Click to rename",
1110
+ "aria-label": `Rename ${ariaLabel.toLowerCase()}: ${value}`,
1111
+ className: cn(
1112
+ "min-w-0 max-w-full rounded-sm px-1 text-left transition-colors",
1113
+ "hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1114
+ truncate && "block truncate",
1115
+ className,
1116
+ displayClassName
1117
+ ),
1118
+ children: value || placeholder || ""
1119
+ }
1120
+ );
1121
+ }
1122
+
1123
+ // src/input.tsx
1124
+ var React7 = __toESM(require("react"), 1);
1125
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1126
+ var getVariantStyles = (variant = "default") => {
1127
+ const baseStyles = `flex h-10 w-full border border-border bg-background text-black dark:text-white shadow-input rounded-md px-3 py-2 text-sm file:border-0 file:bg-transparent
1128
+ file:text-sm file:font-medium placeholder:text-neutral-400 dark:placeholder-text-neutral-600
1129
+ focus-visible:outline-none focus-visible:ring-[2px] focus-visible:ring-neutral-400 dark:focus-visible:ring-neutral-600
1130
+ disabled:cursor-not-allowed disabled:opacity-50
1131
+ dark:shadow-[0px_0px_1px_1px_var(--neutral-700)]
1132
+ transition duration-400
1133
+ [&:-webkit-autofill]:bg-background [&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill]:[caret-color:currentColor]
1134
+ dark:[&:-webkit-autofill]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] dark:[&:-webkit-autofill]:[-webkit-text-fill-color:white]
1135
+ [&:-webkit-autofill:hover]:shadow-[0_0_0_1000px_hsl(var(--background))_inset] [&:-webkit-autofill:focus]:shadow-[0_0_0_1000px_hsl(var(--background))_inset]`;
1136
+ switch (variant) {
1137
+ case "destructive":
1138
+ return `${baseStyles} bg-destructive text-destructive-foreground`;
1139
+ case "outline":
1140
+ return `${baseStyles} border-2`;
1141
+ case "secondary":
1142
+ return `${baseStyles} bg-secondary text-secondary-foreground`;
1143
+ case "ghost":
1144
+ return `${baseStyles} bg-transparent shadow-none`;
1145
+ case "link":
1146
+ return `${baseStyles} bg-transparent underline-offset-4 hover:underline`;
1147
+ case "primary":
1148
+ return `${baseStyles} bg-primary text-primary-foreground`;
1149
+ default:
1150
+ return baseStyles;
1151
+ }
1152
+ };
1153
+ var Input = React7.forwardRef(
1154
+ ({ className, type, variant = "default", ...props }, ref) => {
1155
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1156
+ "input",
1157
+ {
1158
+ type,
1159
+ className: cn(getVariantStyles(variant), className),
1160
+ ref,
1161
+ ...props
1162
+ }
1163
+ );
1164
+ }
1165
+ );
1166
+ Input.displayName = "Input";
1167
+ var EnterInput = React7.forwardRef(
1168
+ ({ onEnter, ...props }, ref) => {
1169
+ const handleKeyDown = (e) => {
1170
+ if (e.key === "Enter" && onEnter) {
1171
+ e.preventDefault();
1172
+ onEnter();
1173
+ }
1174
+ };
1175
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1176
+ Input,
1177
+ {
1178
+ ...props,
1179
+ ref,
1180
+ onKeyDown: (e) => {
1181
+ handleKeyDown(e);
1182
+ if (props.onKeyDown) {
1183
+ props.onKeyDown(e);
1184
+ }
1185
+ }
1186
+ }
1187
+ );
1188
+ }
1189
+ );
1190
+ EnterInput.displayName = "EnterInput";
1191
+ var BasicInput = React7.forwardRef(
1192
+ // `variant` is accepted (prop-compatible with Input) but intentionally
1193
+ // unused — and destructured so it never leaks onto the DOM element.
1194
+ ({ className, type, variant: _variant = "default", ...props }, ref) => {
1195
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1196
+ "input",
1197
+ {
1198
+ type,
1199
+ className: cn(
1200
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
1201
+ className
1202
+ ),
1203
+ ref,
1204
+ ...props
1205
+ }
1206
+ );
1207
+ }
1208
+ );
1209
+ BasicInput.displayName = "BasicInput";
1210
+ var InputWithPrefix = React7.forwardRef(({ prefix, className, wrapperClassName, ...props }, ref) => {
1211
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: cn("relative", wrapperClassName), children: [
1212
+ prefix && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: prefix }),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1214
+ Input,
1215
+ {
1216
+ ref,
1217
+ className: cn(prefix && "pl-10", className),
1218
+ ...props
1219
+ }
1220
+ )
1221
+ ] });
1222
+ });
1223
+ InputWithPrefix.displayName = "InputWithPrefix";
1224
+
1225
+ // src/label.tsx
1226
+ var LabelPrimitive = __toESM(require("@radix-ui/react-label"), 1);
1227
+ var React8 = __toESM(require("react"), 1);
1228
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1229
+ var Label = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1230
+ LabelPrimitive.Root,
1231
+ {
1232
+ ref,
1233
+ className: cn(
1234
+ "text-sm font-medium leading-none text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
1235
+ className
1236
+ ),
1237
+ ...props
1238
+ }
1239
+ ));
1240
+ Label.displayName = LabelPrimitive.Root.displayName;
1241
+
1242
+ // src/overflow-toolbar.tsx
1243
+ var import_react3 = require("react");
1244
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1245
+ var GAP_PX = 6;
1246
+ var TONE = {
1247
+ default: "border border-border bg-background hover:bg-accent text-foreground",
1248
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
1249
+ destructive: "border border-destructive/40 text-destructive hover:bg-destructive/10"
1250
+ };
1251
+ function ToolbarButton({
1252
+ action,
1253
+ enableTooltip = false,
1254
+ renderTooltip
1255
+ }) {
1256
+ const tone = action.tone ?? "default";
1257
+ const Icon2 = action.running ? Loader2Icon : action.icon;
1258
+ const showLabel = !action.hideLabel || action.running && action.runningLabel;
1259
+ const text = action.running && action.runningLabel ? action.runningLabel : action.label;
1260
+ const className = cn(
1261
+ "inline-flex items-center gap-1 h-7 rounded-md text-[11px] font-medium transition-colors whitespace-nowrap",
1262
+ "disabled:opacity-50 disabled:pointer-events-none",
1263
+ action.hideLabel && !action.running ? "w-7 justify-center px-0" : "px-2",
1264
+ TONE[tone]
1265
+ );
1266
+ const inner = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1268
+ Icon2,
1269
+ {
1270
+ className: cn("w-3.5 h-3.5 shrink-0", action.running && "animate-spin")
1271
+ }
1272
+ ),
1273
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: text })
1274
+ ] });
1275
+ const control = action.href && !action.disabled ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1276
+ "a",
1277
+ {
1278
+ href: action.href,
1279
+ target: action.target,
1280
+ rel: action.target === "_blank" ? "noopener noreferrer" : void 0,
1281
+ className,
1282
+ "aria-label": action.label,
1283
+ children: inner
1284
+ }
1285
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1286
+ "button",
1287
+ {
1288
+ type: "button",
1289
+ onClick: action.onSelect,
1290
+ disabled: action.disabled,
1291
+ className,
1292
+ "aria-label": action.label,
1293
+ children: inner
1294
+ }
1295
+ );
1296
+ if (enableTooltip && action.hideLabel && renderTooltip) {
1297
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: renderTooltip(control, action.label) });
1298
+ }
1299
+ return control;
1300
+ }
1301
+ function OverflowTrigger({ ariaLabel }) {
1302
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1303
+ "button",
1304
+ {
1305
+ type: "button",
1306
+ "aria-label": ariaLabel,
1307
+ "aria-haspopup": "menu",
1308
+ title: "More actions",
1309
+ className: cn(
1310
+ "inline-flex items-center justify-center h-7 w-7 rounded-md transition-colors",
1311
+ "border border-border bg-background hover:bg-accent text-foreground"
1312
+ ),
1313
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MoreHorizontalIcon, { className: "w-3.5 h-3.5" })
1314
+ }
1315
+ );
1316
+ }
1317
+ function OverflowToolbar({
1318
+ actions,
1319
+ leading,
1320
+ overflowAriaLabel = "More actions",
1321
+ className,
1322
+ renderOverflowMenu,
1323
+ renderTooltip
1324
+ }) {
1325
+ const visibleActions = (0, import_react3.useMemo)(
1326
+ () => actions.filter((a) => !a.hidden),
1327
+ [actions]
1328
+ );
1329
+ const containerRef = (0, import_react3.useRef)(null);
1330
+ const ghostRef = (0, import_react3.useRef)(null);
1331
+ const leadingRef = (0, import_react3.useRef)(null);
1332
+ const [visibleCount, setVisibleCount] = (0, import_react3.useState)(visibleActions.length);
1333
+ const signature = visibleActions.map(
1334
+ (a) => `${a.id}:${a.hideLabel ? 1 : 0}:${a.running ? 1 : 0}:${a.runningLabel ?? ""}:${a.label}`
1335
+ ).join("|");
1336
+ (0, import_react3.useLayoutEffect)(() => {
1337
+ const container = containerRef.current;
1338
+ const ghost = ghostRef.current;
1339
+ if (!container || !ghost) return void 0;
1340
+ const compute = () => {
1341
+ const available = container.clientWidth;
1342
+ const n = visibleActions.length;
1343
+ const children = Array.from(ghost.children);
1344
+ const hasLeading = leading != null;
1345
+ const leadingW = hasLeading ? leadingRef.current?.offsetWidth ?? 0 : 0;
1346
+ const itemW = (i) => children[i]?.offsetWidth ?? 0;
1347
+ const kebabW = children[n]?.offsetWidth ?? 28;
1348
+ const base = leadingW + (hasLeading && n > 0 ? GAP_PX : 0);
1349
+ let totalAll = base;
1350
+ for (let i = 0; i < n; i++) totalAll += itemW(i) + (i > 0 ? GAP_PX : 0);
1351
+ if (totalAll <= available) {
1352
+ setVisibleCount(n);
1353
+ return;
1354
+ }
1355
+ let used = base;
1356
+ let count = 0;
1357
+ for (let i = 0; i < n; i++) {
1358
+ const add = itemW(i) + (count > 0 ? GAP_PX : 0);
1359
+ if (used + add + GAP_PX + kebabW <= available) {
1360
+ used += add;
1361
+ count += 1;
1362
+ } else break;
1363
+ }
1364
+ setVisibleCount(count);
1365
+ };
1366
+ compute();
1367
+ const ro = new ResizeObserver(compute);
1368
+ ro.observe(container);
1369
+ return () => ro.disconnect();
1370
+ }, [signature, leading != null]);
1371
+ const shown = visibleActions.slice(0, visibleCount);
1372
+ const hidden = visibleActions.slice(visibleCount);
1373
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: containerRef, className: cn("relative min-w-0", className), children: [
1374
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1375
+ "div",
1376
+ {
1377
+ ref: ghostRef,
1378
+ "aria-hidden": true,
1379
+ className: "pointer-events-none absolute left-0 top-0 flex items-center gap-1.5 opacity-0",
1380
+ children: [
1381
+ visibleActions.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolbarButton, { action: a }, a.id)),
1382
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OverflowTrigger, { ariaLabel: overflowAriaLabel })
1383
+ ]
1384
+ }
1385
+ ),
1386
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-end gap-1.5", children: [
1387
+ leading != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { ref: leadingRef, className: "shrink-0", children: leading }),
1388
+ shown.map((a) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1389
+ ToolbarButton,
1390
+ {
1391
+ action: a,
1392
+ enableTooltip: true,
1393
+ renderTooltip
1394
+ },
1395
+ a.id
1396
+ )),
1397
+ hidden.length > 0 && renderOverflowMenu({
1398
+ actions: hidden,
1399
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OverflowTrigger, { ariaLabel: overflowAriaLabel })
1400
+ })
1401
+ ] })
1402
+ ] });
1403
+ }
1404
+
1405
+ // src/score-ring.tsx
1406
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1407
+ var DEFAULT_SCORE_THRESHOLDS = {
1408
+ good: 75,
1409
+ warning: 50
1410
+ };
1411
+ function scoreRingColorClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
1412
+ if (pct === null) return "text-muted-foreground";
1413
+ if (pct >= thresholds.good) return "text-green-500";
1414
+ if (pct >= thresholds.warning) return "text-orange-500";
1415
+ return "text-red-500";
1416
+ }
1417
+ function scoreAccentBgClasses(pct, thresholds = DEFAULT_SCORE_THRESHOLDS) {
1418
+ if (pct === null) return "bg-muted-foreground/30";
1419
+ if (pct >= thresholds.good) return "bg-green-500";
1420
+ if (pct >= thresholds.warning) return "bg-orange-500";
1421
+ return "bg-red-500";
1422
+ }
1423
+ function ScoreRing({
1424
+ pct,
1425
+ size = 112,
1426
+ strokeWidth = 8,
1427
+ label,
1428
+ valueClassName,
1429
+ className,
1430
+ thresholds = DEFAULT_SCORE_THRESHOLDS,
1431
+ suffix = "%"
1432
+ }) {
1433
+ const radius = 50 - strokeWidth / 2;
1434
+ const circumference = 2 * Math.PI * radius;
1435
+ const boundedPct = pct === null ? 0 : Math.max(0, Math.min(100, pct));
1436
+ const dashOffset = circumference * (1 - boundedPct / 100);
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1438
+ "div",
1439
+ {
1440
+ className: cn(
1441
+ "relative flex shrink-0 items-center justify-center",
1442
+ className
1443
+ ),
1444
+ style: { width: size, height: size },
1445
+ role: "img",
1446
+ "aria-label": `${label ?? "Score"}: ${pct === null ? "not available" : `${pct} out of 100`}`,
1447
+ children: [
1448
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("svg", { viewBox: "0 0 100 100", className: "h-full w-full -rotate-90", children: [
1449
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1450
+ "circle",
1451
+ {
1452
+ cx: "50",
1453
+ cy: "50",
1454
+ r: radius,
1455
+ className: "stroke-muted",
1456
+ strokeWidth,
1457
+ fill: "none"
1458
+ }
1459
+ ),
1460
+ pct !== null ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1461
+ "circle",
1462
+ {
1463
+ cx: "50",
1464
+ cy: "50",
1465
+ r: radius,
1466
+ className: cn(
1467
+ "transition-[stroke-dashoffset] duration-700 ease-out",
1468
+ scoreRingColorClasses(pct, thresholds)
1469
+ ),
1470
+ stroke: "currentColor",
1471
+ strokeWidth,
1472
+ strokeLinecap: "round",
1473
+ fill: "none",
1474
+ strokeDasharray: circumference,
1475
+ strokeDashoffset: dashOffset
1476
+ }
1477
+ ) : null
1478
+ ] }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "absolute flex flex-col items-center justify-center", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1481
+ "span",
1482
+ {
1483
+ className: cn(
1484
+ "font-bold tabular-nums text-foreground",
1485
+ valueClassName ?? "text-2xl"
1486
+ ),
1487
+ children: pct === null ? "\u2014" : `${pct}${suffix}`
1488
+ }
1489
+ ),
1490
+ label ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "max-w-[74px] truncate text-[9px] font-semibold uppercase tracking-wide text-muted-foreground", children: label }) : null
1491
+ ] })
1492
+ ]
1493
+ }
1494
+ );
1495
+ }
1496
+
1497
+ // src/segmented-control.tsx
1498
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1499
+ function SegmentedControl({
1500
+ value,
1501
+ onValueChange,
1502
+ data,
1503
+ name: _name,
1504
+ className,
1505
+ fullWidth = false,
1506
+ size = "md"
1507
+ }) {
1508
+ const sizeClasses = {
1509
+ sm: "h-7 text-xs",
1510
+ md: "h-9 text-sm",
1511
+ lg: "h-10 text-base"
1512
+ };
1513
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1514
+ "div",
1515
+ {
1516
+ className: cn(
1517
+ "inline-flex p-0.5 bg-muted rounded-md",
1518
+ fullWidth && "w-full",
1519
+ className
1520
+ ),
1521
+ role: "tablist",
1522
+ children: data.map((option) => {
1523
+ const isActive = value === option.value;
1524
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1525
+ "button",
1526
+ {
1527
+ type: "button",
1528
+ role: "tab",
1529
+ "aria-selected": isActive,
1530
+ disabled: option.disabled,
1531
+ onClick: () => onValueChange(option.value),
1532
+ className: cn(
1533
+ "relative flex items-center justify-center rounded-[0.2rem] px-3 py-1.5 transition-all",
1534
+ sizeClasses[size],
1535
+ fullWidth && "flex-1",
1536
+ isActive ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-background/50",
1537
+ option.disabled && "opacity-50 cursor-not-allowed"
1538
+ ),
1539
+ children: option.label
1540
+ },
1541
+ option.value
1542
+ );
1543
+ })
1544
+ }
1545
+ );
1546
+ }
1547
+
1548
+ // src/select.tsx
1549
+ var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
1550
+ var import_class_variance_authority3 = require("class-variance-authority");
1551
+ var React10 = __toESM(require("react"), 1);
1552
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1553
+ var Select = SelectPrimitive.Root;
1554
+ var SelectGroup = SelectPrimitive.Group;
1555
+ var SelectValue = SelectPrimitive.Value;
1556
+ var selectTriggerVariants = (0, import_class_variance_authority3.cva)(
1557
+ "flex w-full items-center justify-between whitespace-nowrap rounded-md border border-border bg-card text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground transition-colors hover:bg-accent hover:border-accent-foreground/20 focus:outline-none focus:ring-1 focus:ring-primary/30 focus:border-primary/40 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
1558
+ {
1559
+ variants: {
1560
+ size: {
1561
+ sm: "h-7 px-2 py-1 text-xs",
1562
+ default: "h-9 px-3 py-1",
1563
+ lg: "h-10 px-3 py-2"
1564
+ }
1565
+ },
1566
+ defaultVariants: {
1567
+ size: "default"
1568
+ }
1569
+ }
1570
+ );
1571
+ var SelectTrigger = React10.forwardRef(({ className, children, hideArrow = false, size, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1572
+ SelectPrimitive.Trigger,
1573
+ {
1574
+ ref,
1575
+ className: cn(selectTriggerVariants({ size, className })),
1576
+ ...props,
1577
+ children: [
1578
+ children,
1579
+ !hideArrow && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RadixChevronDownIcon, { className: "h-4 w-4 opacity-50" }) })
1580
+ ]
1581
+ }
1582
+ ));
1583
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1584
+ var SelectScrollUpButton = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1585
+ SelectPrimitive.ScrollUpButton,
1586
+ {
1587
+ ref,
1588
+ className: cn(
1589
+ "flex cursor-default items-center justify-center py-1",
1590
+ className
1591
+ ),
1592
+ ...props,
1593
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RadixChevronUpIcon, {})
1594
+ }
1595
+ ));
1596
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
1597
+ var SelectScrollDownButton = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1598
+ SelectPrimitive.ScrollDownButton,
1599
+ {
1600
+ ref,
1601
+ className: cn(
1602
+ "flex cursor-default items-center justify-center py-1",
1603
+ className
1604
+ ),
1605
+ ...props,
1606
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(RadixChevronDownIcon, {})
1607
+ }
1608
+ ));
1609
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
1610
+ var SelectContent = React10.forwardRef(({ className, children, position = "popper", container, ...props }, ref) => {
1611
+ const portalContainer = usePortalContainer(container);
1612
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1613
+ SelectPrimitive.Content,
1614
+ {
1615
+ ref,
1616
+ className: cn(
1617
+ "relative z-[10001] max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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",
1618
+ 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",
1619
+ className
1620
+ ),
1621
+ position,
1622
+ ...props,
1623
+ children: [
1624
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectScrollUpButton, {}),
1625
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1626
+ SelectPrimitive.Viewport,
1627
+ {
1628
+ className: cn(
1629
+ "p-0.5 overflow-y-auto",
1630
+ position === "popper" && "w-full min-w-[var(--radix-select-trigger-width)] max-h-[var(--radix-select-content-available-height)]"
1631
+ ),
1632
+ children
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectScrollDownButton, {})
1636
+ ]
1637
+ }
1638
+ ) });
1639
+ });
1640
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
1641
+ var SelectLabel = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1642
+ SelectPrimitive.Label,
1643
+ {
1644
+ ref,
1645
+ className: cn("px-2 py-1.5 text-sm font-semibold", className),
1646
+ ...props
1647
+ }
1648
+ ));
1649
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
1650
+ var SelectItem = React10.forwardRef(({ className, children, description, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1651
+ SelectPrimitive.Item,
1652
+ {
1653
+ ref,
1654
+ className: cn(
1655
+ "relative flex w-full cursor-default select-none rounded-sm py-1 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1656
+ description ? "flex-col items-start gap-0.5 py-1.5" : "items-center",
1657
+ className
1658
+ ),
1659
+ ...props,
1660
+ children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
1662
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SelectPrimitive.ItemText, { children }),
1663
+ description ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "block text-xs leading-snug text-muted-foreground", children: description }) : null
1664
+ ]
1665
+ }
1666
+ ));
1667
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
1668
+ var SelectSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1669
+ SelectPrimitive.Separator,
1670
+ {
1671
+ ref,
1672
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
1673
+ ...props
1674
+ }
1675
+ ));
1676
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
1677
+
1678
+ // src/separator.tsx
1679
+ var SeparatorPrimitive = __toESM(require("@radix-ui/react-separator"), 1);
1680
+ var React11 = __toESM(require("react"), 1);
1681
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1682
+ var Separator2 = React11.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1683
+ SeparatorPrimitive.Root,
1684
+ {
1685
+ ref,
1686
+ decorative,
1687
+ orientation,
1688
+ className: cn(
1689
+ "shrink-0 bg-border",
1690
+ orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
1691
+ className
1692
+ ),
1693
+ ...props
1694
+ }
1695
+ ));
1696
+ Separator2.displayName = SeparatorPrimitive.Root.displayName;
1697
+
1698
+ // src/sheet.tsx
1699
+ var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
1700
+ var import_react_tree = require("@ai-matrx/kit/react-tree");
1701
+ var import_class_variance_authority4 = require("class-variance-authority");
1702
+ var React12 = __toESM(require("react"), 1);
1703
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1704
+ var SheetContentBase = React12.forwardRef(({ ...props }, ref) => {
1705
+ const isModal = useRadixDialogModal();
1706
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1707
+ SheetPrimitive.Content,
1708
+ {
1709
+ ...props,
1710
+ ref,
1711
+ "aria-modal": isModal || void 0
1712
+ }
1713
+ );
1714
+ });
1715
+ SheetContentBase.displayName = "SheetContentBase";
1716
+ var Sheet = React12.forwardRef(({ children, ...props }, _ref) => {
1717
+ const modal = props.modal ?? true;
1718
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SheetPrimitive.Root, { ...props, modal, children }) });
1719
+ });
1720
+ Sheet.displayName = "Sheet";
1721
+ var SheetTrigger = SheetPrimitive.Trigger;
1722
+ var SheetClose = SheetPrimitive.Close;
1723
+ var SheetPortal = SheetPrimitive.Portal;
1724
+ var SheetOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1725
+ SheetPrimitive.Overlay,
1726
+ {
1727
+ className: cn(
1728
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
1729
+ className
1730
+ ),
1731
+ ...props,
1732
+ ref
1733
+ }
1734
+ ));
1735
+ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
1736
+ var sheetVariants = (0, import_class_variance_authority4.cva)(
1737
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
1738
+ {
1739
+ variants: {
1740
+ side: {
1741
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
1742
+ bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
1743
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
1744
+ right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
1745
+ center: "inset-0 m-auto max-h-full max-w-full border rounded-lg data-[state=closed]:fade-out data-[state=open]:fade-in"
1746
+ }
1747
+ },
1748
+ defaultVariants: {
1749
+ side: "right"
1750
+ }
1751
+ }
1752
+ );
1753
+ var SheetDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1754
+ SheetPrimitive.Description,
1755
+ {
1756
+ ref,
1757
+ className: cn("text-sm text-muted-foreground", className),
1758
+ ...props
1759
+ }
1760
+ ));
1761
+ SheetDescription.displayName = SheetPrimitive.Description.displayName;
1762
+ var SheetContent = React12.forwardRef(
1763
+ ({
1764
+ side = "right",
1765
+ className,
1766
+ children,
1767
+ hideCloseButton = false,
1768
+ hideOverlay = false,
1769
+ overlayClassName,
1770
+ ...props
1771
+ }, ref) => {
1772
+ const hasDescription = (0, import_react_tree.treeContainsComponent)(children, SheetDescription) || (0, import_react_tree.treeContainsComponent)(children, SheetPrimitive.Description);
1773
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SheetPortal, { children: [
1774
+ !hideOverlay && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SheetOverlay, { className: overlayClassName }),
1775
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1776
+ SheetContentBase,
1777
+ {
1778
+ ref,
1779
+ className: cn(sheetVariants({ side }), className),
1780
+ ...hasDescription ? {} : { "aria-describedby": void 0 },
1781
+ ...props,
1782
+ children: [
1783
+ !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
1784
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Cross2Icon, { className: "h-4 w-4" }),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sr-only", children: "Close" })
1786
+ ] }),
1787
+ children
1788
+ ]
1789
+ }
1790
+ )
1791
+ ] });
1792
+ }
1793
+ );
1794
+ SheetContent.displayName = SheetPrimitive.Content.displayName;
1795
+ var SheetHeader = ({
1796
+ className,
1797
+ ...props
1798
+ }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1799
+ "div",
1800
+ {
1801
+ className: cn(
1802
+ "flex flex-col space-y-2 text-center sm:text-left",
1803
+ className
1804
+ ),
1805
+ ...props
1806
+ }
1807
+ );
1808
+ SheetHeader.displayName = "SheetHeader";
1809
+ var SheetFooter = ({
1810
+ className,
1811
+ ...props
1812
+ }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1813
+ "div",
1814
+ {
1815
+ className: cn(
1816
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
1817
+ className
1818
+ ),
1819
+ ...props
1820
+ }
1821
+ );
1822
+ SheetFooter.displayName = "SheetFooter";
1823
+ var SheetTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1824
+ SheetPrimitive.Title,
1825
+ {
1826
+ ref,
1827
+ className: cn("text-lg font-semibold text-foreground", className),
1828
+ ...props
1829
+ }
1830
+ ));
1831
+ SheetTitle.displayName = SheetPrimitive.Title.displayName;
1832
+
1833
+ // src/skeleton.tsx
1834
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1835
+ function Skeleton({
1836
+ className,
1837
+ ...props
1838
+ }) {
1839
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1840
+ "div",
1841
+ {
1842
+ className: cn("animate-pulse rounded-md bg-primary/10", className),
1843
+ ...props
1844
+ }
1845
+ );
1846
+ }
1847
+
1848
+ // src/tabbed-bottom-sheet.tsx
1849
+ var import_react4 = require("react");
1850
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1851
+ function TabbedBottomSheet({
1852
+ open,
1853
+ onOpenChange,
1854
+ title,
1855
+ tabs
1856
+ }) {
1857
+ const [selectedTabId, setSelectedTabId] = (0, import_react4.useState)(null);
1858
+ const [wasOpen, setWasOpen] = (0, import_react4.useState)(open);
1859
+ if (open !== wasOpen) {
1860
+ setWasOpen(open);
1861
+ if (open) setSelectedTabId(null);
1862
+ }
1863
+ const selectedTab = selectedTabId ? tabs.find((tab) => tab.id === selectedTabId) : null;
1864
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1865
+ BottomSheet,
1866
+ {
1867
+ open,
1868
+ onOpenChange,
1869
+ title,
1870
+ size: "full",
1871
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "matrx-mobile-sheet flex min-h-0 flex-1 flex-col", children: [
1872
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1873
+ BottomSheetHeader,
1874
+ {
1875
+ title: selectedTab ? selectedTab.label : title,
1876
+ showBack: !!selectedTab,
1877
+ onBack: () => setSelectedTabId(null)
1878
+ }
1879
+ ),
1880
+ selectedTab ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden pb-safe", children: selectedTab.content }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BottomSheetBody, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "divide-y divide-border", children: tabs.map((tab) => {
1881
+ const Icon2 = tab.icon;
1882
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1883
+ "button",
1884
+ {
1885
+ type: "button",
1886
+ onClick: () => setSelectedTabId(tab.id),
1887
+ className: "flex w-full items-center gap-3 px-4 py-3.5 text-left transition-colors hover:bg-muted/60 active:bg-muted",
1888
+ children: [
1889
+ Icon2 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon2, { className: "h-5 w-5 shrink-0 text-muted-foreground" }) : null,
1890
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "min-w-0 flex-1 text-base text-foreground", children: tab.label }),
1891
+ tab.trailing,
1892
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChevronRightIcon, { className: "h-5 w-5 shrink-0 text-muted-foreground" })
1893
+ ]
1894
+ }
1895
+ ) }, tab.id);
1896
+ }) }) })
1897
+ ] })
1898
+ }
1899
+ );
1900
+ }
1901
+
1902
+ // src/use-scroll-fade.ts
1903
+ var import_react5 = require("react");
1904
+ var EPSILON = 2;
1905
+ function useScrollFade() {
1906
+ const [state, setState] = (0, import_react5.useState)({
1907
+ top: false,
1908
+ bottom: false
1909
+ });
1910
+ const nodeRef = (0, import_react5.useRef)(null);
1911
+ const cleanupRef = (0, import_react5.useRef)(null);
1912
+ const measure = (0, import_react5.useCallback)(() => {
1913
+ const el = nodeRef.current;
1914
+ if (!el) return;
1915
+ const overflowing = el.scrollHeight - el.clientHeight > EPSILON;
1916
+ const next = {
1917
+ top: overflowing && el.scrollTop > EPSILON,
1918
+ bottom: overflowing && el.scrollTop + el.clientHeight < el.scrollHeight - EPSILON
1919
+ };
1920
+ setState(
1921
+ (prev) => prev.top === next.top && prev.bottom === next.bottom ? prev : next
1922
+ );
1923
+ }, []);
1924
+ const ref = (0, import_react5.useCallback)(
1925
+ (node) => {
1926
+ cleanupRef.current?.();
1927
+ cleanupRef.current = null;
1928
+ nodeRef.current = node;
1929
+ if (!node) return;
1930
+ node.addEventListener("scroll", measure, { passive: true });
1931
+ const ro = new ResizeObserver(measure);
1932
+ ro.observe(node);
1933
+ const mo = new MutationObserver(measure);
1934
+ mo.observe(node, { childList: true, subtree: true });
1935
+ cleanupRef.current = () => {
1936
+ node.removeEventListener("scroll", measure);
1937
+ ro.disconnect();
1938
+ mo.disconnect();
1939
+ };
1940
+ requestAnimationFrame(measure);
1941
+ },
1942
+ [measure]
1943
+ );
1944
+ (0, import_react5.useEffect)(() => () => cleanupRef.current?.(), []);
1945
+ return {
1946
+ ref,
1947
+ state,
1948
+ fadeProps: {
1949
+ "data-fade-top": state.top ? "" : void 0,
1950
+ "data-fade-bottom": state.bottom ? "" : void 0,
1951
+ className: "matrx-scroll-fade"
1952
+ }
1953
+ };
1954
+ }
1955
+ //# sourceMappingURL=index.cjs.map