@almadar/ui 5.13.2 → 5.14.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.
@@ -6309,7 +6309,7 @@ var init_Modal = __esm({
6309
6309
  document.body.style.overflow = "";
6310
6310
  };
6311
6311
  }, [isOpen]);
6312
- if (!isOpen) return null;
6312
+ if (!isOpen || typeof document === "undefined") return null;
6313
6313
  const handleClose = () => {
6314
6314
  if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
6315
6315
  onClose();
@@ -6319,124 +6319,127 @@ var init_Modal = __esm({
6319
6319
  handleClose();
6320
6320
  }
6321
6321
  };
6322
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6323
- /* @__PURE__ */ jsxRuntime.jsx(
6324
- exports.Overlay,
6325
- {
6326
- isVisible: isOpen,
6327
- onClick: handleOverlayClick,
6328
- className: "z-40"
6329
- }
6330
- ),
6331
- /* @__PURE__ */ jsxRuntime.jsx(
6332
- exports.Box,
6333
- {
6334
- className: cn(
6335
- "fixed inset-0 z-50 pointer-events-none",
6336
- "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6337
- "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6338
- ),
6339
- children: /* @__PURE__ */ jsxRuntime.jsxs(
6340
- exports.Dialog,
6341
- {
6342
- ref: modalRef,
6343
- open: true,
6344
- className: cn(
6345
- // Reset browser-default dialog chrome — we own styling. `static`
6346
- // overrides the user-agent `position: absolute` so the parent
6347
- // flex container's `justify-center` actually centers the dialog
6348
- // (without this, the dialog drops out of flex flow and `m-0`
6349
- // kills the user-agent's `margin: auto` centering, pinning the
6350
- // dialog to top-left).
6351
- "static m-0 p-0 border-0 bg-transparent",
6352
- // Pre-existing dialog frame
6353
- "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6354
- // Desktop sizing + viewport-aware floor.
6355
- sizeClasses5[size],
6356
- minWidthClasses[size],
6357
- "max-h-[80vh]",
6358
- // Mobile: take the entire screen. Override desktop max-w cap,
6359
- // full height, no rounded corners, no min-width.
6360
- "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6361
- lookStyles2[look],
6362
- className
6363
- ),
6364
- style: dragY > 0 ? {
6365
- transform: `translateY(${dragY}px)`,
6366
- transition: isDragging.current ? "none" : "transform 200ms ease-out"
6367
- } : void 0,
6368
- ...title && { "aria-labelledby": "modal-title" },
6369
- children: [
6370
- /* @__PURE__ */ jsxRuntime.jsx(
6371
- exports.Box,
6372
- {
6373
- className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6374
- onPointerDown: (e) => {
6375
- if (!swipeDownToClose) return;
6376
- dragStartY.current = e.clientY;
6377
- isDragging.current = true;
6378
- e.target.setPointerCapture(e.pointerId);
6379
- },
6380
- onPointerMove: (e) => {
6381
- if (!isDragging.current) return;
6382
- const dy = Math.max(0, e.clientY - dragStartY.current);
6383
- setDragY(dy);
6384
- },
6385
- onPointerUp: () => {
6386
- if (!isDragging.current) return;
6387
- isDragging.current = false;
6388
- if (dragY > 100) {
6389
- handleClose();
6390
- }
6391
- setDragY(0);
6392
- },
6393
- onPointerCancel: () => {
6394
- isDragging.current = false;
6395
- setDragY(0);
6396
- },
6397
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "w-10 h-1 rounded-full bg-border" })
6398
- }
6322
+ return reactDom.createPortal(
6323
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6324
+ /* @__PURE__ */ jsxRuntime.jsx(
6325
+ exports.Overlay,
6326
+ {
6327
+ isVisible: isOpen,
6328
+ onClick: handleOverlayClick,
6329
+ className: "z-[1000]"
6330
+ }
6331
+ ),
6332
+ /* @__PURE__ */ jsxRuntime.jsx(
6333
+ exports.Box,
6334
+ {
6335
+ className: cn(
6336
+ "fixed inset-0 z-[1001] pointer-events-none",
6337
+ "flex items-start justify-center px-4 pb-4 pt-[10vh]",
6338
+ "max-sm:items-stretch max-sm:p-0 max-sm:pt-0"
6339
+ ),
6340
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
6341
+ exports.Dialog,
6342
+ {
6343
+ ref: modalRef,
6344
+ open: true,
6345
+ className: cn(
6346
+ // Reset browser-default dialog chrome we own styling. `static`
6347
+ // overrides the user-agent `position: absolute` so the parent
6348
+ // flex container's `justify-center` actually centers the dialog
6349
+ // (without this, the dialog drops out of flex flow and `m-0`
6350
+ // kills the user-agent's `margin: auto` centering, pinning the
6351
+ // dialog to top-left).
6352
+ "static m-0 p-0 border-0 bg-transparent",
6353
+ // Pre-existing dialog frame
6354
+ "pointer-events-auto w-full flex flex-col bg-surface border shadow-elevation-dialog rounded-container",
6355
+ // Desktop sizing + viewport-aware floor.
6356
+ sizeClasses5[size],
6357
+ minWidthClasses[size],
6358
+ "max-h-[80vh]",
6359
+ // Mobile: take the entire screen. Override desktop max-w cap,
6360
+ // full height, no rounded corners, no min-width.
6361
+ "max-sm:max-w-none max-sm:max-h-none max-sm:w-full max-sm:h-full max-sm:rounded-none",
6362
+ lookStyles2[look],
6363
+ className
6399
6364
  ),
6400
- (title || showCloseButton) && /* @__PURE__ */ jsxRuntime.jsxs(
6401
- exports.Box,
6402
- {
6403
- className: cn(
6404
- "px-6 py-4 flex items-center justify-between",
6405
- "border-b-[length:var(--border-width)] border-border"
6406
- ),
6407
- children: [
6408
- title && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6409
- showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
6410
- exports.Button,
6411
- {
6412
- variant: "ghost",
6413
- size: "sm",
6414
- icon: "x",
6415
- onClick: handleClose,
6416
- "data-event": "CLOSE",
6417
- "aria-label": "Close modal"
6365
+ style: dragY > 0 ? {
6366
+ transform: `translateY(${dragY}px)`,
6367
+ transition: isDragging.current ? "none" : "transform 200ms ease-out"
6368
+ } : void 0,
6369
+ ...title && { "aria-labelledby": "modal-title" },
6370
+ children: [
6371
+ /* @__PURE__ */ jsxRuntime.jsx(
6372
+ exports.Box,
6373
+ {
6374
+ className: "hidden max-sm:flex justify-center py-2 cursor-grab active:cursor-grabbing touch-none",
6375
+ onPointerDown: (e) => {
6376
+ if (!swipeDownToClose) return;
6377
+ dragStartY.current = e.clientY;
6378
+ isDragging.current = true;
6379
+ e.target.setPointerCapture(e.pointerId);
6380
+ },
6381
+ onPointerMove: (e) => {
6382
+ if (!isDragging.current) return;
6383
+ const dy = Math.max(0, e.clientY - dragStartY.current);
6384
+ setDragY(dy);
6385
+ },
6386
+ onPointerUp: () => {
6387
+ if (!isDragging.current) return;
6388
+ isDragging.current = false;
6389
+ if (dragY > 100) {
6390
+ handleClose();
6418
6391
  }
6419
- )
6420
- ]
6421
- }
6422
- ),
6423
- /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 overflow-y-auto p-6", children }),
6424
- footer && /* @__PURE__ */ jsxRuntime.jsx(
6425
- exports.Box,
6426
- {
6427
- className: cn(
6428
- "px-6 py-4 bg-muted",
6429
- "border-t-[length:var(--border-width)] border-border"
6430
- ),
6431
- children: footer
6432
- }
6433
- )
6434
- ]
6435
- }
6436
- )
6437
- }
6438
- )
6439
- ] });
6392
+ setDragY(0);
6393
+ },
6394
+ onPointerCancel: () => {
6395
+ isDragging.current = false;
6396
+ setDragY(0);
6397
+ },
6398
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "w-10 h-1 rounded-full bg-border" })
6399
+ }
6400
+ ),
6401
+ (title || showCloseButton) && /* @__PURE__ */ jsxRuntime.jsxs(
6402
+ exports.Box,
6403
+ {
6404
+ className: cn(
6405
+ "px-6 py-4 flex items-center justify-between",
6406
+ "border-b-[length:var(--border-width)] border-border"
6407
+ ),
6408
+ children: [
6409
+ title && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", as: "h2", id: "modal-title", children: title }),
6410
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
6411
+ exports.Button,
6412
+ {
6413
+ variant: "ghost",
6414
+ size: "sm",
6415
+ icon: "x",
6416
+ onClick: handleClose,
6417
+ "data-event": "CLOSE",
6418
+ "aria-label": "Close modal"
6419
+ }
6420
+ )
6421
+ ]
6422
+ }
6423
+ ),
6424
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 overflow-y-auto p-6", children }),
6425
+ footer && /* @__PURE__ */ jsxRuntime.jsx(
6426
+ exports.Box,
6427
+ {
6428
+ className: cn(
6429
+ "px-6 py-4 bg-muted",
6430
+ "border-t-[length:var(--border-width)] border-border"
6431
+ ),
6432
+ children: footer
6433
+ }
6434
+ )
6435
+ ]
6436
+ }
6437
+ )
6438
+ }
6439
+ )
6440
+ ] }),
6441
+ document.body
6442
+ );
6440
6443
  };
