@keboola/design 1.0.0 → 1.2.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.
@@ -0,0 +1,1002 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var beautifulMermaid = require('beautiful-mermaid');
5
+ var colors = require('@keboola/tailwind-config/colors');
6
+ var clsx = require('clsx');
7
+ var tailwindMerge = require('tailwind-merge');
8
+ var reactTooltip = require('@radix-ui/react-tooltip');
9
+ var classVarianceAuthority = require('class-variance-authority');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+ var reactSlot = require('@radix-ui/react-slot');
12
+ var reactFontawesome = require('@fortawesome/react-fontawesome');
13
+ var design = require('@keboola/design');
14
+
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
+
17
+ var colors__default = /*#__PURE__*/_interopDefault(colors);
18
+
19
+ // src/blocks/MermaidDiagram/MermaidDiagram.tsx
20
+ var twMerge = tailwindMerge.extendTailwindMerge({
21
+ prefix: "tw-"
22
+ });
23
+ var cn = (...classes) => twMerge(clsx.clsx(...classes));
24
+
25
+ // src/utils/copyToClipboard.ts
26
+ var copyToClipboard = (text) => {
27
+ return navigator.clipboard.writeText(text);
28
+ };
29
+
30
+ // src/constants/keyCodes.ts
31
+ var keyCodes = {
32
+ ENTER: "Enter",
33
+ SPACE: " "
34
+ };
35
+ var tooltipVariants = classVarianceAuthority.cva(
36
+ [
37
+ "tailwindcss-preflight",
38
+ "tw-inline-block",
39
+ "tw-rounded",
40
+ "tw-bg-neutral-800",
41
+ "tw-text-white",
42
+ "tw-break-anywhere",
43
+ "tw-max-h-96",
44
+ "tw-overflow-y-auto",
45
+ "tw-z-[1060]"
46
+ ],
47
+ {
48
+ defaultVariants: {
49
+ variant: "action"
50
+ },
51
+ variants: {
52
+ variant: {
53
+ action: [
54
+ "tw-max-w-fit",
55
+ "tw-px-3",
56
+ "tw-py-2",
57
+ "tw-text-center",
58
+ "tw-text-xs",
59
+ "tw-font-medium",
60
+ "tw-uppercase",
61
+ "tw-tracking-wider"
62
+ ],
63
+ explanatory: [
64
+ "tw-max-w-80",
65
+ "tw-px-4",
66
+ "tw-py-3",
67
+ "tw-text-left",
68
+ "tw-text-sm",
69
+ "tw-font-normal"
70
+ ]
71
+ }
72
+ }
73
+ }
74
+ );
75
+ var TooltipContent = ({
76
+ className,
77
+ variant,
78
+ keepOpenOnPointerDownOutside = false,
79
+ children,
80
+ onPointerDownOutside,
81
+ sideOffset = 8,
82
+ collisionPadding = 8,
83
+ hideWhenDetached = true,
84
+ placement = "right",
85
+ ...rest
86
+ }) => {
87
+ const handlePointerDownOutside = (event) => {
88
+ if (keepOpenOnPointerDownOutside) event.preventDefault();
89
+ onPointerDownOutside?.(event);
90
+ };
91
+ return /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
92
+ reactTooltip.Content,
93
+ {
94
+ ...rest,
95
+ "data-tooltip-content": true,
96
+ sideOffset,
97
+ collisionPadding,
98
+ onPointerDownOutside: handlePointerDownOutside,
99
+ className: tooltipVariants({ className, variant }),
100
+ hideWhenDetached,
101
+ side: placement,
102
+ children
103
+ }
104
+ ) });
105
+ };
106
+ var DELAY_SHOW_TOOLTIP = 300;
107
+ var TooltipRoot = ({ children, delayDuration = DELAY_SHOW_TOOLTIP, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.Root, { ...rest, delayDuration, children });
108
+ var TooltipTrigger = ({
109
+ ref,
110
+ children,
111
+ className,
112
+ keepOpenOnClick = false,
113
+ onClick,
114
+ onPointerDown,
115
+ asChild,
116
+ ...rest
117
+ }) => {
118
+ const handleClick = (event) => {
119
+ if (keepOpenOnClick) event.preventDefault();
120
+ onClick?.(event);
121
+ };
122
+ const handePointerDown = (event) => {
123
+ if (keepOpenOnClick) event.preventDefault();
124
+ onPointerDown?.(event);
125
+ };
126
+ return /* @__PURE__ */ jsxRuntime.jsx(
127
+ reactTooltip.Trigger,
128
+ {
129
+ ...rest,
130
+ asChild: true,
131
+ ref,
132
+ className: cn("tailwindcss-preflight", className),
133
+ onClick: handleClick,
134
+ onPointerDown: handePointerDown,
135
+ children: asChild ? children : /* @__PURE__ */ jsxRuntime.jsx("span", { children })
136
+ }
137
+ );
138
+ };
139
+ var ACTION_TOOLTIP_LIMIT = 30;
140
+ var Tooltip = ({
141
+ tooltip,
142
+ children,
143
+ className,
144
+ keepOpenOnTriggerClick = false,
145
+ variant,
146
+ placement = "right",
147
+ forceHide = false,
148
+ forceShow = false,
149
+ // trigger props
150
+ triggerAsChild = false
151
+ }) => {
152
+ const [open, setOpen] = react.useState(false);
153
+ const resolvedVariant = (() => {
154
+ if (!!variant) return variant;
155
+ if (typeof tooltip === "string" && tooltip.length > ACTION_TOOLTIP_LIMIT) return "explanatory";
156
+ return "action";
157
+ })();
158
+ const isActionVariant = resolvedVariant === "action";
159
+ const handleKeyUp = (event) => {
160
+ if (![keyCodes.ENTER, keyCodes.SPACE].includes(event.key)) return;
161
+ event.stopPropagation();
162
+ };
163
+ return /* @__PURE__ */ jsxRuntime.jsxs(
164
+ TooltipRoot,
165
+ {
166
+ open: !!tooltip && (open || forceShow) && !forceHide,
167
+ onOpenChange: setOpen,
168
+ disableHoverableContent: isActionVariant,
169
+ children: [
170
+ /* @__PURE__ */ jsxRuntime.jsx(
171
+ TooltipTrigger,
172
+ {
173
+ asChild: triggerAsChild,
174
+ keepOpenOnClick: keepOpenOnTriggerClick,
175
+ onKeyUp: handleKeyUp,
176
+ children
177
+ }
178
+ ),
179
+ /* @__PURE__ */ jsxRuntime.jsx(
180
+ TooltipContent,
181
+ {
182
+ className,
183
+ variant: resolvedVariant,
184
+ placement,
185
+ keepOpenOnPointerDownOutside: keepOpenOnTriggerClick,
186
+ children: tooltip
187
+ }
188
+ )
189
+ ]
190
+ }
191
+ );
192
+ };
193
+ Tooltip.Root = TooltipRoot;
194
+ Tooltip.Content = TooltipContent;
195
+ Tooltip.Trigger = TooltipTrigger;
196
+ var HEIGHT_CLASS_NAME = {
197
+ xxs: "tw-h-3 tw-rounded",
198
+ xs: "tw-h-4 tw-rounded",
199
+ sm: "tw-h-5 tw-rounded",
200
+ md: "tw-h-6 tw-rounded-md",
201
+ lg: "tw-h-8 tw-rounded-lg",
202
+ xl: "tw-h-10 tw-rounded-lg",
203
+ "2xl": "tw-h-12 tw-rounded-lg"
204
+ };
205
+ var ANIMATION_CLASS_NAME = cn(
206
+ // base styles
207
+ "tw-relative",
208
+ "tw-overflow-hidden",
209
+ "tw-pointer-events-none",
210
+ "tw-bg-neutral-150",
211
+ // before
212
+ 'before:tw-content-[""]',
213
+ "before:tw-opacity-100",
214
+ "before:tw-absolute",
215
+ "before:tw-inset-0",
216
+ "before:-tw-translate-x-full",
217
+ "before:tw-animate-[shimmer_2s_infinite]",
218
+ "before:tw-bg-gradient-to-r",
219
+ "before:tw-from-transparent",
220
+ "before:tw-to-transparent",
221
+ "before:tw-via-neutral-50"
222
+ );
223
+ var Skeleton = ({ height = "md", className, count = 1 }) => {
224
+ const prefixId = react.useId();
225
+ const keys = Array.from({ length: count }, (_, i) => `${prefixId}-${i}`);
226
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: keys.map((key) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(HEIGHT_CLASS_NAME[height], ANIMATION_CLASS_NAME, className) }, key)) });
227
+ };
228
+ var Icon = ({ ref, icon, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, { ...rest, ref, icon });
229
+ var variants = classVarianceAuthority.cva(
230
+ [
231
+ "tailwindcss-preflight",
232
+ "tw-group/button",
233
+ "tw-border-box",
234
+ // layout
235
+ "tw-relative",
236
+ "tw-flex",
237
+ "tw-items-center",
238
+ "tw-justify-center",
239
+ "tw-gap-2",
240
+ // text
241
+ "tw-text-xs",
242
+ "tw-leading-5",
243
+ "tw-font-medium",
244
+ "tw-tracking-[1px]",
245
+ "tw-uppercase",
246
+ // border
247
+ "tw-rounded",
248
+ "tw-border",
249
+ "tw-border-transparent",
250
+ // styling
251
+ "tw-shadow-none",
252
+ "[a]:tw-cursor-pointer",
253
+ // explicitly set for anchor
254
+ "focus-visible:tw-outline",
255
+ "focus-visible:tw-outline-1",
256
+ "focus-visible:-tw-outline-offset-1",
257
+ "focus-visible:tw-outline-secondary-500",
258
+ "focus-visible:tw-ring-4",
259
+ "focus-visible:tw-ring-secondary-200",
260
+ // disabled
261
+ "disabled:tw-opacity-40",
262
+ "disabled:tw-cursor-not-allowed",
263
+ // anchor support
264
+ "!tw-no-underline",
265
+ "aria-disabled:tw-opacity-40",
266
+ "aria-disabled:tw-cursor-not-allowed",
267
+ "[&_svg]:tw-shrink-0"
268
+ ],
269
+ {
270
+ defaultVariants: {
271
+ size: "medium",
272
+ variant: "primary",
273
+ block: false
274
+ },
275
+ variants: {
276
+ block: {
277
+ true: ["tw-w-full"]
278
+ },
279
+ variant: {
280
+ primary: [
281
+ "tw-text-white",
282
+ "tw-bg-primary-500",
283
+ "focus:tw-text-white",
284
+ "hover:tw-text-white",
285
+ "hover:not-disabled:tw-bg-primary-600",
286
+ "active:not-disabled:tw-bg-primary-800",
287
+ // anchor disabled override
288
+ "aria-disabled:!tw-bg-primary-500"
289
+ ],
290
+ secondary: [
291
+ "tw-text-white",
292
+ "tw-bg-secondary-500",
293
+ "focus:tw-text-white",
294
+ "hover:tw-text-white",
295
+ "hover:not-disabled:tw-bg-secondary-700",
296
+ "active:not-disabled:tw-bg-secondary-800",
297
+ // anchor disabled override
298
+ "aria-disabled:!tw-bg-secondary-500"
299
+ ],
300
+ danger: [
301
+ "tw-text-white",
302
+ "tw-bg-error-500",
303
+ "focus:tw-text-white",
304
+ "hover:tw-text-white",
305
+ "hover:not-disabled:tw-bg-error-600",
306
+ "active:not-disabled:tw-bg-error-700",
307
+ // anchor disabled override
308
+ "aria-disabled:!tw-bg-error-500"
309
+ ],
310
+ invisible: [
311
+ "tw-text-neutral-800",
312
+ "tw-bg-transparent",
313
+ "focus:tw-text-neutral-800",
314
+ "hover:not-disabled:tw-bg-neutral-100",
315
+ "hover:tw-text-neutral-800",
316
+ "active:not-disabled:tw-bg-neutral-150",
317
+ // contrasting icon on hover/active
318
+ "[&_svg]:tw-text-neutral-400",
319
+ "[&_svg]:hover:not-disabled:tw-text-secondary-600",
320
+ "[&_svg]:active:not-disabled:tw-text-secondary-600",
321
+ // anchor disabled override
322
+ "aria-disabled:!tw-bg-transparent"
323
+ ],
324
+ outline: [
325
+ "tw-text-neutral-800",
326
+ "tw-bg-white",
327
+ // border
328
+ "!tw-border-neutral-200",
329
+ "hover:tw-text-neutral-800",
330
+ "focus:tw-text-neutral-800",
331
+ "hover:not-disabled:!tw-border-neutral-300",
332
+ "hover:not-disabled:tw-bg-neutral-100",
333
+ "active:not-disabled:tw-bg-neutral-200",
334
+ // contrasting icon hover, same as invisible
335
+ "[&_svg]:tw-text-neutral-400",
336
+ "[&_svg]:not-disabled:hover:tw-text-secondary-600",
337
+ "[&_svg]:active:not-disabled:tw-text-secondary-600",
338
+ // anchor disabled override
339
+ "aria-disabled:!tw-bg-white",
340
+ "aria-disabled:!tw-border-neutral-200"
341
+ ],
342
+ inline: [
343
+ "tw-text-neutral-800",
344
+ "tw-bg-transparent",
345
+ "tw-rounded-full",
346
+ "[&_svg]:tw-text-neutral-400",
347
+ "[&_svg]:not-disabled:hover:tw-text-secondary-600",
348
+ "[&_svg]:not-disabled:focus:tw-text-secondary-600"
349
+ ]
350
+ },
351
+ size: {
352
+ medium: ["tw-max-h-10", "tw-min-h-10", "tw-px-4", "tw-py-2.5", "[&_svg]:tw-size-4"],
353
+ small: ["tw-max-h-8", "tw-min-h-8", "tw-px-4", "tw-py-1.5", "[&_svg]:tw-size-4"],
354
+ large: ["tw-max-h-12", "tw-min-h-12", "tw-px-4", "tw-py-3.5", "[&_svg]:tw-size-4"],
355
+ "icon-lg": ["tw-size-12", "tw-p-0", "[&_svg]:tw-size-6"],
356
+ icon: ["tw-size-10", "tw-p-0", "[&_svg]:tw-size-4"],
357
+ "icon-sm": ["tw-size-8", "tw-p-0", "[&_svg]:tw-size-4"],
358
+ "icon-xs": ["tw-size-6", "tw-p-0", "[&_svg]:tw-size-4"],
359
+ "icon-2xs": ["!tw-inline-flex", "tw-size-5", "tw-max-h-5", "[&_svg]:tw-size-3"],
360
+ "icon-3xs": ["tw-h-fit", "tw-w-fit", "[&_svg]:tw-size-4"]
361
+ }
362
+ }
363
+ }
364
+ );
365
+ var argoVariants = classVarianceAuthority.cva(
366
+ [
367
+ "tailwindcss-preflight",
368
+ // layout
369
+ "tw-relative",
370
+ "tw-inline-flex",
371
+ "tw-items-center",
372
+ "tw-justify-center",
373
+ "tw-whitespace-nowrap",
374
+ "tw-gap-2",
375
+ // border
376
+ "tw-border",
377
+ "tw-border-transparent",
378
+ "tw-rounded-lg",
379
+ // text
380
+ "tw-font-medium",
381
+ "tw-select-none",
382
+ // focus visible
383
+ "!tw-outline-none",
384
+ "focus-visible:tw-ring-2",
385
+ // disabled
386
+ "disabled:tw-cursor-not-allowed",
387
+ "disabled:tw-opacity-50",
388
+ "active:tw-opacity-60",
389
+ "tw-transition-all",
390
+ "tw-bg-clip-padding",
391
+ // anchor support
392
+ "!tw-no-underline",
393
+ // icon
394
+ "tw-shrink-0",
395
+ "[&_svg]:tw-pointer-events-none",
396
+ "[&_svg]:tw-shrink-0",
397
+ "[&_svg:not([class*='tw-size-'])]:tw-size-4"
398
+ ],
399
+ {
400
+ defaultVariants: {
401
+ variant: "primary",
402
+ size: "medium"
403
+ },
404
+ variants: {
405
+ block: {
406
+ true: ["tw-w-full"]
407
+ },
408
+ variant: {
409
+ primary: [
410
+ "tw-bg-primary",
411
+ "tw-text-primary-foreground",
412
+ "[a]:hover:tw-bg-primary/80",
413
+ "hover:not-disabled:tw-bg-primary/90",
414
+ "hover:tw-text-primary-foreground",
415
+ "focus:tw-text-primary-foreground",
416
+ "focus-visible:tw-border-primary",
417
+ "focus-visible:tw-ring-primary/50"
418
+ ],
419
+ secondary: [
420
+ "tw-bg-secondary",
421
+ "tw-text-secondary-foreground",
422
+ "hover:tw-bg-secondary/80",
423
+ "hover:tw-text-secondary-foreground",
424
+ "focus:tw-text-secondary-foreground",
425
+ "focus-visible:tw-border-secondary",
426
+ "focus-visible:tw-ring-primary/50"
427
+ ],
428
+ // should be called "destructive" by Figma
429
+ danger: [
430
+ "tw-bg-destructive",
431
+ "tw-text-destructive-foreground",
432
+ "hover:tw-text-destructive-foreground",
433
+ "focus:tw-text-destructive-foreground",
434
+ "focus-visible:tw-border-destructive",
435
+ "focus-visible:tw-ring-destructive/20"
436
+ ],
437
+ outline: [
438
+ "!tw-border-input",
439
+ "tw-bg-background",
440
+ "hover:not-disabled:tw-bg-accent",
441
+ "hover:not-disabled:tw-text-accent-foreground",
442
+ "hover:active:tw-bg-background",
443
+ "focus-visible:!tw-border-primary",
444
+ "focus-visible:tw-ring-primary/50"
445
+ ],
446
+ // should be called "ghost" by Figma
447
+ invisible: [
448
+ "tw-bg-transparent",
449
+ "tw-text-foreground",
450
+ "hover:not-disabled:tw-bg-accent",
451
+ "hover:not-disabled:tw-text-accent-foreground",
452
+ "hover:not-disabled:tw-border-accent",
453
+ "focus-visible:tw-ring-primary/50"
454
+ ],
455
+ // should be called "link" by Figma
456
+ inline: [
457
+ "tw-bg-transparent",
458
+ "tw-text-primary",
459
+ "hover:tw-underline",
460
+ "hover:active:tw-bg-transparent",
461
+ "focus-visible:tw-ring-primary/50"
462
+ ]
463
+ },
464
+ size: {
465
+ // should be called "default" by Figma
466
+ medium: ["tw-max-h-9", "tw-py-2", "tw-px-4", "tw-text-sm"],
467
+ // should be called "small" by Figma
468
+ small: ["tw-max-h-8", "tw-py-2", "tw-px-3", "tw-text-xs"],
469
+ // should be called "large" by Figma
470
+ large: ["tw-max-h-10", "tw-py-2.5", "tw-px-6", "tw-text-sm"],
471
+ "icon-lg": ["tw-size-10"],
472
+ icon: ["tw-size-9"],
473
+ "icon-sm": ["tw-size-8"],
474
+ // unsupported in ARGO, remove when old design is gone
475
+ "icon-xs": [],
476
+ "icon-2xs": [],
477
+ "icon-3xs": []
478
+ }
479
+ }
480
+ }
481
+ );
482
+ var Button = ({
483
+ ref,
484
+ children,
485
+ disabled = false,
486
+ className,
487
+ type = "button",
488
+ icon: iconProp,
489
+ isLoading = false,
490
+ asChild = false,
491
+ onClick,
492
+ argo = false,
493
+ variant = "primary",
494
+ size = "medium",
495
+ block = false,
496
+ ...buttonProps
497
+ }) => {
498
+ const Comp = asChild ? reactSlot.Root : "button";
499
+ const icon = isLoading ? "spinner" : iconProp;
500
+ const classNames = argo ? argoVariants({ variant, size, block, className }) : variants({
501
+ size,
502
+ variant,
503
+ block,
504
+ className
505
+ });
506
+ const handleClick = (event) => {
507
+ const isAnchor = event.currentTarget.tagName === "A";
508
+ if (isAnchor && disabled) {
509
+ event.preventDefault();
510
+ return;
511
+ }
512
+ onClick?.(event);
513
+ };
514
+ return /* @__PURE__ */ jsxRuntime.jsxs(
515
+ Comp,
516
+ {
517
+ ...buttonProps,
518
+ ref,
519
+ disabled,
520
+ "aria-disabled": disabled,
521
+ "data-variant": variant,
522
+ "data-icon-only": !children,
523
+ type,
524
+ onClick: handleClick,
525
+ className: cn(classNames),
526
+ children: [
527
+ icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, { spin: isLoading, icon }),
528
+ /* @__PURE__ */ jsxRuntime.jsx(reactSlot.Slottable, { children })
529
+ ]
530
+ }
531
+ );
532
+ };
533
+ var Clipboard = ({
534
+ ref,
535
+ text: textProp,
536
+ children,
537
+ tooltip = "Copy to Clipboard",
538
+ tooltipPlacement = "top",
539
+ tooltipVariant: tooltipVariantProp = "action",
540
+ asChild = false,
541
+ onClick,
542
+ className,
543
+ ...restButtonProps
544
+ }) => {
545
+ const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
546
+ const [state, setState] = react.useState("ready");
547
+ const text = typeof textProp === "function" ? textProp() : textProp;
548
+ const copy = async (text2) => {
549
+ try {
550
+ if (!document.hasFocus()) window.focus();
551
+ await copyToClipboard(text2);
552
+ setState("copied");
553
+ } catch {
554
+ setState("error");
555
+ }
556
+ };
557
+ const handleOnClick = (event) => {
558
+ if (text && state === "ready") void copy(text);
559
+ onClick?.(event);
560
+ };
561
+ const handleOnOpenChange = (open) => {
562
+ if (!open && state !== "ready") setState("ready");
563
+ setIsTooltipOpen(open);
564
+ };
565
+ const tooltipContent = (() => {
566
+ if (!text) return "Nothing to copy";
567
+ if (state === "error") return "Failed to copy";
568
+ if (state === "copied") return "Copied to Clipboard";
569
+ return tooltip;
570
+ })();
571
+ const tooltipVariant = state === "ready" && !!text ? tooltipVariantProp : "action";
572
+ return /* @__PURE__ */ jsxRuntime.jsxs(design.Tooltip.Root, { open: isTooltipOpen, onOpenChange: handleOnOpenChange, children: [
573
+ /* @__PURE__ */ jsxRuntime.jsx(
574
+ design.Tooltip.Trigger,
575
+ {
576
+ ...restButtonProps,
577
+ asChild,
578
+ keepOpenOnClick: true,
579
+ onClick: handleOnClick,
580
+ className: design.cn("tw-cursor-pointer", className),
581
+ ref,
582
+ children: children ?? text
583
+ }
584
+ ),
585
+ /* @__PURE__ */ jsxRuntime.jsx(
586
+ design.Tooltip.Content,
587
+ {
588
+ keepOpenOnPointerDownOutside: true,
589
+ placement: tooltipPlacement,
590
+ variant: tooltipVariant,
591
+ children: tooltipContent
592
+ }
593
+ )
594
+ ] });
595
+ };
596
+ var DEFAULT_ICON = "copy";
597
+ var ClipboardButton = ({
598
+ // clipboard props
599
+ text,
600
+ tooltip,
601
+ tooltipPlacement,
602
+ tooltipVariant,
603
+ // button props
604
+ icon = DEFAULT_ICON,
605
+ variant = "outline",
606
+ children,
607
+ ...rest
608
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
609
+ Clipboard,
610
+ {
611
+ asChild: true,
612
+ tooltip,
613
+ tooltipPlacement,
614
+ tooltipVariant,
615
+ text,
616
+ children: /* @__PURE__ */ jsxRuntime.jsx(Button, { ...rest, icon, variant, disabled: !text, children })
617
+ }
618
+ );
619
+ var MIN_SCALE = 0.5;
620
+ var MAX_SCALE = 3;
621
+ var ZOOM_STEP = 0.1;
622
+ var ZoomableSvg = ({ html, copyText, className }) => {
623
+ const containerRef = react.useRef(null);
624
+ const [scale, setScale] = react.useState(1);
625
+ const [translate, setTranslate] = react.useState({ x: 0, y: 0 });
626
+ const [isFullscreen, setIsFullscreen] = react.useState(false);
627
+ react.useEffect(() => {
628
+ if (!isFullscreen) return;
629
+ const onKeyDown = (e) => {
630
+ if (e.key === "Escape") {
631
+ e.stopPropagation();
632
+ setIsFullscreen(false);
633
+ }
634
+ };
635
+ document.addEventListener("keydown", onKeyDown, { capture: true });
636
+ return () => document.removeEventListener("keydown", onKeyDown, { capture: true });
637
+ }, [isFullscreen]);
638
+ const dragRef = react.useRef(null);
639
+ react.useEffect(() => {
640
+ const el = containerRef.current;
641
+ if (!el) return;
642
+ const onWheel = (e) => {
643
+ if (!e.ctrlKey && !e.metaKey) return;
644
+ e.preventDefault();
645
+ const delta = e.deltaY > 0 ? -ZOOM_STEP : ZOOM_STEP;
646
+ setScale((s) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, s + delta)));
647
+ };
648
+ el.addEventListener("wheel", onWheel, { passive: false });
649
+ return () => el.removeEventListener("wheel", onWheel);
650
+ }, []);
651
+ const didDragRef = react.useRef(false);
652
+ const handleMouseDown = react.useCallback(
653
+ (e) => {
654
+ if (e.button !== 0) return;
655
+ e.preventDefault();
656
+ didDragRef.current = false;
657
+ dragRef.current = {
658
+ startX: e.clientX,
659
+ startY: e.clientY,
660
+ startTx: translate.x,
661
+ startTy: translate.y
662
+ };
663
+ },
664
+ [translate]
665
+ );
666
+ const handleMouseMove = react.useCallback((e) => {
667
+ if (!dragRef.current) return;
668
+ didDragRef.current = true;
669
+ setTranslate({
670
+ x: dragRef.current.startTx + e.clientX - dragRef.current.startX,
671
+ y: dragRef.current.startTy + e.clientY - dragRef.current.startY
672
+ });
673
+ }, []);
674
+ const handleMouseUp = react.useCallback(() => {
675
+ dragRef.current = null;
676
+ }, []);
677
+ const handleReset = react.useCallback(() => {
678
+ setScale(1);
679
+ setTranslate({ x: 0, y: 0 });
680
+ }, []);
681
+ const isZoomed = Math.abs(scale - 1) > 1e-3 || translate.x !== 0 || translate.y !== 0;
682
+ const handleClick = react.useCallback((e) => {
683
+ if (didDragRef.current) {
684
+ e.stopPropagation();
685
+ }
686
+ }, []);
687
+ const stopPropagation = react.useCallback((e) => {
688
+ e.stopPropagation();
689
+ }, []);
690
+ const diagramContent = /* @__PURE__ */ jsxRuntime.jsxs(
691
+ "div",
692
+ {
693
+ role: "presentation",
694
+ className: cn("tw-group/zoom tw-relative", isFullscreen && "tw-h-full"),
695
+ onClick: handleClick,
696
+ children: [
697
+ /* @__PURE__ */ jsxRuntime.jsx(
698
+ "div",
699
+ {
700
+ role: "presentation",
701
+ ref: containerRef,
702
+ className: cn(
703
+ "tw-overflow-hidden tw-cursor-grab active:tw-cursor-grabbing tw-p-3",
704
+ isFullscreen && "tw-h-full"
705
+ ),
706
+ onMouseDown: handleMouseDown,
707
+ onMouseMove: handleMouseMove,
708
+ onMouseUp: handleMouseUp,
709
+ onMouseLeave: handleMouseUp,
710
+ children: /* @__PURE__ */ jsxRuntime.jsx(
711
+ "div",
712
+ {
713
+ className: cn(
714
+ "tw-flex tw-justify-center tw-origin-center",
715
+ isFullscreen && "tw-h-full [&>svg]:tw-h-full"
716
+ ),
717
+ style: { transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})` },
718
+ dangerouslySetInnerHTML: { __html: html }
719
+ }
720
+ )
721
+ }
722
+ ),
723
+ /* @__PURE__ */ jsxRuntime.jsxs(
724
+ "div",
725
+ {
726
+ role: "presentation",
727
+ className: "tw-absolute tw-right-1 tw-top-1 tw-flex tw-gap-1 tw-opacity-0 tw-transition-opacity group-hover/zoom:tw-opacity-100",
728
+ onClick: stopPropagation,
729
+ children: [
730
+ isZoomed && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { tooltip: "Reset zoom", placement: "top", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "small", variant: "outline", onClick: handleReset, argo: true, children: "Reset" }) }),
731
+ copyText && /* @__PURE__ */ jsxRuntime.jsx(
732
+ ClipboardButton,
733
+ {
734
+ text: copyText,
735
+ tooltip: "Copy code",
736
+ size: "icon-sm",
737
+ variant: "outline",
738
+ argo: true
739
+ }
740
+ ),
741
+ /* @__PURE__ */ jsxRuntime.jsx(
742
+ Tooltip,
743
+ {
744
+ tooltip: isFullscreen ? "Exit fullscreen" : "Fullscreen",
745
+ placement: "top",
746
+ triggerAsChild: true,
747
+ children: /* @__PURE__ */ jsxRuntime.jsx(
748
+ Button,
749
+ {
750
+ size: "icon-sm",
751
+ variant: "outline",
752
+ icon: isFullscreen ? "down-left-and-up-right-to-center" : "up-right-and-down-left-from-center",
753
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Fullscreen",
754
+ onClick: () => setIsFullscreen((f) => !f),
755
+ argo: true
756
+ }
757
+ )
758
+ }
759
+ )
760
+ ]
761
+ }
762
+ )
763
+ ]
764
+ }
765
+ );
766
+ if (isFullscreen) {
767
+ return /* @__PURE__ */ jsxRuntime.jsx(
768
+ "div",
769
+ {
770
+ role: "presentation",
771
+ className: "tw-fixed tw-inset-0 tw-z-[1060] tw-bg-neutral-50 tw-p-4",
772
+ onClick: stopPropagation,
773
+ children: diagramContent
774
+ }
775
+ );
776
+ }
777
+ return /* @__PURE__ */ jsxRuntime.jsx(
778
+ "div",
779
+ {
780
+ className: cn(
781
+ "tw-overflow-hidden tw-rounded-md tw-border tw-border-neutral-150 tw-bg-neutral-50",
782
+ className
783
+ ),
784
+ children: diagramContent
785
+ }
786
+ );
787
+ };
788
+ var mermaidPromise = null;
789
+ var getMermaid = () => {
790
+ if (!mermaidPromise) {
791
+ mermaidPromise = import('mermaid').then((m) => {
792
+ m.default.initialize({
793
+ startOnLoad: false,
794
+ securityLevel: "strict",
795
+ theme: "base",
796
+ themeVariables: {
797
+ primaryColor: colors__default.default.secondary[100],
798
+ primaryTextColor: colors__default.default.neutral[800],
799
+ primaryBorderColor: colors__default.default.secondary[700],
800
+ secondaryColor: colors__default.default.white,
801
+ secondaryTextColor: colors__default.default.neutral[800],
802
+ secondaryBorderColor: colors__default.default.neutral[150],
803
+ tertiaryColor: colors__default.default.warning[100],
804
+ tertiaryTextColor: colors__default.default.neutral[800],
805
+ tertiaryBorderColor: colors__default.default.warning[500],
806
+ lineColor: colors__default.default.neutral[300],
807
+ textColor: colors__default.default.neutral[800],
808
+ mainBkg: colors__default.default.secondary[100],
809
+ nodeBorder: colors__default.default.secondary[700],
810
+ clusterBkg: colors__default.default.white,
811
+ clusterBorder: colors__default.default.neutral[150],
812
+ titleColor: colors__default.default.neutral[800],
813
+ edgeLabelBackground: colors__default.default.white,
814
+ nodeTextColor: colors__default.default.neutral[800],
815
+ actorBorder: colors__default.default.secondary[700],
816
+ actorBkg: colors__default.default.secondary[100],
817
+ actorTextColor: colors__default.default.neutral[800],
818
+ actorLineColor: colors__default.default.neutral[300],
819
+ signalColor: colors__default.default.neutral[800],
820
+ signalTextColor: colors__default.default.neutral[800],
821
+ labelBoxBkgColor: colors__default.default.secondary[100],
822
+ labelBoxBorderColor: colors__default.default.secondary[700],
823
+ labelTextColor: colors__default.default.neutral[800],
824
+ loopTextColor: colors__default.default.neutral[800],
825
+ noteBorderColor: colors__default.default.warning[500],
826
+ noteBkgColor: colors__default.default.warning[100],
827
+ noteTextColor: colors__default.default.neutral[800],
828
+ sectionBkgColor: colors__default.default.secondary[100],
829
+ altSectionBkgColor: colors__default.default.white,
830
+ sectionBkgColor2: colors__default.default.neutral[100],
831
+ taskBorderColor: colors__default.default.secondary[700],
832
+ taskBkgColor: colors__default.default.secondary[100],
833
+ taskTextColor: colors__default.default.neutral[800],
834
+ taskTextDarkColor: colors__default.default.neutral[800],
835
+ taskTextLightColor: colors__default.default.neutral[800],
836
+ activeTaskBorderColor: colors__default.default.primary.DEFAULT,
837
+ activeTaskBkgColor: colors__default.default.secondary[200],
838
+ doneTaskBorderColor: colors__default.default.primary[600],
839
+ doneTaskBkgColor: colors__default.default.primary[100],
840
+ critBorderColor: colors__default.default.error[500],
841
+ critBkgColor: colors__default.default.error[100],
842
+ fontFamily: "Inter, system-ui, sans-serif",
843
+ fontSize: "14px"
844
+ }
845
+ });
846
+ return m;
847
+ }).catch((err) => {
848
+ mermaidPromise = null;
849
+ throw err;
850
+ });
851
+ }
852
+ return mermaidPromise;
853
+ };
854
+ var stripFontImports = (svg) => svg.replace(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*\);?\s*/g, "");
855
+ var tryFastRender = (code) => {
856
+ try {
857
+ return stripFontImports(
858
+ beautifulMermaid.renderMermaidSVG(code, {
859
+ bg: colors__default.default.white,
860
+ fg: colors__default.default.neutral[800],
861
+ transparent: true,
862
+ font: "Inter, system-ui, sans-serif"
863
+ })
864
+ );
865
+ } catch {
866
+ return null;
867
+ }
868
+ };
869
+ var makeResponsive = (svgString) => {
870
+ const viewBoxMatch = svgString.match(/viewBox="[^"]*\s([\d.]+)\s[\d.]+"/);
871
+ const vbWidth = viewBoxMatch ? Math.round(Number(viewBoxMatch[1])) : void 0;
872
+ let result = svgString.replace(/(<svg[^>]*?)\s+width="[^"]*"/i, '$1 width="100%"').replace(/(<svg[^>]*?)\s+height="[^"]*"/i, "$1");
873
+ if (!vbWidth) return result;
874
+ const hasStyle = /(<svg[^>]*?)\s+style="([^"]*)"/i.test(result);
875
+ if (hasStyle) {
876
+ result = result.replace(/(<svg[^>]*?)\s+style="([^"]*)"/i, (_m, pre, styles) => {
877
+ const cleaned = styles.replace(/max-width:\s*[^;"]*;?\s*/g, "").trim();
878
+ const combined = [cleaned, `max-width: ${vbWidth}px`].filter(Boolean).join("; ");
879
+ return `${pre} style="${combined}"`;
880
+ });
881
+ } else {
882
+ result = result.replace(/<svg/, `<svg style="max-width: ${vbWidth}px"`);
883
+ }
884
+ return result;
885
+ };
886
+ var RENDER_DEBOUNCE_MS = 300;
887
+ var svgCache = /* @__PURE__ */ new Map();
888
+ var MermaidDiagram = ({ code }) => {
889
+ const id = react.useId();
890
+ const [svg, setSvg] = react.useState(() => {
891
+ const cached = svgCache.get(code);
892
+ if (cached) return cached;
893
+ const fast = tryFastRender(code);
894
+ if (fast) {
895
+ svgCache.set(code, fast);
896
+ return fast;
897
+ }
898
+ return null;
899
+ });
900
+ const [renderFailed, setRenderFailed] = react.useState(false);
901
+ const debounceRef = react.useRef(null);
902
+ const renderIdRef = react.useRef(0);
903
+ const [prevCode, setPrevCode] = react.useState(code);
904
+ if (code !== prevCode) {
905
+ setPrevCode(code);
906
+ const cached = svgCache.get(code);
907
+ const fast = cached ?? tryFastRender(code);
908
+ if (fast && !cached) svgCache.set(code, fast);
909
+ setSvg(fast);
910
+ setRenderFailed(false);
911
+ }
912
+ react.useEffect(() => {
913
+ if (svgCache.has(code)) {
914
+ setSvg(svgCache.get(code));
915
+ setRenderFailed(false);
916
+ return;
917
+ }
918
+ const fastResult = tryFastRender(code);
919
+ if (fastResult) {
920
+ svgCache.set(code, fastResult);
921
+ setSvg(fastResult);
922
+ setRenderFailed(false);
923
+ return;
924
+ }
925
+ setSvg(null);
926
+ const currentRenderId = ++renderIdRef.current;
927
+ setRenderFailed(false);
928
+ if (debounceRef.current) {
929
+ clearTimeout(debounceRef.current);
930
+ }
931
+ debounceRef.current = setTimeout(() => {
932
+ getMermaid().then(async (mermaidModule) => {
933
+ if (renderIdRef.current !== currentRenderId) return;
934
+ const rendererId = `mermaid-${id.replaceAll(":", "")}`;
935
+ const container = document.createElement("div");
936
+ container.style.visibility = "hidden";
937
+ container.style.position = "absolute";
938
+ container.style.top = "-9999px";
939
+ container.style.width = "900px";
940
+ document.body.appendChild(container);
941
+ try {
942
+ const result = await mermaidModule.default.render(rendererId, code, container);
943
+ if (renderIdRef.current === currentRenderId && result) {
944
+ svgCache.set(code, result.svg);
945
+ setSvg(result.svg);
946
+ setRenderFailed(false);
947
+ }
948
+ } finally {
949
+ container.remove();
950
+ }
951
+ }).catch((err) => {
952
+ if (renderIdRef.current === currentRenderId) {
953
+ console.error("[MermaidDiagram] fallback failed:", err);
954
+ setSvg(null);
955
+ setRenderFailed(true);
956
+ }
957
+ });
958
+ }, RENDER_DEBOUNCE_MS);
959
+ const timer = debounceRef.current;
960
+ const renderId = renderIdRef;
961
+ return () => {
962
+ renderId.current++;
963
+ if (timer) {
964
+ clearTimeout(timer);
965
+ }
966
+ };
967
+ }, [code, id]);
968
+ const processedSvg = svg ? makeResponsive(svg) : null;
969
+ if (renderFailed) {
970
+ return /* @__PURE__ */ jsxRuntime.jsx(
971
+ "pre",
972
+ {
973
+ className: cn(
974
+ "tw-my-3 tw-overflow-auto tw-whitespace-pre-wrap tw-break-all",
975
+ "tw-py-3 tw-px-4",
976
+ "tw-bg-neutral-50",
977
+ "tw-rounded-md tw-text-neutral-400",
978
+ "tw-text-sm tw-font-mono"
979
+ ),
980
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code })
981
+ }
982
+ );
983
+ }
984
+ if (processedSvg) {
985
+ return /* @__PURE__ */ jsxRuntime.jsx(
986
+ ZoomableSvg,
987
+ {
988
+ html: processedSvg,
989
+ copyText: `\`\`\`mermaid
990
+ ${code}
991
+ \`\`\``,
992
+ className: "tw-my-3"
993
+ },
994
+ code
995
+ );
996
+ }
997
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tw-my-3 tw-overflow-hidden tw-rounded-md tw-border tw-border-neutral-150 tw-bg-neutral-50 tw-p-6", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "tw-h-40" }) });
998
+ };
999
+
1000
+ exports.MermaidDiagram = MermaidDiagram;
1001
+ //# sourceMappingURL=mermaid.cjs.map
1002
+ //# sourceMappingURL=mermaid.cjs.map