@litelens/design-system 1.0.3

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.
@@ -0,0 +1,822 @@
1
+ import { Tooltip, TooltipTrigger, TooltipContent, Button, DropdownMenuItem, TooltipProvider, Sheet, SheetContent, SheetHeader, ScrollArea, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, TableRow, TableCell, toast, Badge } from './chunk-NPDXDIXD.js';
2
+ import { CheckIcon, CopyIcon, Loader2Icon, MinusIcon, PlusIcon, Trash2Icon, PencilIcon, RefreshCwIcon, ScalingIcon, XCircleIcon, CheckCircle2Icon, SearchIcon, Input, ChevronDownIcon, CircleCheckIcon, CircleXIcon } from './chunk-7YPL4ZPM.js';
3
+ import { cn } from './chunk-QUNCRUSO.js';
4
+ import { useRef, useState, useLayoutEffect, Component, useMemo, useEffect } from 'react';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+ import { createPortal } from 'react-dom';
7
+ import ReactMarkdown from 'react-markdown';
8
+ import remarkGfm from 'remark-gfm';
9
+
10
+ var AnnotationBadge = ({ label }) => {
11
+ const spanRef = useRef(null);
12
+ const [isOverflowing, setIsOverflowing] = useState(false);
13
+ useLayoutEffect(() => {
14
+ const el = spanRef.current;
15
+ if (el) setIsOverflowing(el.scrollWidth > el.clientWidth);
16
+ }, [label]);
17
+ const badge = /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "max-w-xs cursor-default font-mono text-xs", children: /* @__PURE__ */ jsx("span", { ref: spanRef, className: "block truncate", children: label }) });
18
+ if (!isOverflowing) return badge;
19
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
20
+ /* @__PURE__ */ jsx(TooltipTrigger, { className: "text-left", children: badge }),
21
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: label }) })
22
+ ] });
23
+ };
24
+ var Divider = ({ className }) => {
25
+ return /* @__PURE__ */ jsx("hr", { className: cn("border-border w-full", className) });
26
+ };
27
+ var ResourceLink = ({
28
+ children,
29
+ className,
30
+ truncate,
31
+ truncateTextClassName,
32
+ onClick
33
+ }) => {
34
+ const ref = useRef(null);
35
+ const [isOverflowing, setIsOverflowing] = useState(false);
36
+ useLayoutEffect(() => {
37
+ if (!truncate) return;
38
+ const el = ref.current;
39
+ if (el) setIsOverflowing(el.scrollWidth > el.clientWidth);
40
+ }, [truncate, children]);
41
+ const inner = onClick ? /* @__PURE__ */ jsx(
42
+ Button,
43
+ {
44
+ variant: "link",
45
+ type: "button",
46
+ size: "xs",
47
+ className: cn("text-info h-auto w-fit p-0", className),
48
+ onClick,
49
+ children: truncate ? /* @__PURE__ */ jsx(
50
+ "span",
51
+ {
52
+ ref,
53
+ className: cn(
54
+ "max-w-65 inline-block truncate group-hover/button:[box-shadow:0_1px_0_0_currentColor]",
55
+ truncateTextClassName
56
+ ),
57
+ children
58
+ }
59
+ ) : children
60
+ }
61
+ ) : /* @__PURE__ */ jsx("span", { className: cn("text-info cursor-default", className), children: truncate ? /* @__PURE__ */ jsx("span", { ref, className: cn("max-w-65 inline-block truncate", truncateTextClassName), children }) : children });
62
+ if (!truncate || !isOverflowing) return inner;
63
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
64
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: inner }),
65
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children }) })
66
+ ] });
67
+ };
68
+ var RADIUS = 36;
69
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
70
+ var colorClass = {
71
+ green: "bg-success",
72
+ amber: "bg-warning",
73
+ red: "bg-destructive"
74
+ };
75
+ var DonutChart = ({
76
+ label,
77
+ total,
78
+ running,
79
+ pending = 0,
80
+ failed = 0,
81
+ items,
82
+ onNavigate
83
+ }) => {
84
+ const runRatio = total === 0 ? 0 : running / total;
85
+ const pendingRatio = total === 0 ? 0 : pending / total;
86
+ const failRatio = total === 0 ? 0 : failed / total;
87
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1", children: [
88
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: /* @__PURE__ */ jsxs(ResourceLink, { onClick: onNavigate, children: [
89
+ label,
90
+ " (",
91
+ total,
92
+ ")"
93
+ ] }) }),
94
+ /* @__PURE__ */ jsxs("svg", { width: "88", height: "88", viewBox: "0 0 88 88", children: [
95
+ /* @__PURE__ */ jsx("circle", { cx: "44", cy: "44", r: RADIUS, fill: "none", strokeWidth: "8", className: "stroke-muted" }),
96
+ /* @__PURE__ */ jsx(
97
+ "circle",
98
+ {
99
+ cx: "44",
100
+ cy: "44",
101
+ r: RADIUS,
102
+ fill: "none",
103
+ strokeWidth: "8",
104
+ strokeDasharray: `${runRatio * CIRCUMFERENCE} ${CIRCUMFERENCE}`,
105
+ strokeLinecap: "round",
106
+ className: "stroke-success",
107
+ transform: "rotate(-90 44 44)"
108
+ }
109
+ ),
110
+ pending > 0 && /* @__PURE__ */ jsx(
111
+ "circle",
112
+ {
113
+ cx: "44",
114
+ cy: "44",
115
+ r: RADIUS,
116
+ fill: "none",
117
+ strokeWidth: "8",
118
+ strokeDasharray: `${pendingRatio * CIRCUMFERENCE} ${CIRCUMFERENCE}`,
119
+ strokeLinecap: "round",
120
+ className: "stroke-warning",
121
+ transform: `rotate(${ -90 + runRatio * 360} 44 44)`
122
+ }
123
+ ),
124
+ failed > 0 && /* @__PURE__ */ jsx(
125
+ "circle",
126
+ {
127
+ cx: "44",
128
+ cy: "44",
129
+ r: RADIUS,
130
+ fill: "none",
131
+ strokeWidth: "8",
132
+ strokeDasharray: `${failRatio * CIRCUMFERENCE} ${CIRCUMFERENCE}`,
133
+ strokeLinecap: "round",
134
+ className: "stroke-destructive",
135
+ transform: `rotate(${ -90 + (runRatio + pendingRatio) * 360} 44 44)`
136
+ }
137
+ )
138
+ ] }),
139
+ /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-col gap-1", children: items.flatMap(
140
+ (i) => i.count > 0 ? [
141
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
142
+ /* @__PURE__ */ jsx("span", { className: `h-2 w-2 shrink-0 rounded-sm ${colorClass[i.color]}` }),
143
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
144
+ i.label,
145
+ ": ",
146
+ i.count
147
+ ] })
148
+ ] }, i.label)
149
+ ] : []
150
+ ) })
151
+ ] });
152
+ };
153
+ var EmptyState = ({ icon, title, description, action }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-12", children: [
154
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: icon }),
155
+ /* @__PURE__ */ jsx("h3", { className: "text-h3", children: title }),
156
+ description && /* @__PURE__ */ jsx("p", { className: "text-caption text-muted-foreground", children: description }),
157
+ action && /* @__PURE__ */ jsx("div", { className: "mt-2", children: action })
158
+ ] });
159
+ var ErrorBoundary = class extends Component {
160
+ state = { error: null, copied: false };
161
+ static getDerivedStateFromError(error) {
162
+ return { error };
163
+ }
164
+ componentDidCatch(error, info) {
165
+ console.error("[ErrorBoundary]", error, info.componentStack);
166
+ }
167
+ reset = () => this.setState({ error: null, copied: false });
168
+ copyError = () => {
169
+ const { error } = this.state;
170
+ if (!error) return;
171
+ const text = `${error.message}
172
+ ${error.stack ?? ""}`;
173
+ navigator.clipboard.writeText(text).then(() => {
174
+ this.setState({ copied: true });
175
+ setTimeout(() => this.setState({ copied: false }), 2e3);
176
+ });
177
+ };
178
+ render() {
179
+ const { error, copied } = this.state;
180
+ if (error) {
181
+ if (this.props.fallback) return this.props.fallback(error, this.reset);
182
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 p-8 text-center", children: [
183
+ /* @__PURE__ */ jsx("p", { className: "text-destructive font-semibold", children: "Something went wrong" }),
184
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-xl", children: [
185
+ /* @__PURE__ */ jsxs("pre", { className: "bg-muted text-muted-foreground overflow-auto rounded p-4 text-left text-xs", children: [
186
+ error.message,
187
+ "\n",
188
+ error.stack
189
+ ] }),
190
+ /* @__PURE__ */ jsx(
191
+ Button,
192
+ {
193
+ type: "button",
194
+ variant: "ghost",
195
+ size: "icon",
196
+ className: "absolute right-2 top-2 h-6 w-6",
197
+ "aria-label": "Copy error",
198
+ onClick: this.copyError,
199
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-success size-3.5" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "size-3.5" })
200
+ }
201
+ )
202
+ ] }),
203
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "link", onClick: this.reset, className: "text-sm", children: "Try again" })
204
+ ] });
205
+ }
206
+ return this.props.children;
207
+ }
208
+ };
209
+ var LoadingSpinner = ({ className }) => /* @__PURE__ */ jsx("div", { className: cn("flex h-full items-center justify-center", className), children: /* @__PURE__ */ jsx(Loader2Icon, { className: "text-muted-foreground size-5 animate-spin" }) });
210
+ function barColor(percent) {
211
+ if (percent <= 50) return "bg-success";
212
+ if (percent <= 80) return "bg-warning";
213
+ return "bg-destructive";
214
+ }
215
+ var ResourceCell = ({ label, percent }) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-36 flex-col gap-1", children: [
216
+ /* @__PURE__ */ jsx("div", { className: "bg-muted h-1.5 w-full rounded-full", children: percent > 0 && /* @__PURE__ */ jsx(
217
+ "div",
218
+ {
219
+ className: cn("transition-interactive h-full rounded-full", barColor(percent)),
220
+ style: { width: `${Math.min(percent, 100)}%` }
221
+ }
222
+ ) }),
223
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: label })
224
+ ] });
225
+ var ButtonGroup = ({ children, className }) => /* @__PURE__ */ jsx(
226
+ "div",
227
+ {
228
+ "data-slot": "button-group",
229
+ className: cn(
230
+ "flex -space-x-px [&>button:first-child]:rounded-l-lg [&>button:focus-visible]:z-10 [&>button:last-child]:rounded-r-lg [&>button]:rounded-none",
231
+ className
232
+ ),
233
+ children
234
+ }
235
+ );
236
+ var ResourceBulkDeletionButton = ({
237
+ count,
238
+ ariaLabel,
239
+ tooltip,
240
+ onClick
241
+ }) => /* @__PURE__ */ jsxs(Tooltip, { children: [
242
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsxs(
243
+ Button,
244
+ {
245
+ size: "icon-sm",
246
+ variant: "destructive",
247
+ className: "relative rounded-full",
248
+ disabled: count === 0,
249
+ "aria-label": ariaLabel,
250
+ onClick,
251
+ children: [
252
+ /* @__PURE__ */ jsx(MinusIcon, { className: "size-3.5" }),
253
+ count > 0 && /* @__PURE__ */ jsx("span", { className: "bg-destructive absolute -right-2.5 -top-2.5 flex size-5 items-center justify-center rounded-full text-[10px] font-bold text-white", children: count })
254
+ ]
255
+ }
256
+ ) }),
257
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltip })
258
+ ] });
259
+ var ResourceCreationButton = ({
260
+ ariaLabel,
261
+ tooltip,
262
+ onClick
263
+ }) => /* @__PURE__ */ jsxs(Tooltip, { children: [
264
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(Button, { size: "icon-sm", className: "rounded-full", "aria-label": ariaLabel, onClick, children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" }) }) }),
265
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltip })
266
+ ] });
267
+ var ResourceDeletionButton = ({
268
+ onClick,
269
+ mode = "menu-item",
270
+ ariaLabel = "Delete",
271
+ disabled,
272
+ isPending,
273
+ label = "Delete",
274
+ className
275
+ }) => {
276
+ const isDisabled = disabled || isPending;
277
+ if (mode === "icon-button") {
278
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
279
+ /* @__PURE__ */ jsx(
280
+ TooltipTrigger,
281
+ {
282
+ render: /* @__PURE__ */ jsx(
283
+ Button,
284
+ {
285
+ "aria-label": ariaLabel,
286
+ variant: "ghost",
287
+ size: "icon-sm",
288
+ disabled: isDisabled,
289
+ onClick,
290
+ className,
291
+ children: isPending ? /* @__PURE__ */ jsx(Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(Trash2Icon, {})
292
+ }
293
+ )
294
+ }
295
+ ),
296
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: label })
297
+ ] });
298
+ }
299
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, { disabled: isDisabled, onClick, className, children: [
300
+ isPending ? /* @__PURE__ */ jsx(Loader2Icon, { className: "mr-2 size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Trash2Icon, { className: "mr-2 size-3.5" }),
301
+ label
302
+ ] });
303
+ };
304
+ var ResourceModificationButton = ({
305
+ onClick,
306
+ mode = "menu-item",
307
+ ariaLabel = "Edit",
308
+ disabled
309
+ }) => {
310
+ if (mode === "icon-button") {
311
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
312
+ /* @__PURE__ */ jsx(
313
+ TooltipTrigger,
314
+ {
315
+ render: /* @__PURE__ */ jsx(
316
+ Button,
317
+ {
318
+ "aria-label": ariaLabel,
319
+ variant: "ghost",
320
+ size: "icon-sm",
321
+ disabled,
322
+ onClick,
323
+ children: /* @__PURE__ */ jsx(PencilIcon, {})
324
+ }
325
+ )
326
+ }
327
+ ),
328
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Edit" })
329
+ ] });
330
+ }
331
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, { disabled, onClick, children: [
332
+ /* @__PURE__ */ jsx(PencilIcon, { className: "mr-2 size-3.5" }),
333
+ "Edit"
334
+ ] });
335
+ };
336
+ var ResourceRestartButton = ({
337
+ onClick,
338
+ mode = "menu-item",
339
+ ariaLabel = "Restart",
340
+ disabled
341
+ }) => {
342
+ if (mode === "icon-button") {
343
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
344
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(
345
+ Button,
346
+ {
347
+ "aria-label": ariaLabel,
348
+ variant: "ghost",
349
+ size: "icon-sm",
350
+ disabled,
351
+ onClick,
352
+ children: /* @__PURE__ */ jsx(RefreshCwIcon, {})
353
+ }
354
+ ) }),
355
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Restart" })
356
+ ] });
357
+ }
358
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, { disabled, onClick, children: [
359
+ /* @__PURE__ */ jsx(RefreshCwIcon, { className: "mr-2 size-3.5" }),
360
+ "Restart"
361
+ ] });
362
+ };
363
+ var ResourceScaleButton = ({
364
+ onClick,
365
+ mode = "menu-item",
366
+ ariaLabel = "Scale",
367
+ disabled,
368
+ isNotAllowed,
369
+ notAllowedReason
370
+ }) => {
371
+ if (mode === "icon-button") {
372
+ if (isNotAllowed) {
373
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
374
+ /* @__PURE__ */ jsx(
375
+ TooltipTrigger,
376
+ {
377
+ render: /* @__PURE__ */ jsx("span", { className: "inline-flex", children: /* @__PURE__ */ jsx(Button, { "aria-label": ariaLabel, variant: "ghost", size: "icon-sm", disabled: true, children: /* @__PURE__ */ jsx(ScalingIcon, {}) }) })
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: notAllowedReason ?? "Not allowed" })
381
+ ] });
382
+ }
383
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
384
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(
385
+ Button,
386
+ {
387
+ "aria-label": ariaLabel,
388
+ variant: "ghost",
389
+ size: "icon-sm",
390
+ disabled,
391
+ onClick,
392
+ children: /* @__PURE__ */ jsx(ScalingIcon, {})
393
+ }
394
+ ) }),
395
+ /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Scale" })
396
+ ] });
397
+ }
398
+ if (isNotAllowed) {
399
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
400
+ /* @__PURE__ */ jsx(
401
+ TooltipTrigger,
402
+ {
403
+ render: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsxs(DropdownMenuItem, { disabled: true, children: [
404
+ /* @__PURE__ */ jsx(ScalingIcon, { className: "mr-2 size-3.5" }),
405
+ "Scale"
406
+ ] }) })
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsx(TooltipContent, { side: "left", positionerClassName: "z-popover-nested", children: notAllowedReason ?? "Not allowed" })
410
+ ] }) });
411
+ }
412
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, { disabled, onClick, children: [
413
+ /* @__PURE__ */ jsx(ScalingIcon, { className: "mr-2 size-3.5" }),
414
+ "Scale"
415
+ ] });
416
+ };
417
+ var ResourceDetailEmptyBody = ({ resourceKind }) => /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground p-4 text-xs", children: [
418
+ "There are no information for this ",
419
+ resourceKind,
420
+ "."
421
+ ] });
422
+ var ResourceDetailDrawer = ({
423
+ open,
424
+ onClose,
425
+ children,
426
+ className
427
+ }) => {
428
+ return /* @__PURE__ */ jsx(
429
+ Sheet,
430
+ {
431
+ open,
432
+ onOpenChange: (o) => {
433
+ if (!o) onClose();
434
+ },
435
+ children: /* @__PURE__ */ jsx(
436
+ SheetContent,
437
+ {
438
+ side: "right",
439
+ className: cn("w-200 sm:max-w-200 flex flex-col gap-0 p-0", className),
440
+ children
441
+ }
442
+ )
443
+ }
444
+ );
445
+ };
446
+ var ResourceDetailDrawerHeader = ({
447
+ children,
448
+ className
449
+ }) => /* @__PURE__ */ jsx(
450
+ SheetHeader,
451
+ {
452
+ className: cn("flex flex-row items-center justify-between border-b px-4 py-3", className),
453
+ children
454
+ }
455
+ );
456
+ var ResourceDetailDrawerBody = ({
457
+ children,
458
+ className
459
+ }) => /* @__PURE__ */ jsx(ScrollArea, { className: "h-full", children: /* @__PURE__ */ jsx("div", { className: cn("p-4", className), children }) });
460
+ var LineIcon = ({
461
+ isError,
462
+ isSpinning
463
+ }) => {
464
+ if (isError) return /* @__PURE__ */ jsx(XCircleIcon, { className: "text-destructive mt-0.5 h-3.5 w-3.5 shrink-0" });
465
+ if (isSpinning)
466
+ return /* @__PURE__ */ jsx(Loader2Icon, { className: "text-info mt-0.5 h-3.5 w-3.5 shrink-0 animate-spin" });
467
+ return /* @__PURE__ */ jsx(CheckCircle2Icon, { className: "text-success mt-0.5 h-3.5 w-3.5 shrink-0" });
468
+ };
469
+ var SearchInput = ({
470
+ wrapperClassName = "w-68",
471
+ className,
472
+ ...props
473
+ }) => {
474
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", wrapperClassName), children: [
475
+ /* @__PURE__ */ jsx(SearchIcon, { className: "text-muted-foreground absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2" }),
476
+ /* @__PURE__ */ jsx(Input, { className: cn("pl-8 text-xs", className), ...props })
477
+ ] });
478
+ };
479
+ var TIMEZONES = Intl.supportedValuesOf("timeZone");
480
+ var TimezoneSelect = ({
481
+ value,
482
+ onChange,
483
+ "aria-labelledby": ariaLabelledBy
484
+ }) => {
485
+ const [open, setOpen] = useState(false);
486
+ const [search, setSearch] = useState("");
487
+ const [dropdownRect, setDropdownRect] = useState(null);
488
+ const triggerRef = useRef(null);
489
+ const dropdownRef = useRef(null);
490
+ const searchRef = useRef(null);
491
+ const filtered = useMemo(
492
+ () => search.trim() ? TIMEZONES.filter((tz) => tz.toLowerCase().includes(search.toLowerCase())) : TIMEZONES,
493
+ [search]
494
+ );
495
+ function handleOpen() {
496
+ const rect = triggerRef.current?.getBoundingClientRect();
497
+ if (!rect) return;
498
+ setDropdownRect({ top: rect.bottom + 4, left: rect.left, width: rect.width });
499
+ setSearch("");
500
+ setOpen(true);
501
+ requestAnimationFrame(() => searchRef.current?.focus());
502
+ }
503
+ useEffect(() => {
504
+ if (!open) return;
505
+ function handlePointerDown(e) {
506
+ const target = e.target;
507
+ if (triggerRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
508
+ setOpen(false);
509
+ }
510
+ document.addEventListener("mousedown", handlePointerDown);
511
+ return () => document.removeEventListener("mousedown", handlePointerDown);
512
+ }, [open]);
513
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
514
+ /* @__PURE__ */ jsxs(
515
+ Button,
516
+ {
517
+ ref: triggerRef,
518
+ variant: "outline",
519
+ "aria-haspopup": "listbox",
520
+ "aria-expanded": open,
521
+ "aria-labelledby": ariaLabelledBy,
522
+ onClick: handleOpen,
523
+ className: "w-full justify-between font-normal",
524
+ children: [
525
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: value }),
526
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground size-4 shrink-0" })
527
+ ]
528
+ }
529
+ ),
530
+ open && dropdownRect && createPortal(
531
+ /* @__PURE__ */ jsxs(
532
+ "div",
533
+ {
534
+ ref: dropdownRef,
535
+ style: {
536
+ position: "fixed",
537
+ top: dropdownRect.top,
538
+ left: dropdownRect.left,
539
+ width: dropdownRect.width,
540
+ zIndex: 50
541
+ },
542
+ className: "bg-popover text-popover-foreground ring-foreground/10 flex flex-col overflow-hidden rounded-lg shadow-md ring-1",
543
+ children: [
544
+ /* @__PURE__ */ jsx("div", { className: "border-b p-1.5", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
545
+ /* @__PURE__ */ jsx(SearchIcon, { className: "text-muted-foreground pointer-events-none absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2" }),
546
+ /* @__PURE__ */ jsx(
547
+ Input,
548
+ {
549
+ ref: searchRef,
550
+ value: search,
551
+ onChange: (e) => setSearch(e.target.value),
552
+ placeholder: "Search timezone\u2026",
553
+ className: "pl-8 text-sm"
554
+ }
555
+ )
556
+ ] }) }),
557
+ /* @__PURE__ */ jsx("div", { role: "listbox", "aria-label": "Timezone", className: "max-h-56 overflow-y-auto p-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-4 text-center text-sm", children: "No timezone found." }) : filtered.map((tz) => /* @__PURE__ */ jsxs(
558
+ "div",
559
+ {
560
+ role: "option",
561
+ "aria-selected": tz === value,
562
+ tabIndex: -1,
563
+ onClick: () => {
564
+ onChange(tz);
565
+ setOpen(false);
566
+ },
567
+ onKeyDown: (e) => {
568
+ if (e.key === "Enter" || e.key === " ") {
569
+ e.preventDefault();
570
+ onChange(tz);
571
+ setOpen(false);
572
+ }
573
+ },
574
+ className: cn(
575
+ "flex cursor-pointer items-center justify-between rounded-md px-3 py-1.5 text-sm",
576
+ tz === value ? "bg-accent text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground"
577
+ ),
578
+ children: [
579
+ tz,
580
+ tz === value && /* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5 shrink-0" })
581
+ ]
582
+ },
583
+ tz
584
+ )) })
585
+ ]
586
+ }
587
+ ),
588
+ document.body
589
+ )
590
+ ] });
591
+ };
592
+ var ConfirmationModal = ({
593
+ open,
594
+ title,
595
+ description,
596
+ confirmLabel = "Confirm",
597
+ confirmVariant = "default",
598
+ isPending,
599
+ onClose,
600
+ onConfirm
601
+ }) => /* @__PURE__ */ jsx(
602
+ Dialog,
603
+ {
604
+ open,
605
+ onOpenChange: (o) => {
606
+ if (!o && !isPending) onClose();
607
+ },
608
+ children: /* @__PURE__ */ jsxs(DialogContent, { children: [
609
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-h2 flex gap-2", children: title }) }),
610
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-body", children: description }),
611
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
612
+ /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: isPending, onClick: onClose, children: "Cancel" }),
613
+ /* @__PURE__ */ jsxs(Button, { variant: confirmVariant, disabled: isPending, onClick: onConfirm, children: [
614
+ isPending && /* @__PURE__ */ jsx(Loader2Icon, { className: "mr-1.5 size-3.5 animate-spin" }),
615
+ confirmLabel
616
+ ] })
617
+ ] })
618
+ ] })
619
+ }
620
+ );
621
+ var FormModal = ({
622
+ open,
623
+ onOpenChange,
624
+ onClose,
625
+ title,
626
+ children,
627
+ onSubmit,
628
+ isLoading = false,
629
+ submitDisabled = false,
630
+ submitLabel = "Submit",
631
+ cancelLabel = "Cancel",
632
+ size = "sm"
633
+ }) => /* @__PURE__ */ jsx(
634
+ Dialog,
635
+ {
636
+ open,
637
+ onOpenChange: (o) => {
638
+ if (!o && !isLoading) onClose();
639
+ onOpenChange?.(o);
640
+ },
641
+ children: /* @__PURE__ */ jsxs(DialogContent, { size, children: [
642
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-h2", children: title }) }),
643
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children }),
644
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
645
+ /* @__PURE__ */ jsx(Button, { variant: "outline", disabled: isLoading, onClick: onClose, children: cancelLabel }),
646
+ /* @__PURE__ */ jsxs(Button, { disabled: isLoading || submitDisabled, onClick: onSubmit, children: [
647
+ isLoading && /* @__PURE__ */ jsx(Loader2Icon, { className: "mr-1.5 size-3.5 animate-spin" }),
648
+ submitLabel
649
+ ] })
650
+ ] })
651
+ ] })
652
+ }
653
+ );
654
+ var EMPTY_COLUMN_WIDTHS = [];
655
+ var TableSkeletonRow = ({
656
+ columns,
657
+ includeCheckbox = false,
658
+ columnWidths = EMPTY_COLUMN_WIDTHS
659
+ }) => /* @__PURE__ */ jsxs(TableRow, { children: [
660
+ includeCheckbox && /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("div", { className: "bg-muted h-4 w-4 animate-pulse rounded-[4px]" }) }),
661
+ Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
662
+ "div",
663
+ {
664
+ className: cn("bg-muted h-4 animate-pulse rounded-sm", columnWidths[i] ?? "w-[70%]")
665
+ }
666
+ ) }, i)),
667
+ /* @__PURE__ */ jsx(TableCell, {})
668
+ ] });
669
+ var EMPTY_COLUMN_WIDTHS2 = [];
670
+ var TableSkeletonLoader = ({
671
+ rows = 5,
672
+ columns,
673
+ includeCheckbox = false,
674
+ columnWidths = EMPTY_COLUMN_WIDTHS2
675
+ }) => /* @__PURE__ */ jsx(Fragment, { children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(
676
+ TableSkeletonRow,
677
+ {
678
+ columns,
679
+ includeCheckbox,
680
+ columnWidths
681
+ },
682
+ i
683
+ )) });
684
+ var markdownComponents = {
685
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "text-foreground mb-3 mt-4 text-lg font-bold leading-tight", children }),
686
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-foreground border-border/50 mb-2.5 mt-3.5 border-b pb-2 text-base font-semibold leading-snug", children }),
687
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-foreground mb-2 mt-3 text-sm font-semibold leading-snug", children }),
688
+ h4: ({ children }) => /* @__PURE__ */ jsx("h4", { className: "text-foreground mb-1.5 mt-2.5 text-sm font-semibold leading-snug", children }),
689
+ h5: ({ children }) => /* @__PURE__ */ jsx("h5", { className: "text-foreground mb-1.5 mt-2.5 text-xs font-semibold leading-snug", children }),
690
+ h6: ({ children }) => /* @__PURE__ */ jsx("h6", { className: "text-muted-foreground mb-1.5 mt-2.5 text-xs font-semibold leading-snug", children }),
691
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { className: "text-foreground mb-2.5 text-xs leading-relaxed", children }),
692
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "text-foreground mb-2.5 list-inside list-disc space-y-1 text-xs leading-relaxed", children }),
693
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "text-foreground mb-2.5 list-inside list-decimal space-y-1 text-xs leading-relaxed", children }),
694
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { className: "text-foreground text-xs leading-relaxed", children }),
695
+ pre: ({ children }) => /* @__PURE__ */ jsx("pre", { className: "bg-muted/40 border-border/40 my-3 overflow-x-auto rounded border p-3", children }),
696
+ code: ({ children, className }) => {
697
+ const isBlock = !!className;
698
+ if (isBlock) {
699
+ return /* @__PURE__ */ jsx("code", { className: "text-foreground block font-mono text-xs leading-relaxed", children });
700
+ }
701
+ return /* @__PURE__ */ jsx("code", { className: "bg-muted/60 text-foreground rounded px-1.5 py-0.5 font-mono text-xs", children });
702
+ },
703
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "my-3 overflow-x-auto", children: /* @__PURE__ */ jsx("table", { className: "border-collapse text-xs", children }) }),
704
+ thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "bg-muted/50", children }),
705
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "text-foreground border-border/40 border px-2.5 py-2 text-left text-xs font-semibold", children }),
706
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "border-border/40 text-foreground border px-2.5 py-2 text-xs", children }),
707
+ blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "border-border/60 text-muted-foreground my-2.5 border-l-4 py-1 pl-3 text-xs italic", children }),
708
+ a: ({ children, href }) => /* @__PURE__ */ jsx(
709
+ "a",
710
+ {
711
+ href,
712
+ target: "_blank",
713
+ rel: "noreferrer",
714
+ className: "wrap-break-word cursor-pointer text-blue-500 underline-offset-1 hover:underline",
715
+ children
716
+ }
717
+ ),
718
+ img: ({ src, alt }) => /* @__PURE__ */ jsx("img", { src, alt, className: "border-border/40 my-2.5 h-auto max-w-full rounded border" }),
719
+ hr: () => /* @__PURE__ */ jsx("hr", { className: "border-border/40 my-3 border-t" })
720
+ };
721
+ var Markdown = ({ children, className }) => /* @__PURE__ */ jsx("div", { className: cn("text-foreground", className), children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents, children: children.replace(/<!--[\s\S]*?-->/g, "") }) });
722
+ var TruncatedText = ({ text, className, tooltipClassName, positionerClassName }) => {
723
+ const wrapperRef = useRef(null);
724
+ const textRef = useRef(null);
725
+ const [overflowing, setOverflowing] = useState(false);
726
+ useLayoutEffect(() => {
727
+ const wrapper = wrapperRef.current;
728
+ if (!wrapper) return;
729
+ const check = () => {
730
+ const el = textRef.current;
731
+ if (el) setOverflowing(el.scrollWidth > el.clientWidth);
732
+ };
733
+ check();
734
+ const observer = new ResizeObserver(check);
735
+ observer.observe(wrapper);
736
+ return () => observer.disconnect();
737
+ }, [text]);
738
+ const content = /* @__PURE__ */ jsx("span", { ref: textRef, className: cn("block truncate font-mono text-xs", className), children: text });
739
+ return /* @__PURE__ */ jsx("span", { ref: wrapperRef, className: "block min-w-0 overflow-hidden", children: overflowing ? /* @__PURE__ */ jsxs(Tooltip, { children: [
740
+ /* @__PURE__ */ jsx(TooltipTrigger, { className: "block w-full", children: content }),
741
+ /* @__PURE__ */ jsx(TooltipContent, { className: tooltipClassName, positionerClassName, children: /* @__PURE__ */ jsx("p", { children: text }) })
742
+ ] }) : content });
743
+ };
744
+ var SuccessToast = ({ title, description, action }) => {
745
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-(--radius) bg-success flex w-full flex-col gap-1.5 px-4 py-3 text-white shadow-lg", children: [
746
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
747
+ /* @__PURE__ */ jsx(CircleCheckIcon, { className: "mt-0.5 h-4 w-4 shrink-0" }),
748
+ /* @__PURE__ */ jsx("p", { className: "flex-1 text-sm font-semibold", children: title }),
749
+ action && /* @__PURE__ */ jsx(
750
+ Button,
751
+ {
752
+ variant: "outline",
753
+ size: "xs",
754
+ className: "shrink-0 border-white/40 bg-transparent text-white hover:bg-white/10 hover:text-white",
755
+ onClick: action.onClick,
756
+ children: action.label
757
+ }
758
+ )
759
+ ] }),
760
+ /* @__PURE__ */ jsx("p", { className: "pl-7 text-xs opacity-90", children: description })
761
+ ] });
762
+ };
763
+
764
+ // src/components/toasts/const.ts
765
+ var TOAST_STYLE = { "--width": "450px" };
766
+ function renderSuccessToast(props) {
767
+ toast.custom(
768
+ (t) => /* @__PURE__ */ jsx(
769
+ SuccessToast,
770
+ {
771
+ ...props,
772
+ action: props.action && {
773
+ label: props.action.label,
774
+ onClick: () => {
775
+ toast.dismiss(t);
776
+ props.action.onClick();
777
+ }
778
+ }
779
+ }
780
+ ),
781
+ { style: TOAST_STYLE }
782
+ );
783
+ }
784
+ var ErrorToast = ({ title, description, action }) => {
785
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-(--radius) bg-destructive flex w-full flex-col gap-1.5 px-4 py-3 text-white shadow-lg", children: [
786
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
787
+ /* @__PURE__ */ jsx(CircleXIcon, { className: "mt-0.5 h-4 w-4 shrink-0" }),
788
+ /* @__PURE__ */ jsx("p", { className: "flex-1 text-sm font-semibold", children: title }),
789
+ action && /* @__PURE__ */ jsx(
790
+ Button,
791
+ {
792
+ variant: "outline",
793
+ size: "xs",
794
+ className: "shrink-0 border-white/40 bg-transparent text-white hover:bg-white/10 hover:text-white",
795
+ onClick: action.onClick,
796
+ children: action.label
797
+ }
798
+ )
799
+ ] }),
800
+ description && /* @__PURE__ */ jsx("p", { className: "pl-7 text-xs opacity-90", children: description })
801
+ ] });
802
+ };
803
+ function renderErrorToast(props) {
804
+ toast.custom(
805
+ (t) => /* @__PURE__ */ jsx(
806
+ ErrorToast,
807
+ {
808
+ ...props,
809
+ action: props.action && {
810
+ label: props.action.label,
811
+ onClick: () => {
812
+ toast.dismiss(t);
813
+ props.action.onClick();
814
+ }
815
+ }
816
+ }
817
+ ),
818
+ { style: TOAST_STYLE }
819
+ );
820
+ }
821
+
822
+ export { AnnotationBadge, ButtonGroup, ConfirmationModal, Divider, DonutChart, EmptyState, ErrorBoundary, ErrorToast, FormModal, LineIcon, LoadingSpinner, Markdown, ResourceBulkDeletionButton, ResourceCell, ResourceCreationButton, ResourceDeletionButton, ResourceDetailDrawer, ResourceDetailDrawerBody, ResourceDetailDrawerHeader, ResourceDetailEmptyBody, ResourceLink, ResourceModificationButton, ResourceRestartButton, ResourceScaleButton, SearchInput, SuccessToast, TOAST_STYLE, TableSkeletonLoader, TableSkeletonRow, TimezoneSelect, TruncatedText, renderErrorToast, renderSuccessToast };