@labpane/ui 0.0.0-stage → 1.0.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 ADDED
@@ -0,0 +1,918 @@
1
+ import {
2
+ Alert,
3
+ AlertDescription,
4
+ AlertTitle,
5
+ Back,
6
+ Badge,
7
+ Button,
8
+ Checkbox,
9
+ CopyButton,
10
+ Field,
11
+ FieldError,
12
+ FieldLabel,
13
+ Input,
14
+ Page,
15
+ PageActions,
16
+ PageHeader,
17
+ Select,
18
+ SelectContent,
19
+ SelectItem,
20
+ SelectTrigger,
21
+ SelectValue,
22
+ Skeleton,
23
+ Spinner,
24
+ cn
25
+ } from "./chunk-3ZY2AVB4.js";
26
+
27
+ // dialog.tsx
28
+ import * as React from "react";
29
+ import * as AlertDialog from "@radix-ui/react-alert-dialog";
30
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
31
+ import { CircleAlertIcon, XIcon } from "lucide-react";
32
+ import { jsx, jsxs } from "react/jsx-runtime";
33
+ var Dialog = DialogPrimitive.Root;
34
+ var DialogTrigger = DialogPrimitive.Trigger;
35
+ var DialogClose = DialogPrimitive.Close;
36
+ var DialogContent = React.forwardRef(function DialogContent2({ className, children, showCloseButton = true, ...props }, ref) {
37
+ return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
38
+ /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "labui:fixed labui:inset-0 labui:z-50 labui:bg-overlay" }),
39
+ /* @__PURE__ */ jsxs(
40
+ DialogPrimitive.Content,
41
+ {
42
+ ref,
43
+ "data-slot": "dialog-content",
44
+ className: cn(
45
+ "labui:fixed labui:top-1/2 labui:left-1/2 labui:z-50 labui:-translate-x-1/2 labui:-translate-y-1/2",
46
+ "labui:grid labui:max-h-[calc(100dvh-2rem)] labui:w-full labui:max-w-[calc(100%-2rem)] labui:sm:max-w-lg labui:gap-6 labui:overflow-y-auto",
47
+ "labui:rounded-(--labui-radius-dialog) labui:border labui:bg-popover labui:p-6 labui:text-popover-foreground labui:shadow-sm labui:outline-none",
48
+ className
49
+ ),
50
+ ...props,
51
+ children: [
52
+ children,
53
+ showCloseButton && /* @__PURE__ */ jsxs(
54
+ DialogPrimitive.Close,
55
+ {
56
+ "data-slot": "dialog-close",
57
+ className: cn(
58
+ "labui:absolute labui:top-4 labui:right-4 labui:inline-flex labui:size-8 labui:items-center labui:justify-center labui:rounded-md",
59
+ "labui:text-muted-foreground labui:transition-colors labui:hover:bg-accent labui:hover:text-foreground",
60
+ "labui:focus-visible:ring-[3px] labui:focus-visible:ring-ring/50 labui:focus-visible:outline-none labui:disabled:pointer-events-none",
61
+ "labui:[&_svg]:pointer-events-none labui:[&_svg]:size-4 labui:[&_svg]:shrink-0"
62
+ ),
63
+ children: [
64
+ /* @__PURE__ */ jsx(XIcon, {}),
65
+ /* @__PURE__ */ jsx("span", { className: "labui:sr-only", children: "Close" })
66
+ ]
67
+ }
68
+ )
69
+ ]
70
+ }
71
+ )
72
+ ] });
73
+ });
74
+ var DialogHeader = React.forwardRef(function DialogHeader2({ className, ...props }, ref) {
75
+ return /* @__PURE__ */ jsx(
76
+ "div",
77
+ {
78
+ ref,
79
+ "data-slot": "dialog-header",
80
+ className: cn(
81
+ "labui:flex labui:min-w-0 labui:flex-col labui:gap-2 labui:text-left",
82
+ className
83
+ ),
84
+ ...props
85
+ }
86
+ );
87
+ });
88
+ var DialogFooter = React.forwardRef(function DialogFooter2({ className, ...props }, ref) {
89
+ return /* @__PURE__ */ jsx(
90
+ "div",
91
+ {
92
+ ref,
93
+ "data-slot": "dialog-footer",
94
+ className: cn(
95
+ "labui:flex labui:flex-wrap labui:items-center labui:justify-end labui:gap-2",
96
+ className
97
+ ),
98
+ ...props
99
+ }
100
+ );
101
+ });
102
+ var DialogTitle = React.forwardRef(function DialogTitle2({ className, ...props }, ref) {
103
+ return /* @__PURE__ */ jsx(
104
+ DialogPrimitive.Title,
105
+ {
106
+ ref,
107
+ "data-slot": "dialog-title",
108
+ className: cn(
109
+ "labui:pr-8 labui:text-lg labui:leading-7 labui:font-semibold labui:break-words",
110
+ className
111
+ ),
112
+ ...props
113
+ }
114
+ );
115
+ });
116
+ var DialogDescription = React.forwardRef(function DialogDescription2({ className, ...props }, ref) {
117
+ return /* @__PURE__ */ jsx(
118
+ DialogPrimitive.Description,
119
+ {
120
+ ref,
121
+ "data-slot": "dialog-description",
122
+ className: cn("labui:text-sm labui:text-muted-foreground", className),
123
+ ...props
124
+ }
125
+ );
126
+ });
127
+ function ConfirmDialog({
128
+ trigger,
129
+ title,
130
+ name,
131
+ confirmLabel,
132
+ typeToConfirm,
133
+ onConfirm
134
+ }) {
135
+ const [open, setOpen] = React.useState(false);
136
+ const [value, setValue] = React.useState("");
137
+ const [busy, setBusy] = React.useState(false);
138
+ const [error, setError] = React.useState();
139
+ function change(next) {
140
+ if (busy) return;
141
+ setOpen(next);
142
+ setValue("");
143
+ setError(void 0);
144
+ }
145
+ async function submit(event) {
146
+ event.preventDefault();
147
+ setBusy(true);
148
+ setError(void 0);
149
+ try {
150
+ await onConfirm();
151
+ setOpen(false);
152
+ } catch (err) {
153
+ setError(err.message);
154
+ } finally {
155
+ setBusy(false);
156
+ }
157
+ }
158
+ return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: change, children: [
159
+ /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: trigger }),
160
+ /* @__PURE__ */ jsx(
161
+ DialogContent,
162
+ {
163
+ role: "alertdialog",
164
+ "aria-describedby": void 0,
165
+ className: "labui:p-0",
166
+ showCloseButton: !busy,
167
+ onOpenAutoFocus: (event) => {
168
+ const input = event.target.querySelector("input");
169
+ if (!input) return;
170
+ event.preventDefault();
171
+ input.focus();
172
+ },
173
+ children: /* @__PURE__ */ jsxs(
174
+ "form",
175
+ {
176
+ className: "labui:flex labui:min-w-0 labui:flex-col",
177
+ onSubmit: submit,
178
+ children: [
179
+ /* @__PURE__ */ jsxs("div", { className: "labui:flex labui:min-w-0 labui:flex-col labui:gap-4 labui:p-6", children: [
180
+ /* @__PURE__ */ jsxs("div", { className: "labui:flex labui:items-center labui:gap-3", children: [
181
+ /* @__PURE__ */ jsx(
182
+ "span",
183
+ {
184
+ "aria-hidden": "true",
185
+ className: "labui:flex labui:size-9 labui:shrink-0 labui:items-center labui:justify-center labui:rounded-xl labui:bg-destructive-muted labui:text-destructive",
186
+ children: /* @__PURE__ */ jsx(CircleAlertIcon, { className: "labui:size-5" })
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsxs(DialogTitle, { children: [
190
+ title,
191
+ " ",
192
+ /* @__PURE__ */ jsxs("span", { className: "labui:inline-flex labui:items-center labui:gap-1 labui:rounded-md labui:border labui:bg-muted/50 labui:py-0.5 labui:pr-0.5 labui:pl-2 labui:align-middle labui:font-mono labui:text-base labui:break-all", children: [
193
+ name,
194
+ /* @__PURE__ */ jsx(CopyButton, { value: name, label: "Copy name" })
195
+ ] }),
196
+ "?"
197
+ ] })
198
+ ] }),
199
+ typeToConfirm && /* @__PURE__ */ jsx(
200
+ Input,
201
+ {
202
+ "aria-label": "Name",
203
+ autoComplete: "off",
204
+ spellCheck: "false",
205
+ placeholder: name,
206
+ value,
207
+ disabled: busy,
208
+ onChange: (event) => setValue(event.target.value)
209
+ }
210
+ ),
211
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "labui:text-sm labui:text-destructive", children: error })
212
+ ] }),
213
+ /* @__PURE__ */ jsxs(DialogFooter, { className: "labui:justify-between labui:border-t labui:bg-muted/40 labui:px-6 labui:py-4", children: [
214
+ /* @__PURE__ */ jsx(
215
+ Button,
216
+ {
217
+ type: "button",
218
+ variant: "ghost",
219
+ disabled: busy,
220
+ onClick: () => change(false),
221
+ children: "Cancel"
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsxs(
225
+ Button,
226
+ {
227
+ type: "submit",
228
+ variant: "destructive",
229
+ disabled: busy || typeToConfirm && value !== name,
230
+ children: [
231
+ busy && /* @__PURE__ */ jsx(Spinner, {}),
232
+ confirmLabel
233
+ ]
234
+ }
235
+ )
236
+ ] })
237
+ ]
238
+ }
239
+ )
240
+ }
241
+ )
242
+ ] });
243
+ }
244
+ var dialogAction = "labui:inline-flex labui:shrink-0 labui:items-center labui:justify-center labui:rounded-md labui:text-sm labui:font-medium labui:outline-none labui:transition-colors labui:hover:bg-accent labui:focus-visible:ring-2 labui:focus-visible:ring-ring labui:px-4 labui:py-2";
245
+ function DiscardDialog({
246
+ label,
247
+ onCancel,
248
+ onConfirm,
249
+ onCloseAutoFocus
250
+ }) {
251
+ return /* @__PURE__ */ jsx(
252
+ AlertDialog.Root,
253
+ {
254
+ open: label !== void 0,
255
+ onOpenChange: (open) => !open && onCancel(),
256
+ children: /* @__PURE__ */ jsxs(AlertDialog.Portal, { children: [
257
+ /* @__PURE__ */ jsx(AlertDialog.Overlay, { className: "labui:fixed labui:inset-0 labui:z-50 labui:font-sans labui:text-sm labui:leading-normal labui:bg-overlay" }),
258
+ /* @__PURE__ */ jsxs(
259
+ AlertDialog.Content,
260
+ {
261
+ className: cn(
262
+ "labui:fixed labui:top-1/2 labui:left-1/2 labui:z-50 labui:-translate-x-1/2 labui:-translate-y-1/2",
263
+ "labui:w-[calc(100%-2rem)] labui:max-w-lg labui:rounded-[1.25rem] labui:border labui:border-border labui:bg-popover labui:p-6",
264
+ "labui:font-sans labui:text-sm labui:leading-normal labui:text-popover-foreground labui:shadow-sm labui:outline-none"
265
+ ),
266
+ onCloseAutoFocus,
267
+ children: [
268
+ /* @__PURE__ */ jsxs(AlertDialog.Title, { className: "labui:m-0 labui:text-lg labui:font-semibold", children: [
269
+ "Discard changes in ",
270
+ label,
271
+ "?"
272
+ ] }),
273
+ /* @__PURE__ */ jsx(AlertDialog.Description, { className: "labui:mt-2 labui:text-muted-foreground", children: "Closing the tab discards its unsaved changes." }),
274
+ /* @__PURE__ */ jsxs("div", { className: "labui:mt-6 labui:flex labui:flex-wrap labui:justify-end labui:gap-2", children: [
275
+ /* @__PURE__ */ jsx(
276
+ AlertDialog.Cancel,
277
+ {
278
+ className: dialogAction + " labui:border labui:border-border",
279
+ children: "Keep tab"
280
+ }
281
+ ),
282
+ /* @__PURE__ */ jsx(
283
+ AlertDialog.Action,
284
+ {
285
+ className: dialogAction + " labui:bg-destructive-muted labui:text-destructive",
286
+ onClick: onConfirm,
287
+ children: "Discard and close"
288
+ }
289
+ )
290
+ ] })
291
+ ]
292
+ }
293
+ )
294
+ ] })
295
+ }
296
+ );
297
+ }
298
+
299
+ // menu.tsx
300
+ import "react";
301
+ import * as ContextMenu from "@radix-ui/react-context-menu";
302
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
303
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
304
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
305
+ var panel = "labui:z-50 labui:rounded-lg labui:border labui:border-border labui:bg-popover labui:p-1 labui:font-sans labui:text-sm labui:leading-normal labui:text-popover-foreground labui:shadow-sm";
306
+ var menuItem = "labui:flex labui:min-h-9 labui:cursor-default labui:items-center labui:gap-3 labui:rounded-md labui:px-3 labui:text-sm labui:outline-none labui:data-highlighted:bg-accent labui:data-disabled:opacity-50 labui:[@media(pointer:coarse)]:min-h-11";
307
+ var optionPanel = panel + " labui:min-w-40 labui:max-h-[var(--radix-dropdown-menu-content-available-height)] labui:overflow-auto";
308
+ function MenuContent({
309
+ children,
310
+ className = "labui:w-56"
311
+ }) {
312
+ return /* @__PURE__ */ jsx2(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx2(
313
+ DropdownMenu.Content,
314
+ {
315
+ align: "start",
316
+ sideOffset: 4,
317
+ collisionPadding: 8,
318
+ className: "labui:z-50 labui:max-h-[var(--radix-dropdown-menu-content-available-height)] labui:overflow-auto labui:rounded-lg labui:border labui:bg-popover labui:p-1 labui:text-popover-foreground labui:shadow-sm " + className,
319
+ children
320
+ }
321
+ ) });
322
+ }
323
+ function contextItem(action, index) {
324
+ if (!action)
325
+ return /* @__PURE__ */ jsx2(
326
+ ContextMenu.Separator,
327
+ {
328
+ className: "labui:my-1 labui:border-t labui:border-border"
329
+ },
330
+ index
331
+ );
332
+ if ("items" in action)
333
+ return /* @__PURE__ */ jsxs2(ContextMenu.Sub, { children: [
334
+ /* @__PURE__ */ jsxs2(
335
+ ContextMenu.SubTrigger,
336
+ {
337
+ className: menuItem + " labui:justify-between labui:data-[state=open]:bg-accent",
338
+ children: [
339
+ action.label,
340
+ /* @__PURE__ */ jsx2(ChevronRightIcon, { className: "labui:size-4" })
341
+ ]
342
+ }
343
+ ),
344
+ /* @__PURE__ */ jsx2(ContextMenu.Portal, { children: /* @__PURE__ */ jsx2(
345
+ ContextMenu.SubContent,
346
+ {
347
+ className: panel + " labui:min-w-40",
348
+ sideOffset: 4,
349
+ collisionPadding: 8,
350
+ children: action.items.map(contextItem)
351
+ }
352
+ ) })
353
+ ] }, action.label);
354
+ if (action.checked !== void 0)
355
+ return /* @__PURE__ */ jsxs2(
356
+ ContextMenu.CheckboxItem,
357
+ {
358
+ className: menuItem,
359
+ checked: action.checked,
360
+ disabled: action.disabled,
361
+ onSelect: action.onSelect,
362
+ children: [
363
+ /* @__PURE__ */ jsx2("span", { className: "labui:grid labui:size-4 labui:place-items-center", children: /* @__PURE__ */ jsx2(ContextMenu.ItemIndicator, { children: /* @__PURE__ */ jsx2(CheckIcon, { className: "labui:size-4" }) }) }),
364
+ action.label
365
+ ]
366
+ },
367
+ action.label
368
+ );
369
+ return /* @__PURE__ */ jsx2(
370
+ ContextMenu.Item,
371
+ {
372
+ className: menuItem,
373
+ disabled: action.disabled,
374
+ onSelect: action.onSelect,
375
+ children: action.label
376
+ },
377
+ action.label
378
+ );
379
+ }
380
+ function ActionMenu({
381
+ children,
382
+ actions,
383
+ onCloseAutoFocus
384
+ }) {
385
+ return /* @__PURE__ */ jsxs2(ContextMenu.Root, { modal: false, children: [
386
+ /* @__PURE__ */ jsx2(ContextMenu.Trigger, { asChild: true, children }),
387
+ /* @__PURE__ */ jsx2(ContextMenu.Portal, { children: /* @__PURE__ */ jsx2(
388
+ ContextMenu.Content,
389
+ {
390
+ className: panel + " labui:min-w-44",
391
+ onCloseAutoFocus,
392
+ children: actions.map(contextItem)
393
+ }
394
+ ) })
395
+ ] });
396
+ }
397
+ function OptionMenu({
398
+ trigger,
399
+ options,
400
+ onSelect,
401
+ open,
402
+ onOpenChange,
403
+ onCloseAutoFocus
404
+ }) {
405
+ const groups = [
406
+ ...new Set(
407
+ options.flatMap((option) => option.group ? [option.group] : [])
408
+ )
409
+ ];
410
+ const item = (option) => /* @__PURE__ */ jsxs2(
411
+ DropdownMenu.Item,
412
+ {
413
+ className: menuItem,
414
+ onSelect: () => onSelect(option.id),
415
+ children: [
416
+ option.icon,
417
+ option.label
418
+ ]
419
+ },
420
+ option.id
421
+ );
422
+ return /* @__PURE__ */ jsxs2(DropdownMenu.Root, { modal: false, open, onOpenChange, children: [
423
+ /* @__PURE__ */ jsx2(DropdownMenu.Trigger, { asChild: true, children: trigger }),
424
+ /* @__PURE__ */ jsx2(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs2(
425
+ DropdownMenu.Content,
426
+ {
427
+ align: "start",
428
+ sideOffset: 4,
429
+ collisionPadding: 8,
430
+ className: optionPanel,
431
+ onCloseAutoFocus,
432
+ children: [
433
+ options.filter((option) => !option.group).map(item),
434
+ groups.map((group) => /* @__PURE__ */ jsxs2(DropdownMenu.Sub, { children: [
435
+ /* @__PURE__ */ jsxs2(
436
+ DropdownMenu.SubTrigger,
437
+ {
438
+ className: menuItem + " labui:justify-between labui:data-[state=open]:bg-accent",
439
+ children: [
440
+ group,
441
+ /* @__PURE__ */ jsx2(ChevronRightIcon, { className: "labui:size-4" })
442
+ ]
443
+ }
444
+ ),
445
+ /* @__PURE__ */ jsx2(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx2(
446
+ DropdownMenu.SubContent,
447
+ {
448
+ className: optionPanel,
449
+ sideOffset: 4,
450
+ collisionPadding: 8,
451
+ children: options.filter((option) => option.group === group).map(item)
452
+ }
453
+ ) })
454
+ ] }, group))
455
+ ]
456
+ }
457
+ ) })
458
+ ] });
459
+ }
460
+
461
+ // app-menu.tsx
462
+ import * as Popover from "@radix-ui/react-popover";
463
+ import { useRef, useState as useState2 } from "react";
464
+ import { MaximizeIcon, MinimizeIcon, MoonIcon, SunIcon } from "lucide-react";
465
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
466
+ var round = "labui:rounded-full labui:border labui:border-border";
467
+ function AppMenu({
468
+ name,
469
+ logo,
470
+ version,
471
+ dark = false,
472
+ onThemeChange,
473
+ size = 100,
474
+ align = "start",
475
+ onSizeChange,
476
+ onSizeReset,
477
+ fullscreen = false,
478
+ onFullscreenChange
479
+ }) {
480
+ const trigger = useRef(null);
481
+ const sizePanel = useRef(null);
482
+ const [anchor, setAnchor] = useState2();
483
+ const level = Math.max(0, Math.min(100, size));
484
+ const ThemeIcon = dark ? SunIcon : MoonIcon;
485
+ const theme = dark ? "dark " : "";
486
+ return /* @__PURE__ */ jsxs3(
487
+ Popover.Root,
488
+ {
489
+ onOpenChange: (open) => {
490
+ if (open) setAnchor(trigger.current?.offsetHeight);
491
+ },
492
+ children: [
493
+ /* @__PURE__ */ jsx3(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
494
+ "button",
495
+ {
496
+ ref: trigger,
497
+ type: "button",
498
+ "aria-label": name,
499
+ title: `${name} menu`,
500
+ className: "labui:group labui:relative labui:grid labui:size-[var(--lab-tab-height,2.75rem)] labui:shrink-0 labui:cursor-pointer labui:place-items-center labui:rounded-full labui:outline-none labui:focus-visible:outline-2 labui:focus-visible:outline-ring",
501
+ children: [
502
+ /* @__PURE__ */ jsx3("span", { className: "labui:grid labui:size-[var(--lab-logo-size,1.5rem)] labui:transition-[filter,translate] labui:duration-150 labui:motion-safe:group-hover:-translate-y-0.5 labui:group-hover:drop-shadow-[0_3px_2px_#00000035] labui:group-active:translate-y-0 labui:dark:group-hover:drop-shadow-[0_3px_3px_#00000090]", children: logo }),
503
+ /* @__PURE__ */ jsx3(Popover.Anchor, { asChild: true, children: /* @__PURE__ */ jsx3(
504
+ "span",
505
+ {
506
+ className: "labui:absolute labui:inset-x-0 labui:top-0",
507
+ style: { height: anchor ?? "100%" }
508
+ }
509
+ ) })
510
+ ]
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ jsx3(Popover.Portal, { children: /* @__PURE__ */ jsxs3(
514
+ Popover.Content,
515
+ {
516
+ align,
517
+ sideOffset: 4,
518
+ collisionPadding: 8,
519
+ "aria-label": `${name} menu`,
520
+ onInteractOutside: (event) => {
521
+ if (sizePanel.current?.contains(event.target))
522
+ event.preventDefault();
523
+ },
524
+ className: theme + (align === "start" ? "labui:ml-1 labui:sm:-ml-1 " : "labui:mr-1 labui:sm:-mr-1 ") + "labui:z-50 labui:flex labui:w-max labui:max-h-[var(--radix-popover-content-available-height)] labui:flex-col labui:items-center labui:gap-3 labui:overflow-auto labui:rounded-lg labui:border labui:bg-popover labui:p-4 labui:text-center labui:text-popover-foreground labui:shadow-sm",
525
+ children: [
526
+ /* @__PURE__ */ jsxs3("div", { className: "labui:flex labui:items-center labui:gap-2 labui:text-2xl", children: [
527
+ /* @__PURE__ */ jsx3("span", { className: "labui:grid labui:size-6 labui:shrink-0", children: logo }),
528
+ /* @__PURE__ */ jsx3("span", { className: "labui:font-display labui:font-bold labui:tracking-tight", children: name })
529
+ ] }),
530
+ version != null && /* @__PURE__ */ jsx3("div", { className: "labui:text-xs labui:text-muted-foreground", children: /* @__PURE__ */ jsx3("span", { className: "labui:font-mono", children: version }) }),
531
+ /* @__PURE__ */ jsxs3("div", { className: "labui:flex labui:items-center labui:justify-center labui:gap-2", children: [
532
+ onThemeChange && /* @__PURE__ */ jsx3(
533
+ Button,
534
+ {
535
+ variant: "ghost",
536
+ size: "icon-sm",
537
+ className: round,
538
+ "aria-label": "Toggle theme",
539
+ "aria-pressed": dark,
540
+ onClick: () => onThemeChange(!dark),
541
+ title: "Toggle theme",
542
+ children: /* @__PURE__ */ jsx3(ThemeIcon, { className: "labui:size-4" })
543
+ }
544
+ ),
545
+ onSizeChange && /* @__PURE__ */ jsxs3(Popover.Root, { children: [
546
+ /* @__PURE__ */ jsx3(
547
+ ActionMenu,
548
+ {
549
+ actions: onSizeReset ? [{ label: "Reset", onSelect: onSizeReset }] : [],
550
+ children: /* @__PURE__ */ jsx3(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx3(
551
+ Button,
552
+ {
553
+ variant: "ghost",
554
+ size: "icon-sm",
555
+ className: round,
556
+ "aria-label": "Workspace size",
557
+ title: "Workspace size",
558
+ children: /* @__PURE__ */ jsx3(
559
+ "svg",
560
+ {
561
+ "aria-hidden": "true",
562
+ viewBox: "0 0 24 24",
563
+ className: "labui:size-4 labui:[&_rect]:transition-[fill-opacity]",
564
+ children: [0, 1, 2].map((row) => /* @__PURE__ */ jsx3(
565
+ "rect",
566
+ {
567
+ x: "4",
568
+ y: 3 + row * 7,
569
+ width: "16",
570
+ height: "4",
571
+ rx: "1",
572
+ stroke: "currentColor",
573
+ strokeWidth: "1.5",
574
+ fill: "currentColor",
575
+ fillOpacity: Math.max(
576
+ 0,
577
+ Math.min(1, level / 100 * 3 - (2 - row))
578
+ )
579
+ },
580
+ row
581
+ ))
582
+ }
583
+ )
584
+ }
585
+ ) })
586
+ }
587
+ ),
588
+ /* @__PURE__ */ jsx3(Popover.Portal, { children: /* @__PURE__ */ jsxs3(
589
+ Popover.Content,
590
+ {
591
+ ref: sizePanel,
592
+ side: "bottom",
593
+ align: "center",
594
+ sideOffset: 8,
595
+ collisionPadding: 8,
596
+ "aria-label": "Workspace size",
597
+ className: theme + "labui:z-[60] labui:origin-(--radix-popover-content-transform-origin) labui:animate-pop labui:rounded-xl labui:border labui:bg-popover labui:p-2 labui:shadow-md labui:data-[state=closed]:animate-[labui-pop_120ms_ease-in_reverse]",
598
+ children: [
599
+ /* @__PURE__ */ jsxs3("div", { className: "labui:relative labui:h-28 labui:w-7 labui:overflow-hidden labui:rounded-full labui:border labui:bg-secondary labui:shadow-inner labui:has-focus-visible:outline-2 labui:has-focus-visible:outline-offset-2 labui:has-focus-visible:outline-ring", children: [
600
+ /* @__PURE__ */ jsx3(
601
+ "div",
602
+ {
603
+ className: "labui:pointer-events-none labui:absolute labui:inset-x-0 labui:bottom-0 labui:bg-white labui:shadow-[0_-1px_4px_#00000014] labui:[transition:height_100ms_ease-out] labui:forced-colors:hidden",
604
+ style: { height: `${level}%` }
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsx3(
608
+ "input",
609
+ {
610
+ type: "range",
611
+ min: 0,
612
+ max: 100,
613
+ step: "any",
614
+ value: level,
615
+ "aria-label": "Workspace size",
616
+ "aria-orientation": "vertical",
617
+ "aria-valuetext": `${Math.round(level)}%`,
618
+ className: "labui:range-overlay",
619
+ onChange: (event) => onSizeChange(event.currentTarget.valueAsNumber)
620
+ }
621
+ )
622
+ ] }),
623
+ /* @__PURE__ */ jsx3(Popover.Arrow, { asChild: true, width: 16, height: 8, children: /* @__PURE__ */ jsx3(
624
+ "svg",
625
+ {
626
+ viewBox: "0 0 16 8",
627
+ className: "labui:fill-popover labui:stroke-border",
628
+ children: /* @__PURE__ */ jsx3("path", { d: "M0 0 C3 0 5 6 7 7 Q8 8 9 7 C11 6 13 0 16 0" })
629
+ }
630
+ ) })
631
+ ]
632
+ }
633
+ ) })
634
+ ] }),
635
+ onFullscreenChange && /* @__PURE__ */ jsx3(
636
+ Button,
637
+ {
638
+ variant: "ghost",
639
+ size: "icon-sm",
640
+ className: round,
641
+ "aria-label": "Full screen",
642
+ "aria-pressed": fullscreen,
643
+ title: fullscreen ? "Exit full screen" : "Full screen",
644
+ onClick: () => onFullscreenChange(!fullscreen),
645
+ children: fullscreen ? /* @__PURE__ */ jsx3(MinimizeIcon, { className: "labui:size-4" }) : /* @__PURE__ */ jsx3(MaximizeIcon, { className: "labui:size-4" })
646
+ }
647
+ )
648
+ ] })
649
+ ]
650
+ }
651
+ ) })
652
+ ]
653
+ }
654
+ );
655
+ }
656
+
657
+ // form-fields.tsx
658
+ import { useId } from "react";
659
+ import { PlusIcon } from "lucide-react";
660
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
661
+ function TextField({ label, value, onChange, ...props }) {
662
+ const id = useId();
663
+ return /* @__PURE__ */ jsxs4(Field, { "data-invalid": props["aria-invalid"] || void 0, children: [
664
+ /* @__PURE__ */ jsx4(FieldLabel, { htmlFor: id, children: label }),
665
+ /* @__PURE__ */ jsx4(
666
+ Input,
667
+ {
668
+ id,
669
+ autoComplete: "off",
670
+ value,
671
+ onChange: (e) => onChange(e.target.value),
672
+ ...props
673
+ }
674
+ )
675
+ ] });
676
+ }
677
+ function SelectField({
678
+ label,
679
+ value,
680
+ onChange,
681
+ options,
682
+ children
683
+ }) {
684
+ const id = useId();
685
+ return /* @__PURE__ */ jsxs4(Field, { children: [
686
+ /* @__PURE__ */ jsx4(FieldLabel, { htmlFor: id, children: label }),
687
+ /* @__PURE__ */ jsxs4("div", { className: "labui:flex labui:items-center labui:gap-2", children: [
688
+ /* @__PURE__ */ jsxs4(Select, { value, onValueChange: onChange, children: [
689
+ /* @__PURE__ */ jsx4(SelectTrigger, { id, className: "labui:flex-1", children: /* @__PURE__ */ jsx4(SelectValue, {}) }),
690
+ /* @__PURE__ */ jsx4(SelectContent, { children: options.map((o) => /* @__PURE__ */ jsx4(SelectItem, { value: o.id, disabled: o.disabled, children: o.name }, o.id)) })
691
+ ] }),
692
+ children
693
+ ] })
694
+ ] });
695
+ }
696
+ function AddButton({
697
+ children,
698
+ onClick
699
+ }) {
700
+ return /* @__PURE__ */ jsxs4(Button, { type: "button", variant: "secondary", onClick, children: [
701
+ /* @__PURE__ */ jsx4(PlusIcon, {}),
702
+ children
703
+ ] });
704
+ }
705
+
706
+ // table.tsx
707
+ import * as React3 from "react";
708
+ import "react";
709
+ import { ArrowDownIcon, ArrowUpDownIcon, ArrowUpIcon } from "lucide-react";
710
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
711
+ var show = (value) => value == null ? "" : String(value);
712
+ var cellClass = "labui:px-3 labui:py-(--labui-row-py) labui:align-middle";
713
+ function Table({
714
+ label,
715
+ columns,
716
+ rows,
717
+ rowKey,
718
+ loading,
719
+ empty = "No rows to display.",
720
+ defaultSort = null,
721
+ onRowActivate,
722
+ rowLabel
723
+ }) {
724
+ const [sort, setSort] = React3.useState(defaultSort);
725
+ const sortBy = columns.find((c) => c.id === sort?.column)?.sortValue;
726
+ const sorted = sort && sortBy ? [...rows].sort((x, y) => {
727
+ const a = sortBy(x);
728
+ const b = sortBy(y);
729
+ if (a == null || b == null)
730
+ return Number(a == null) - Number(b == null);
731
+ const order = typeof a === "number" && typeof b === "number" ? a - b : String(a).localeCompare(String(b), void 0, {
732
+ numeric: true
733
+ });
734
+ return sort.direction === "asc" ? order : -order;
735
+ }) : rows;
736
+ function toggle(column2) {
737
+ setSort(
738
+ sort?.column === column2.id ? {
739
+ column: column2.id,
740
+ direction: sort.direction === "asc" ? "desc" : "asc"
741
+ } : { column: column2.id, direction: column2.numeric ? "desc" : "asc" }
742
+ );
743
+ }
744
+ return /* @__PURE__ */ jsx5("div", { className: "labui:min-w-0 labui:overflow-auto labui:rounded-lg labui:border", children: /* @__PURE__ */ jsxs5(
745
+ "table",
746
+ {
747
+ "aria-label": label,
748
+ "aria-busy": loading || void 0,
749
+ className: "labui:w-full labui:text-xs labui:tabular-nums",
750
+ children: [
751
+ /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsx5("tr", { children: columns.map((column2) => {
752
+ const direction = sort?.column === column2.id ? sort.direction : null;
753
+ const Marker = direction === "asc" ? ArrowUpIcon : direction === "desc" ? ArrowDownIcon : ArrowUpDownIcon;
754
+ return /* @__PURE__ */ jsx5(
755
+ "th",
756
+ {
757
+ scope: "col",
758
+ "aria-sort": direction ? direction === "asc" ? "ascending" : "descending" : void 0,
759
+ className: cn(
760
+ "labui:sticky labui:top-0 labui:z-10 labui:h-8 labui:bg-card labui:px-3 labui:text-left labui:font-medium labui:whitespace-nowrap labui:text-muted-foreground labui:shadow-[inset_0_-1px_var(--labui-border)]",
761
+ column2.numeric && "labui:text-right"
762
+ ),
763
+ children: /* @__PURE__ */ jsxs5(
764
+ Button,
765
+ {
766
+ type: "button",
767
+ variant: "ghost",
768
+ size: "sm",
769
+ className: "labui:-mx-2 labui:h-7 labui:gap-1 labui:px-2 labui:text-xs labui:font-medium labui:hover:bg-transparent",
770
+ disabled: loading,
771
+ onClick: () => toggle(column2),
772
+ children: [
773
+ column2.header,
774
+ column2.headerDetail && /* @__PURE__ */ jsx5("span", { className: "labui:text-[10px] labui:font-normal", children: column2.headerDetail }),
775
+ /* @__PURE__ */ jsx5(
776
+ Marker,
777
+ {
778
+ "aria-hidden": "true",
779
+ className: cn(
780
+ "labui:size-3.5",
781
+ !direction && "labui:opacity-40"
782
+ )
783
+ }
784
+ )
785
+ ]
786
+ }
787
+ )
788
+ },
789
+ column2.id
790
+ );
791
+ }) }) }),
792
+ /* @__PURE__ */ jsx5("tbody", { className: "labui:[&_tr:last-child]:border-0", children: loading ? Array.from({ length: 6 }, (_, index) => /* @__PURE__ */ jsx5("tr", { "aria-hidden": "true", className: "labui:border-b", children: columns.map((column2, at) => /* @__PURE__ */ jsx5("td", { className: cellClass, children: /* @__PURE__ */ jsx5(
793
+ Skeleton,
794
+ {
795
+ className: cn(
796
+ "labui:h-3",
797
+ at % 2 ? "labui:w-1/2" : "labui:w-3/4"
798
+ )
799
+ }
800
+ ) }, column2.id)) }, index)) : sorted.length === 0 ? /* @__PURE__ */ jsx5("tr", { children: /* @__PURE__ */ jsx5(
801
+ "td",
802
+ {
803
+ colSpan: columns.length,
804
+ className: "labui:p-4 labui:text-muted-foreground",
805
+ children: empty
806
+ }
807
+ ) }) : sorted.map((row, index) => /* @__PURE__ */ jsx5(
808
+ "tr",
809
+ {
810
+ className: cn(
811
+ "labui:border-b labui:transition-colors labui:hover:bg-muted/50",
812
+ onRowActivate && "labui:cursor-pointer"
813
+ ),
814
+ onClick: (event) => {
815
+ if (!event.target.closest("a, button"))
816
+ onRowActivate?.(row);
817
+ },
818
+ children: columns.map((column2, at) => {
819
+ const Cell = column2.rowHeader ? "th" : "td";
820
+ return /* @__PURE__ */ jsx5(
821
+ Cell,
822
+ {
823
+ scope: column2.rowHeader ? "row" : void 0,
824
+ className: cn(
825
+ cellClass,
826
+ column2.rowHeader && "labui:text-left labui:font-medium",
827
+ column2.numeric && "labui:text-right"
828
+ ),
829
+ children: at === 0 && onRowActivate ? /* @__PURE__ */ jsx5(
830
+ "button",
831
+ {
832
+ type: "button",
833
+ "aria-label": rowLabel?.(row),
834
+ className: "labui:-m-1 labui:min-h-6 labui:rounded labui:p-1 labui:text-left labui:whitespace-nowrap labui:focus-visible:outline-2 labui:focus-visible:outline-ring",
835
+ onClick: () => onRowActivate(row),
836
+ children: column2.cell(row)
837
+ }
838
+ ) : column2.cell(row)
839
+ },
840
+ column2.id
841
+ );
842
+ })
843
+ },
844
+ rowKey(row, index)
845
+ )) })
846
+ ]
847
+ }
848
+ ) });
849
+ }
850
+ function column(id, header, value, cell = (row) => show(value(row))) {
851
+ return { id, header, sortValue: value, cell };
852
+ }
853
+ var mono = (id, header, value) => column(
854
+ id,
855
+ header,
856
+ (row) => show(value(row)),
857
+ (row) => /* @__PURE__ */ jsx5("span", { className: "labui:font-mono", children: show(value(row)) })
858
+ );
859
+ var num = (id, header, value, digits = 0, headerDetail) => ({
860
+ ...column(
861
+ id,
862
+ header,
863
+ value,
864
+ (row) => value(row).toLocaleString("en-US", {
865
+ minimumFractionDigits: digits,
866
+ maximumFractionDigits: digits
867
+ })
868
+ ),
869
+ numeric: true,
870
+ headerDetail
871
+ });
872
+ export {
873
+ ActionMenu,
874
+ AddButton,
875
+ Alert,
876
+ AlertDescription,
877
+ AlertTitle,
878
+ AppMenu,
879
+ Back,
880
+ Badge,
881
+ Button,
882
+ Checkbox,
883
+ ConfirmDialog,
884
+ CopyButton,
885
+ Dialog,
886
+ DialogClose,
887
+ DialogContent,
888
+ DialogDescription,
889
+ DialogFooter,
890
+ DialogHeader,
891
+ DialogTitle,
892
+ DialogTrigger,
893
+ DiscardDialog,
894
+ Field,
895
+ FieldError,
896
+ FieldLabel,
897
+ Input,
898
+ MenuContent,
899
+ OptionMenu,
900
+ Page,
901
+ PageActions,
902
+ PageHeader,
903
+ Select,
904
+ SelectContent,
905
+ SelectField,
906
+ SelectItem,
907
+ SelectTrigger,
908
+ SelectValue,
909
+ Skeleton,
910
+ Spinner,
911
+ Table,
912
+ TextField,
913
+ cn,
914
+ column,
915
+ mono,
916
+ num
917
+ };
918
+ //# sourceMappingURL=index.js.map