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