6441
6444
  exports.Modal.displayName = "Modal";
6442
6445
  }
@@ -8676,13 +8679,13 @@ var init_MapView = __esm({
8676
8679
  shadowSize: [41, 41]
8677
8680
  });
8678
8681
  L.Marker.prototype.options.icon = defaultIcon;
8679
- const { useEffect: useEffect72, useRef: useRef66, useCallback: useCallback128, useState: useState111 } = React80__namespace.default;
8682
+ const { useEffect: useEffect73, useRef: useRef67, useCallback: useCallback129, useState: useState112 } = React80__namespace.default;
8680
8683
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8681
8684
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8682
8685
  function MapUpdater({ centerLat, centerLng, zoom }) {
8683
8686
  const map = useMap();
8684
- const prevRef = useRef66({ centerLat, centerLng, zoom });
8685
- useEffect72(() => {
8687
+ const prevRef = useRef67({ centerLat, centerLng, zoom });
8688
+ useEffect73(() => {
8686
8689
  const prev = prevRef.current;
8687
8690
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
8688
8691
  map.setView([centerLat, centerLng], zoom);
@@ -8693,7 +8696,7 @@ var init_MapView = __esm({
8693
8696
  }
8694
8697
  function MapClickHandler({ onMapClick }) {
8695
8698
  const map = useMap();
8696
- useEffect72(() => {
8699
+ useEffect73(() => {
8697
8700
  if (!onMapClick) return;
8698
8701
  const handler = (e) => {
8699
8702
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -8721,8 +8724,8 @@ var init_MapView = __esm({
8721
8724
  showAttribution = true
8722
8725
  }) {
8723
8726
  const eventBus = useEventBus2();
8724
- const [clickedPosition, setClickedPosition] = useState111(null);
8725
- const handleMapClick = useCallback128((lat, lng) => {
8727
+ const [clickedPosition, setClickedPosition] = useState112(null);
8728
+ const handleMapClick = useCallback129((lat, lng) => {
8726
8729
  if (showClickedPin) {
8727
8730
  setClickedPosition({ lat, lng });
8728
8731
  }
@@ -8731,7 +8734,7 @@ var init_MapView = __esm({
8731
8734
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
8732
8735
  }
8733
8736
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
8734
- const handleMarkerClick = useCallback128((marker) => {
8737
+ const handleMarkerClick = useCallback129((marker) => {
8735
8738
  onMarkerClick?.(marker);
8736
8739
  if (markerClickEvent) {
8737
8740
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -12488,7 +12491,7 @@ var init_CodeBlock = __esm({
12488
12491
  };
12489
12492
  };
12490
12493
  }, [errorLines]);
12491
- const isFoldable = foldableProp ?? (language === "orb" || language === "json");
12494
+ const isFoldable = foldableProp ?? true;
12492
12495
  const [collapsed, setCollapsed] = React80.useState(() => /* @__PURE__ */ new Set());
12493
12496
  const foldRegions = React80.useMemo(
12494
12497
  () => isFoldable ? computeFoldRegions(code) : [],
@@ -12511,6 +12514,8 @@ var init_CodeBlock = __esm({
12511
12514
  collapsedRef.current = collapsed;
12512
12515
  const foldStartMapRef = React80.useRef(foldStartMap);
12513
12516
  foldStartMapRef.current = foldStartMap;
12517
+ const hiddenLinesRef = React80.useRef(hiddenLines);
12518
+ hiddenLinesRef.current = hiddenLines;
12514
12519
  const toggleFold = React80.useCallback((lineNum) => {
12515
12520
  setCollapsed((prev) => {
12516
12521
  const next = new Set(prev);
@@ -12623,6 +12628,60 @@ var init_CodeBlock = __esm({
12623
12628
  eventBus.emit("UI:COPY_CODE", { language, success: false });
12624
12629
  }
12625
12630
  };
12631
+ const handleSelectionCopy = React80.useCallback((e) => {
12632
+ if (hiddenLinesRef.current.size === 0) return;
12633
+ const sel = typeof window !== "undefined" ? window.getSelection() : null;
12634
+ if (!sel || sel.rangeCount === 0 || sel.isCollapsed) return;
12635
+ const lineOf = (node) => {
12636
+ const start = node instanceof HTMLElement ? node : node?.parentElement ?? null;
12637
+ const lineEl = start?.closest("[data-line]");
12638
+ if (!lineEl) return null;
12639
+ const n = parseInt(lineEl.getAttribute("data-line") ?? "", 10);
12640
+ return Number.isNaN(n) ? null : n;
12641
+ };
12642
+ const range = sel.getRangeAt(0);
12643
+ let a = lineOf(range.startContainer);
12644
+ let b = lineOf(range.endContainer);
12645
+ if (a === null || b === null) {
12646
+ const container = codeRef.current;
12647
+ if (!container) return;
12648
+ let min = Infinity, max = -Infinity;
12649
+ container.querySelectorAll("[data-line]").forEach((el) => {
12650
+ if (!sel.containsNode(el, true)) return;
12651
+ const n = parseInt(el.getAttribute("data-line") ?? "", 10);
12652
+ if (!Number.isNaN(n)) {
12653
+ min = Math.min(min, n);
12654
+ max = Math.max(max, n);
12655
+ }
12656
+ });
12657
+ if (min === Infinity) return;
12658
+ a = a ?? min;
12659
+ b = b ?? max;
12660
+ }
12661
+ if (a > b) [a, b] = [b, a];
12662
+ let touchesFold = false;
12663
+ for (let i = a; i <= b; i++) {
12664
+ if (hiddenLinesRef.current.has(i) || foldStartMapRef.current.has(i) && collapsedRef.current.has(i)) {
12665
+ touchesFold = true;
12666
+ break;
12667
+ }
12668
+ }
12669
+ if (!touchesFold) return;
12670
+ let endLine = b;
12671
+ let changed = true;
12672
+ while (changed) {
12673
+ changed = false;
12674
+ foldStartMapRef.current.forEach((region, start) => {
12675
+ if (start >= a && start <= endLine && collapsedRef.current.has(start) && region.end > endLine) {
12676
+ endLine = region.end;
12677
+ changed = true;
12678
+ }
12679
+ });
12680
+ }
12681
+ const full = code.split("\n").slice(a, endLine + 1).join("\n");
12682
+ e.clipboardData.setData("text/plain", full);
12683
+ e.preventDefault();
12684
+ }, [code]);
12626
12685
  const hasHeader = showLanguageBadge || showCopyButton;
12627
12686
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: `relative group ${className || ""}`, style: { display: "flex", flexDirection: "column", height: "100%" }, children: [
12628
12687
  hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -12773,6 +12832,7 @@ var init_CodeBlock = __esm({
12773
12832
  "div",
12774
12833
  {
12775
12834
  ref: scrollRef,
12835
+ onCopy: handleSelectionCopy,
12776
12836
  style: {
12777
12837
  flex: 1,
12778
12838
  minHeight: 0,
@@ -23832,6 +23892,242 @@ var init_InputGroup = __esm({
23832
23892
  exports.InputGroup.displayName = "InputGroup";
23833
23893
  }
23834
23894
  });
23895
+ function resolveAnchorRect(anchor) {
23896
+ if (typeof anchor === "string") {
23897
+ return document.querySelector(anchor)?.getBoundingClientRect() ?? null;
23898
+ }
23899
+ if (anchor instanceof DOMRect) return anchor;
23900
+ return anchor?.current?.getBoundingClientRect() ?? null;
23901
+ }
23902
+ function useAnchorRect(anchor, active) {
23903
+ const [rect, setRect] = React80.useState(null);
23904
+ const read = React80.useCallback(() => resolveAnchorRect(anchor), [anchor]);
23905
+ React80.useEffect(() => {
23906
+ if (!active || typeof document === "undefined") {
23907
+ setRect(null);
23908
+ return;
23909
+ }
23910
+ const update = () => setRect(read());
23911
+ update();
23912
+ window.addEventListener("scroll", update, true);
23913
+ window.addEventListener("resize", update);
23914
+ let raf = 0;
23915
+ let tries = 0;
23916
+ const poll = () => {
23917
+ const found = read();
23918
+ if (found) {
23919
+ setRect(found);
23920
+ } else if (tries++ < 40) {
23921
+ raf = requestAnimationFrame(poll);
23922
+ }
23923
+ };
23924
+ if (!read()) raf = requestAnimationFrame(poll);
23925
+ return () => {
23926
+ window.removeEventListener("scroll", update, true);
23927
+ window.removeEventListener("resize", update);
23928
+ if (raf) cancelAnimationFrame(raf);
23929
+ };
23930
+ }, [active, read]);
23931
+ return rect;
23932
+ }
23933
+ function placeCard(placement, rect, size) {
23934
+ const vw = typeof window !== "undefined" ? window.innerWidth : 1024;
23935
+ const vh = typeof window !== "undefined" ? window.innerHeight : 768;
23936
+ let top = 0;
23937
+ let left = 0;
23938
+ switch (placement) {
23939
+ case "top":
23940
+ top = rect.top - size.h - GAP;
23941
+ left = rect.left + rect.width / 2 - size.w / 2;
23942
+ break;
23943
+ case "left":
23944
+ left = rect.left - size.w - GAP;
23945
+ top = rect.top + rect.height / 2 - size.h / 2;
23946
+ break;
23947
+ case "right":
23948
+ left = rect.right + GAP;
23949
+ top = rect.top + rect.height / 2 - size.h / 2;
23950
+ break;
23951
+ case "bottom":
23952
+ default:
23953
+ top = rect.bottom + GAP;
23954
+ left = rect.left + rect.width / 2 - size.w / 2;
23955
+ break;
23956
+ }
23957
+ left = Math.max(EDGE, Math.min(left, vw - size.w - EDGE));
23958
+ top = Math.max(EDGE, Math.min(top, vh - size.h - EDGE));
23959
+ return { top, left };
23960
+ }
23961
+ var GAP, EDGE; exports.Coachmark = void 0;
23962
+ var init_Coachmark = __esm({
23963
+ "components/molecules/Coachmark.tsx"() {
23964
+ "use client";
23965
+ init_Box();
23966
+ init_Typography();
23967
+ init_Button();
23968
+ init_Icon();
23969
+ init_cn();
23970
+ GAP = 10;
23971
+ EDGE = 8;
23972
+ exports.Coachmark = ({
23973
+ open,
23974
+ anchor,
23975
+ placement = "bottom",
23976
+ title,
23977
+ children,
23978
+ onDismiss,
23979
+ onPrimary,
23980
+ primaryLabel,
23981
+ onSecondary,
23982
+ secondaryLabel,
23983
+ showBeacon = false,
23984
+ className
23985
+ }) => {
23986
+ const cardRef = React80.useRef(null);
23987
+ const rect = useAnchorRect(anchor, open);
23988
+ const [pos, setPos] = React80.useState(null);
23989
+ React80.useLayoutEffect(() => {
23990
+ if (!open || !rect || !cardRef.current) {
23991
+ setPos(null);
23992
+ return;
23993
+ }
23994
+ const size = {
23995
+ w: cardRef.current.offsetWidth,
23996
+ h: cardRef.current.offsetHeight
23997
+ };
23998
+ setPos(placeCard(placement, rect, size));
23999
+ }, [open, rect, placement, children, title]);
24000
+ if (!open || !rect || typeof document === "undefined") return null;
24001
+ const hasFooter = Boolean(onPrimary || onSecondary);
24002
+ const card = /* @__PURE__ */ jsxRuntime.jsxs(
24003
+ exports.Box,
24004
+ {
24005
+ ref: cardRef,
24006
+ bg: "surface",
24007
+ border: true,
24008
+ rounded: "lg",
24009
+ shadow: "xl",
24010
+ padding: "md",
24011
+ role: "dialog",
24012
+ "aria-label": title,
24013
+ className: cn(
24014
+ "fixed z-50 max-w-xs w-72 transition-opacity duration-150",
24015
+ pos ? "opacity-100" : "opacity-0",
24016
+ className
24017
+ ),
24018
+ style: pos ? { top: pos.top, left: pos.left } : { top: -9999, left: -9999 },
24019
+ children: [
24020
+ /* @__PURE__ */ jsxRuntime.jsx(
24021
+ "button",
24022
+ {
24023
+ type: "button",
24024
+ "aria-label": "Dismiss",
24025
+ onClick: onDismiss,
24026
+ className: "absolute top-2 right-2 text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)]",
24027
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: "close", size: "xs" })
24028
+ }
24029
+ ),
24030
+ title && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body1", weight: "semibold", className: "pr-6 mb-1", children: title }),
24031
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body2", color: "muted", as: "div", children }),
24032
+ hasFooter && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center justify-end gap-2", children: [
24033
+ onSecondary && /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "ghost", size: "sm", onClick: onSecondary, children: secondaryLabel ?? "Skip" }),
24034
+ onPrimary && /* @__PURE__ */ jsxRuntime.jsx(exports.Button, { variant: "primary", size: "sm", onClick: onPrimary, children: primaryLabel ?? "Got it" })
24035
+ ] })
24036
+ ]
24037
+ }
24038
+ );
24039
+ const beacon = showBeacon ? /* @__PURE__ */ jsxRuntime.jsx(
24040
+ "div",
24041
+ {
24042
+ className: "fixed z-50 pointer-events-none",
24043
+ style: {
24044
+ top: rect.top + rect.height / 2 - 6,
24045
+ left: rect.left + rect.width / 2 - 6
24046
+ },
24047
+ "aria-hidden": "true",
24048
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-3 w-3", children: [
24049
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--color-primary)] opacity-75" }),
24050
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex h-3 w-3 rounded-full bg-[var(--color-primary)]" })
24051
+ ] })
24052
+ }
24053
+ ) : null;
24054
+ return reactDom.createPortal(
24055
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
24056
+ beacon,
24057
+ card
24058
+ ] }),
24059
+ document.body
24060
+ );
24061
+ };
24062
+ exports.Coachmark.displayName = "Coachmark";
24063
+ }
24064
+ });
24065
+ var DIM; exports.OnboardingSpotlight = void 0;
24066
+ var init_OnboardingSpotlight = __esm({
24067
+ "components/molecules/OnboardingSpotlight.tsx"() {
24068
+ "use client";
24069
+ init_Coachmark();
24070
+ init_cn();
24071
+ DIM = "fixed z-[45] bg-black/60";
24072
+ exports.OnboardingSpotlight = ({
24073
+ steps,
24074
+ stepIndex,
24075
+ onNext,
24076
+ onSkip,
24077
+ onFinish,
24078
+ cutoutPadding = 6
24079
+ }) => {
24080
+ const step = steps[stepIndex];
24081
+ const rect = useAnchorRect(step?.anchor ?? "", Boolean(step));
24082
+ if (!step || typeof document === "undefined") return null;
24083
+ const isLast = stepIndex >= steps.length - 1;
24084
+ const backdrop = rect ? (() => {
24085
+ const p2 = cutoutPadding;
24086
+ const top = Math.max(0, rect.top - p2);
24087
+ const left = Math.max(0, rect.left - p2);
24088
+ const right = rect.right + p2;
24089
+ const bottom = rect.bottom + p2;
24090
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
24091
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DIM, style: { top: 0, left: 0, right: 0, height: top } }),
24092
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DIM, style: { top: bottom, left: 0, right: 0, bottom: 0 } }),
24093
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DIM, style: { top, left: 0, width: left, height: bottom - top } }),
24094
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DIM, style: { top, left: right, right: 0, height: bottom - top } })
24095
+ ] });
24096
+ })() : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(DIM, "inset-0") });
24097
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
24098
+ reactDom.createPortal(backdrop, document.body),
24099
+ /* @__PURE__ */ jsxRuntime.jsxs(
24100
+ exports.Coachmark,
24101
+ {
24102
+ open: true,
24103
+ anchor: step.anchor,
24104
+ placement: step.placement ?? "bottom",
24105
+ title: step.title,
24106
+ onDismiss: onSkip,
24107
+ onSecondary: onSkip,
24108
+ secondaryLabel: "Skip",
24109
+ onPrimary: isLast ? onFinish : onNext,
24110
+ primaryLabel: isLast ? "Done" : "Next",
24111
+ children: [
24112
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: step.body }),
24113
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-3 flex items-center gap-1.5", children: steps.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
24114
+ "span",
24115
+ {
24116
+ className: cn(
24117
+ "h-1.5 w-1.5 rounded-full",
24118
+ i === stepIndex ? "bg-[var(--color-primary)]" : "bg-[var(--color-border)]"
24119
+ )
24120
+ },
24121
+ i
24122
+ )) })
24123
+ ]
24124
+ }
24125
+ )
24126
+ ] });
24127
+ };
24128
+ exports.OnboardingSpotlight.displayName = "OnboardingSpotlight";
24129
+ }
24130
+ });
23835
24131
  function gateEnabled(level, ns = NAMESPACE) {
23836
24132
  return logger.isLogLevelEnabled(level, ns);
23837
24133
  }
@@ -34192,7 +34488,7 @@ var init_AvlPage = __esm({
34192
34488
  AvlPage.displayName = "AvlPage";
34193
34489
  }
34194
34490
  });
34195
- var NODE_W, NODE_H, GAP, ARROW_W, MiniStateMachine;
34491
+ var NODE_W, NODE_H, GAP2, ARROW_W, MiniStateMachine;
34196
34492
  var init_MiniStateMachine = __esm({
34197
34493
  "components/molecules/avl/MiniStateMachine.tsx"() {
34198
34494
  "use client";
@@ -34201,7 +34497,7 @@ var init_MiniStateMachine = __esm({
34201
34497
  init_types();
34202
34498
  NODE_W = 24;
34203
34499
  NODE_H = 16;
34204
- GAP = 8;
34500
+ GAP2 = 8;
34205
34501
  ARROW_W = 16;
34206
34502
  MiniStateMachine = ({ data, className }) => {
34207
34503
  const states = data.states;
@@ -34218,12 +34514,12 @@ var init_MiniStateMachine = __esm({
34218
34514
  for (const e of t.effects) effectTypes.add(e.type);
34219
34515
  }
34220
34516
  const effectList = Array.from(effectTypes).slice(0, 6);
34221
- const totalW = states.length * NODE_W + (states.length - 1) * (GAP + ARROW_W + GAP);
34517
+ const totalW = states.length * NODE_W + (states.length - 1) * (GAP2 + ARROW_W + GAP2);
34222
34518
  const svgW = Math.max(totalW + 4, 60);
34223
34519
  const svgH = NODE_H + (effectList.length > 0 ? 18 : 4);
34224
34520
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: svgW, height: svgH, viewBox: `0 0 ${svgW} ${svgH}`, className, children: [
34225
34521
  states.map((s, i) => {
34226
- const x = 2 + i * (NODE_W + GAP + ARROW_W + GAP);
34522
+ const x = 2 + i * (NODE_W + GAP2 + ARROW_W + GAP2);
34227
34523
  const tc = transitionCounts[s.name] ?? 0;
34228
34524
  const role = getStateRole(s.name, s.isInitial, s.isTerminal, tc, maxTC);
34229
34525
  return /* @__PURE__ */ jsxRuntime.jsxs(React80__namespace.default.Fragment, { children: [
@@ -34244,9 +34540,9 @@ var init_MiniStateMachine = __esm({
34244
34540
  /* @__PURE__ */ jsxRuntime.jsx(
34245
34541
  "line",
34246
34542
  {
34247
- x1: x + NODE_W + GAP,
34543
+ x1: x + NODE_W + GAP2,
34248
34544
  y1: NODE_H / 2,
34249
- x2: x + NODE_W + GAP + ARROW_W - 3,
34545
+ x2: x + NODE_W + GAP2 + ARROW_W - 3,
34250
34546
  y2: NODE_H / 2,
34251
34547
  stroke: "var(--color-muted-foreground)",
34252
34548
  strokeWidth: 1,
@@ -34256,7 +34552,7 @@ var init_MiniStateMachine = __esm({
34256
34552
  /* @__PURE__ */ jsxRuntime.jsx(
34257
34553
  "polygon",
34258
34554
  {
34259
- points: `${x + NODE_W + GAP + ARROW_W - 3},${NODE_H / 2 - 2.5} ${x + NODE_W + GAP + ARROW_W},${NODE_H / 2} ${x + NODE_W + GAP + ARROW_W - 3},${NODE_H / 2 + 2.5}`,
34555
+ points: `${x + NODE_W + GAP2 + ARROW_W - 3},${NODE_H / 2 - 2.5} ${x + NODE_W + GAP2 + ARROW_W},${NODE_H / 2} ${x + NODE_W + GAP2 + ARROW_W - 3},${NODE_H / 2 + 2.5}`,
34260
34556
  fill: "var(--color-muted-foreground)",
34261
34557
  opacity: 0.4
34262
34558
  }
@@ -34403,6 +34699,8 @@ var init_molecules = __esm({
34403
34699
  init_Modal();
34404
34700
  init_Pagination();
34405
34701
  init_Popover();
34702
+ init_Coachmark();
34703
+ init_OnboardingSpotlight();
34406
34704
  init_RelationSelect();
34407
34705
  init_SearchInput();
34408
34706
  init_SidePanel();
@@ -50817,6 +51115,7 @@ exports.transitionAnimation = transitionAnimation;
50817
51115
  exports.updateEntity = updateEntity;
50818
51116
  exports.updateSingleton = updateSingleton;
50819
51117
  exports.useAgentChat = useAgentChat;
51118
+ exports.useAnchorRect = useAnchorRect;
50820
51119
  exports.useAuthContext = useAuthContext;
50821
51120
  exports.useBattleState = useBattleState;
50822
51121
  exports.useCamera = useCamera;