@yoamigo.com/core 0.4.1 → 0.4.2

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +14 -1
  2. package/dist/index.js +1146 -465
  3. package/package.json +1 -2
package/dist/index.js CHANGED
@@ -1143,6 +1143,16 @@ function ContentStoreProvider({
1143
1143
  (fieldId) => changeSourceMap[fieldId] || "initial",
1144
1144
  [changeSourceMap]
1145
1145
  );
1146
+ const clearChangeSource = useCallback(
1147
+ (fieldId) => {
1148
+ setChangeSourceMap((prev) => {
1149
+ const next = { ...prev };
1150
+ delete next[fieldId];
1151
+ return next;
1152
+ });
1153
+ },
1154
+ []
1155
+ );
1146
1156
  const setMode = useCallback(
1147
1157
  (newMode) => {
1148
1158
  setModeState(newMode);
@@ -1245,6 +1255,7 @@ function ContentStoreProvider({
1245
1255
  getValue,
1246
1256
  setValue,
1247
1257
  getChangeSource,
1258
+ clearChangeSource,
1248
1259
  mode,
1249
1260
  setMode,
1250
1261
  subscribe,
@@ -1321,55 +1332,106 @@ function ContentStoreProvider2({ children, initialContent }) {
1321
1332
  }
1322
1333
 
1323
1334
  // src/components/YaText.tsx
1324
- import { useEffect as useEffect6, useRef as useRef6, useState as useState5, useCallback as useCallback7 } from "react";
1325
- import { createPortal as createPortal3 } from "react-dom";
1335
+ import { useEffect as useEffect7, useRef as useRef8, useState as useState7, useCallback as useCallback9 } from "react";
1336
+ import { createPortal as createPortal4 } from "react-dom";
1326
1337
  import { useEditor, EditorContent } from "@tiptap/react";
1327
1338
 
1328
1339
  // src/components/ControlledBubbleMenu.tsx
1329
- import { useFloating, autoUpdate, offset, flip, shift } from "@floating-ui/react";
1330
1340
  import { isNodeSelection, posToDOMRect } from "@tiptap/core";
1331
- import { useLayoutEffect } from "react";
1341
+ import { useLayoutEffect, useState as useState2, useRef as useRef2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
1332
1342
  import { createPortal } from "react-dom";
1333
1343
  import { jsx as jsx3 } from "react/jsx-runtime";
1334
1344
  function ControlledBubbleMenu({ editor, open, children, className }) {
1335
- const { floatingStyles, refs, isPositioned } = useFloating({
1336
- open,
1337
- // Required for isPositioned to work
1338
- strategy: "fixed",
1339
- whileElementsMounted: autoUpdate,
1340
- placement: "top",
1341
- middleware: [
1342
- offset({ mainAxis: 8 }),
1343
- flip({
1344
- padding: 8,
1345
- fallbackPlacements: ["bottom", "top-start", "bottom-start", "top-end", "bottom-end"]
1346
- }),
1347
- shift({ padding: 8 })
1348
- ]
1349
- });
1350
- useLayoutEffect(() => {
1351
- if (!open) return;
1345
+ const menuRef = useRef2(null);
1346
+ const [position, setPosition] = useState2(null);
1347
+ const [isMounted, setIsMounted] = useState2(false);
1348
+ useEffect2(() => {
1349
+ setIsMounted(true);
1350
+ }, []);
1351
+ const getSelectionRect = useCallback2(() => {
1352
+ if (!editor.view) return null;
1352
1353
  const { ranges } = editor.state.selection;
1353
1354
  const from = Math.min(...ranges.map((range) => range.$from.pos));
1354
1355
  const to = Math.max(...ranges.map((range) => range.$to.pos));
1355
- refs.setReference({
1356
- getBoundingClientRect() {
1357
- if (isNodeSelection(editor.state.selection)) {
1358
- const node = editor.view.nodeDOM(from);
1359
- if (node) return node.getBoundingClientRect();
1360
- }
1361
- return posToDOMRect(editor.view, from, to);
1362
- }
1363
- });
1364
- }, [refs, editor.view, editor.state.selection, open]);
1365
- if (!open) return null;
1356
+ if (isNodeSelection(editor.state.selection)) {
1357
+ const node = editor.view.nodeDOM(from);
1358
+ if (node) return node.getBoundingClientRect();
1359
+ }
1360
+ return posToDOMRect(editor.view, from, to);
1361
+ }, [editor]);
1362
+ const calculatePosition = useCallback2(() => {
1363
+ const selectionRect = getSelectionRect();
1364
+ if (!selectionRect) return null;
1365
+ const gap = 8;
1366
+ const menuHeight = 44;
1367
+ const menuWidth = 300;
1368
+ const padding = 8;
1369
+ let placement = "top";
1370
+ let top = selectionRect.top - menuHeight - gap;
1371
+ let left = selectionRect.left + selectionRect.width / 2 - menuWidth / 2;
1372
+ if (top < padding) {
1373
+ placement = "bottom";
1374
+ top = selectionRect.bottom + gap;
1375
+ }
1376
+ if (left < padding) {
1377
+ left = padding;
1378
+ } else if (left + menuWidth > window.innerWidth - padding) {
1379
+ left = window.innerWidth - menuWidth - padding;
1380
+ }
1381
+ return { top, left, placement, adjusted: false };
1382
+ }, [getSelectionRect]);
1383
+ useLayoutEffect(() => {
1384
+ if (!open) {
1385
+ setPosition(null);
1386
+ return;
1387
+ }
1388
+ const updatePosition = () => {
1389
+ const pos = calculatePosition();
1390
+ setPosition(pos);
1391
+ };
1392
+ updatePosition();
1393
+ const handleSelectionUpdate = () => {
1394
+ if (open) updatePosition();
1395
+ };
1396
+ editor.on("selectionUpdate", handleSelectionUpdate);
1397
+ editor.on("transaction", handleSelectionUpdate);
1398
+ window.addEventListener("scroll", updatePosition, true);
1399
+ window.addEventListener("resize", updatePosition);
1400
+ return () => {
1401
+ editor.off("selectionUpdate", handleSelectionUpdate);
1402
+ editor.off("transaction", handleSelectionUpdate);
1403
+ window.removeEventListener("scroll", updatePosition, true);
1404
+ window.removeEventListener("resize", updatePosition);
1405
+ };
1406
+ }, [open, editor, calculatePosition]);
1407
+ useLayoutEffect(() => {
1408
+ if (!open || !menuRef.current || !position || position.adjusted) return;
1409
+ const menuRect = menuRef.current.getBoundingClientRect();
1410
+ const padding = 8;
1411
+ let adjustedLeft = position.left;
1412
+ let adjustedTop = position.top;
1413
+ if (menuRect.right > window.innerWidth - padding) {
1414
+ adjustedLeft -= menuRect.right - window.innerWidth + padding;
1415
+ }
1416
+ if (menuRect.left < padding) {
1417
+ adjustedLeft += padding - menuRect.left;
1418
+ }
1419
+ if (adjustedLeft !== position.left || adjustedTop !== position.top) {
1420
+ setPosition((prev) => prev ? { ...prev, left: adjustedLeft, top: adjustedTop, adjusted: true } : null);
1421
+ } else {
1422
+ setPosition((prev) => prev ? { ...prev, adjusted: true } : null);
1423
+ }
1424
+ }, [open, position]);
1425
+ if (!open || !isMounted || !position) return null;
1366
1426
  const style = {
1367
- ...floatingStyles,
1368
- opacity: isPositioned ? 1 : 0,
1427
+ position: "fixed",
1428
+ top: position.top,
1429
+ left: position.left,
1430
+ opacity: 1,
1369
1431
  transition: "opacity 0.15s ease"
1370
1432
  };
1371
1433
  return createPortal(
1372
- /* @__PURE__ */ jsx3("div", { ref: refs.setFloating, style, className, children }),
1434
+ /* @__PURE__ */ jsx3("div", { ref: menuRef, style, className, children }),
1373
1435
  document.body
1374
1436
  );
1375
1437
  }
@@ -1381,7 +1443,7 @@ import { TextStyle } from "@tiptap/extension-text-style";
1381
1443
  import { Extension } from "@tiptap/core";
1382
1444
 
1383
1445
  // src/components/SafeHtml.tsx
1384
- import { useEffect as useEffect2, useRef as useRef2, useState as useState2, useCallback as useCallback2 } from "react";
1446
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3, useCallback as useCallback3 } from "react";
1385
1447
  import { createPortal as createPortal2 } from "react-dom";
1386
1448
  import DOMPurify from "dompurify";
1387
1449
  import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
@@ -1485,10 +1547,10 @@ function LinkPopover({
1485
1547
  );
1486
1548
  }
1487
1549
  function SafeHtml({ content, className, mode = "read-only" }) {
1488
- const containerRef = useRef2(null);
1489
- const showTimerRef = useRef2(void 0);
1490
- const hideTimerRef = useRef2(void 0);
1491
- const [popoverState, setPopoverState] = useState2({
1550
+ const containerRef = useRef3(null);
1551
+ const showTimerRef = useRef3(void 0);
1552
+ const hideTimerRef = useRef3(void 0);
1553
+ const [popoverState, setPopoverState] = useState3({
1492
1554
  isVisible: false,
1493
1555
  href: "",
1494
1556
  displayText: "",
@@ -1499,20 +1561,20 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1499
1561
  ALLOWED_TAGS,
1500
1562
  ALLOWED_ATTR
1501
1563
  });
1502
- const hidePopover = useCallback2(() => {
1564
+ const hidePopover = useCallback3(() => {
1503
1565
  clearTimeout(showTimerRef.current);
1504
1566
  setPopoverState((prev) => ({ ...prev, isVisible: false }));
1505
1567
  }, []);
1506
- const scheduleHide = useCallback2(() => {
1568
+ const scheduleHide = useCallback3(() => {
1507
1569
  clearTimeout(showTimerRef.current);
1508
1570
  hideTimerRef.current = window.setTimeout(() => {
1509
1571
  hidePopover();
1510
1572
  }, 100);
1511
1573
  }, [hidePopover]);
1512
- const cancelHide = useCallback2(() => {
1574
+ const cancelHide = useCallback3(() => {
1513
1575
  clearTimeout(hideTimerRef.current);
1514
1576
  }, []);
1515
- const handlePopoverClick = useCallback2(() => {
1577
+ const handlePopoverClick = useCallback3(() => {
1516
1578
  if (popoverState.isExternal) {
1517
1579
  window.open(popoverState.href, "_blank", "noopener,noreferrer");
1518
1580
  } else {
@@ -1520,7 +1582,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1520
1582
  }
1521
1583
  hidePopover();
1522
1584
  }, [popoverState.href, popoverState.isExternal, hidePopover]);
1523
- useEffect2(() => {
1585
+ useEffect3(() => {
1524
1586
  if (mode !== "inline-edit" || !containerRef.current) return;
1525
1587
  const container = containerRef.current;
1526
1588
  const handleMouseOver = (e) => {
@@ -1606,10 +1668,10 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1606
1668
  import { useMemo as useMemo4 } from "react";
1607
1669
 
1608
1670
  // src/hooks/useAIEditAnimation.ts
1609
- import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4, useMemo as useMemo3 } from "react";
1671
+ import { useState as useState4, useEffect as useEffect4, useRef as useRef5, useCallback as useCallback5, useMemo as useMemo3 } from "react";
1610
1672
 
1611
1673
  // src/contexts/AIEditContext.tsx
1612
- import { createContext as createContext3, useContext as useContext3, useCallback as useCallback3, useRef as useRef3, useMemo as useMemo2 } from "react";
1674
+ import { createContext as createContext3, useContext as useContext3, useCallback as useCallback4, useRef as useRef4, useMemo as useMemo2 } from "react";
1613
1675
  import { jsx as jsx5 } from "react/jsx-runtime";
1614
1676
  var AIEditContext = createContext3(null);
1615
1677
  function useAIEditContext() {
@@ -1623,17 +1685,17 @@ function useAIEditContextOptional() {
1623
1685
  return useContext3(AIEditContext);
1624
1686
  }
1625
1687
  function AIEditProvider({ children, staggerDelay = 100 }) {
1626
- const animationsRef = useRef3(/* @__PURE__ */ new Map());
1627
- const listenersRef = useRef3(/* @__PURE__ */ new Map());
1628
- const queueRef = useRef3([]);
1629
- const processingRef = useRef3(false);
1630
- const notifyListeners = useCallback3((fieldId) => {
1688
+ const animationsRef = useRef4(/* @__PURE__ */ new Map());
1689
+ const listenersRef = useRef4(/* @__PURE__ */ new Map());
1690
+ const queueRef = useRef4([]);
1691
+ const processingRef = useRef4(false);
1692
+ const notifyListeners = useCallback4((fieldId) => {
1631
1693
  const listeners = listenersRef.current.get(fieldId);
1632
1694
  if (listeners) {
1633
1695
  listeners.forEach((listener) => listener());
1634
1696
  }
1635
1697
  }, []);
1636
- const processQueue = useCallback3(() => {
1698
+ const processQueue = useCallback4(() => {
1637
1699
  if (processingRef.current || queueRef.current.length === 0) return;
1638
1700
  processingRef.current = true;
1639
1701
  const fieldId = queueRef.current.shift();
@@ -1648,7 +1710,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1648
1710
  processQueue();
1649
1711
  }, staggerDelay);
1650
1712
  }, [staggerDelay, notifyListeners]);
1651
- const queueAnimation = useCallback3(
1713
+ const queueAnimation = useCallback4(
1652
1714
  (fieldId, config) => {
1653
1715
  const existing = animationsRef.current.get(fieldId);
1654
1716
  if (existing?.status === "animating") {
@@ -1671,7 +1733,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1671
1733
  },
1672
1734
  [notifyListeners, processQueue]
1673
1735
  );
1674
- const cancelAnimation = useCallback3(
1736
+ const cancelAnimation = useCallback4(
1675
1737
  (fieldId) => {
1676
1738
  const state = animationsRef.current.get(fieldId);
1677
1739
  if (state) {
@@ -1685,14 +1747,14 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1685
1747
  },
1686
1748
  [notifyListeners]
1687
1749
  );
1688
- const isAnimating = useCallback3((fieldId) => {
1750
+ const isAnimating = useCallback4((fieldId) => {
1689
1751
  const state = animationsRef.current.get(fieldId);
1690
1752
  return state?.status === "animating" || state?.status === "pending";
1691
1753
  }, []);
1692
- const getAnimationState = useCallback3((fieldId) => {
1754
+ const getAnimationState = useCallback4((fieldId) => {
1693
1755
  return animationsRef.current.get(fieldId);
1694
1756
  }, []);
1695
- const subscribe = useCallback3((fieldId, listener) => {
1757
+ const subscribe = useCallback4((fieldId, listener) => {
1696
1758
  let listeners = listenersRef.current.get(fieldId);
1697
1759
  if (!listeners) {
1698
1760
  listeners = /* @__PURE__ */ new Set();
@@ -1706,7 +1768,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1706
1768
  }
1707
1769
  };
1708
1770
  }, []);
1709
- const completeAnimation = useCallback3(
1771
+ const completeAnimation = useCallback4(
1710
1772
  (fieldId) => {
1711
1773
  const state = animationsRef.current.get(fieldId);
1712
1774
  if (state) {
@@ -1739,16 +1801,16 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1739
1801
  function useAIEditAnimation(fieldId, value, options) {
1740
1802
  const { enabled = true, strategy, maxDuration = 2e3, onStart, onComplete } = options;
1741
1803
  const context = useAIEditContextOptional();
1742
- const { getChangeSource } = useContentStore();
1743
- const previousValueRef = useRef4(value);
1744
- const isFirstRender = useRef4(true);
1745
- const [phase, setPhase] = useState3("idle");
1746
- const [progress, setProgress] = useState3(0);
1747
- const [displayValue, setDisplayValue] = useState3(value);
1748
- const metadataRef = useRef4(null);
1749
- const animationFrameRef = useRef4(null);
1750
- const startTimeRef = useRef4(0);
1751
- const cancel = useCallback4(() => {
1804
+ const { getChangeSource, clearChangeSource } = useContentStore();
1805
+ const previousValueRef = useRef5(value);
1806
+ const isFirstRender = useRef5(true);
1807
+ const [phase, setPhase] = useState4("idle");
1808
+ const [progress, setProgress] = useState4(0);
1809
+ const [displayValue, setDisplayValue] = useState4(value);
1810
+ const metadataRef = useRef5(null);
1811
+ const animationFrameRef = useRef5(null);
1812
+ const startTimeRef = useRef5(0);
1813
+ const cancel = useCallback5(() => {
1752
1814
  if (animationFrameRef.current !== null) {
1753
1815
  cancelAnimationFrame(animationFrameRef.current);
1754
1816
  animationFrameRef.current = null;
@@ -1759,7 +1821,7 @@ function useAIEditAnimation(fieldId, value, options) {
1759
1821
  metadataRef.current = null;
1760
1822
  context?.cancelAnimation(fieldId);
1761
1823
  }, [value, context, fieldId]);
1762
- const runAnimation = useCallback4(() => {
1824
+ const runAnimation = useCallback5(() => {
1763
1825
  if (!metadataRef.current) return;
1764
1826
  const metadata = metadataRef.current;
1765
1827
  const elapsed = performance.now() - startTimeRef.current;
@@ -1774,6 +1836,7 @@ function useAIEditAnimation(fieldId, value, options) {
1774
1836
  onComplete?.();
1775
1837
  setTimeout(() => {
1776
1838
  setPhase("idle");
1839
+ clearChangeSource(fieldId);
1777
1840
  }, 400);
1778
1841
  return;
1779
1842
  }
@@ -1782,8 +1845,8 @@ function useAIEditAnimation(fieldId, value, options) {
1782
1845
  const interpolatedValue = strategy.interpolate(metadata, currentProgress);
1783
1846
  setDisplayValue(interpolatedValue);
1784
1847
  animationFrameRef.current = requestAnimationFrame(runAnimation);
1785
- }, [strategy, maxDuration, context, fieldId, onComplete]);
1786
- useEffect3(() => {
1848
+ }, [strategy, maxDuration, context, fieldId, onComplete, clearChangeSource]);
1849
+ useEffect4(() => {
1787
1850
  if (isFirstRender.current) {
1788
1851
  isFirstRender.current = false;
1789
1852
  previousValueRef.current = value;
@@ -1801,6 +1864,7 @@ function useAIEditAnimation(fieldId, value, options) {
1801
1864
  setPhase("complete");
1802
1865
  setTimeout(() => {
1803
1866
  setPhase("idle");
1867
+ clearChangeSource(fieldId);
1804
1868
  }, 400);
1805
1869
  return;
1806
1870
  }
@@ -1832,8 +1896,8 @@ function useAIEditAnimation(fieldId, value, options) {
1832
1896
  cancelAnimationFrame(animationFrameRef.current);
1833
1897
  }
1834
1898
  };
1835
- }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation, getChangeSource]);
1836
- useEffect3(() => {
1899
+ }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation, getChangeSource, clearChangeSource]);
1900
+ useEffect4(() => {
1837
1901
  return () => {
1838
1902
  if (animationFrameRef.current !== null) {
1839
1903
  cancelAnimationFrame(animationFrameRef.current);
@@ -2213,8 +2277,8 @@ function ChevronDownIcon({ size = 12, className }) {
2213
2277
  }
2214
2278
 
2215
2279
  // src/components/BubbleDropdown.tsx
2216
- import { useEffect as useEffect4 } from "react";
2217
- import { useFloating as useFloating2, autoUpdate as autoUpdate2, offset as offset2, flip as flip2, shift as shift2, useClick, useDismiss, useInteractions, FloatingPortal } from "@floating-ui/react";
2280
+ import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useState as useState5, useRef as useRef6, useCallback as useCallback6 } from "react";
2281
+ import { createPortal as createPortal3 } from "react-dom";
2218
2282
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
2219
2283
  function BubbleDropdown({
2220
2284
  label,
@@ -2224,29 +2288,66 @@ function BubbleDropdown({
2224
2288
  triggerClassName = "",
2225
2289
  panelClassName = ""
2226
2290
  }) {
2227
- const { refs, floatingStyles, context, isPositioned } = useFloating2({
2228
- open,
2229
- onOpenChange,
2230
- placement: "bottom-start",
2231
- strategy: "fixed",
2232
- whileElementsMounted: autoUpdate2,
2233
- middleware: [
2234
- offset2({ mainAxis: 4 }),
2235
- flip2({
2236
- padding: 8,
2237
- fallbackPlacements: ["bottom-end", "top-start", "top-end"]
2238
- }),
2239
- shift2({ padding: 8 })
2240
- ]
2241
- });
2242
- const click = useClick(context);
2243
- const dismiss = useDismiss(context, {
2244
- // Don't dismiss on ancestor scroll - we're inside a portaled bubble menu
2245
- ancestorScroll: false
2246
- });
2247
- const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
2248
- useEffect4(() => {
2291
+ const triggerRef = useRef6(null);
2292
+ const panelRef = useRef6(null);
2293
+ const [position, setPosition] = useState5(null);
2294
+ const [isMounted, setIsMounted] = useState5(false);
2295
+ useEffect5(() => {
2296
+ setIsMounted(true);
2297
+ }, []);
2298
+ const calculatePosition = useCallback6(() => {
2299
+ if (!triggerRef.current) return null;
2300
+ const triggerRect = triggerRef.current.getBoundingClientRect();
2301
+ const gap = 4;
2302
+ const padding = 8;
2303
+ let top = triggerRect.bottom + gap;
2304
+ let left = triggerRect.left;
2305
+ const estimatedWidth = 150;
2306
+ if (left + estimatedWidth > window.innerWidth - padding) {
2307
+ left = window.innerWidth - estimatedWidth - padding;
2308
+ }
2309
+ if (left < padding) {
2310
+ left = padding;
2311
+ }
2312
+ return { top, left, adjusted: false };
2313
+ }, []);
2314
+ useEffect5(() => {
2315
+ if (open) {
2316
+ const pos = calculatePosition();
2317
+ setPosition(pos);
2318
+ } else {
2319
+ setPosition(null);
2320
+ }
2321
+ }, [open, calculatePosition]);
2322
+ useLayoutEffect2(() => {
2323
+ if (!open || !panelRef.current || !position || position.adjusted) return;
2324
+ const panelRect = panelRef.current.getBoundingClientRect();
2325
+ const padding = 8;
2326
+ let adjustedLeft = position.left;
2327
+ let adjustedTop = position.top;
2328
+ if (panelRect.right > window.innerWidth - padding) {
2329
+ adjustedLeft -= panelRect.right - window.innerWidth + padding;
2330
+ }
2331
+ if (panelRect.bottom > window.innerHeight - padding) {
2332
+ const triggerRect = triggerRef.current?.getBoundingClientRect();
2333
+ if (triggerRect) {
2334
+ adjustedTop = triggerRect.top - panelRect.height - 4;
2335
+ }
2336
+ }
2337
+ if (adjustedLeft !== position.left || adjustedTop !== position.top) {
2338
+ setPosition({ top: adjustedTop, left: adjustedLeft, adjusted: true });
2339
+ } else {
2340
+ setPosition((prev) => prev ? { ...prev, adjusted: true } : null);
2341
+ }
2342
+ }, [open, position]);
2343
+ useEffect5(() => {
2249
2344
  if (!open) return;
2345
+ const handleClickOutside = (e) => {
2346
+ if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) {
2347
+ return;
2348
+ }
2349
+ onOpenChange(false);
2350
+ };
2250
2351
  const handleKeyDown = (e) => {
2251
2352
  if (e.key === "Escape") {
2252
2353
  e.preventDefault();
@@ -2254,16 +2355,19 @@ function BubbleDropdown({
2254
2355
  onOpenChange(false);
2255
2356
  }
2256
2357
  };
2358
+ const timeoutId = setTimeout(() => {
2359
+ document.addEventListener("mousedown", handleClickOutside);
2360
+ }, 0);
2257
2361
  document.addEventListener("keydown", handleKeyDown);
2258
- return () => document.removeEventListener("keydown", handleKeyDown);
2362
+ return () => {
2363
+ clearTimeout(timeoutId);
2364
+ document.removeEventListener("mousedown", handleClickOutside);
2365
+ document.removeEventListener("keydown", handleKeyDown);
2366
+ };
2259
2367
  }, [open, onOpenChange]);
2260
- const panelStyle = {
2261
- ...floatingStyles,
2262
- opacity: isPositioned ? 1 : 0,
2263
- transition: "opacity 0.15s ease"
2264
- };
2265
2368
  const handleTriggerClick = (e) => {
2266
2369
  e.stopPropagation();
2370
+ onOpenChange(!open);
2267
2371
  };
2268
2372
  const handleTriggerMouseDown = (e) => {
2269
2373
  e.preventDefault();
@@ -2272,40 +2376,46 @@ function BubbleDropdown({
2272
2376
  const handlePanelClick = (e) => {
2273
2377
  e.stopPropagation();
2274
2378
  };
2379
+ const panelStyle = position ? {
2380
+ position: "fixed",
2381
+ top: position.top,
2382
+ left: position.left,
2383
+ opacity: 1,
2384
+ transition: "opacity 0.15s ease"
2385
+ } : {};
2275
2386
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
2276
2387
  /* @__PURE__ */ jsxs3(
2277
2388
  "button",
2278
2389
  {
2279
- ref: refs.setReference,
2390
+ ref: triggerRef,
2280
2391
  type: "button",
2281
2392
  className: `ya-bubble-dropdown-trigger ${open ? "is-open" : ""} ${triggerClassName}`,
2282
- ...getReferenceProps({
2283
- onClick: handleTriggerClick,
2284
- onMouseDown: handleTriggerMouseDown
2285
- }),
2393
+ onClick: handleTriggerClick,
2394
+ onMouseDown: handleTriggerMouseDown,
2286
2395
  children: [
2287
2396
  /* @__PURE__ */ jsx7("span", { className: "ya-bubble-dropdown-label", children: label }),
2288
2397
  /* @__PURE__ */ jsx7(ChevronDownIcon, { size: 10, className: `ya-bubble-dropdown-arrow ${open ? "is-open" : ""}` })
2289
2398
  ]
2290
2399
  }
2291
2400
  ),
2292
- open && /* @__PURE__ */ jsx7(FloatingPortal, { children: /* @__PURE__ */ jsx7(
2293
- "div",
2294
- {
2295
- ref: refs.setFloating,
2296
- style: panelStyle,
2297
- className: `ya-bubble-dropdown-panel ${panelClassName}`,
2298
- ...getFloatingProps({
2299
- onClick: handlePanelClick
2300
- }),
2301
- children
2302
- }
2303
- ) })
2401
+ isMounted && open && position && createPortal3(
2402
+ /* @__PURE__ */ jsx7(
2403
+ "div",
2404
+ {
2405
+ ref: panelRef,
2406
+ style: panelStyle,
2407
+ className: `ya-bubble-dropdown-panel ${panelClassName}`,
2408
+ onClick: handlePanelClick,
2409
+ children
2410
+ }
2411
+ ),
2412
+ document.body
2413
+ )
2304
2414
  ] });
2305
2415
  }
2306
2416
 
2307
2417
  // src/components/FontSizePicker.tsx
2308
- import { useState as useState4, useEffect as useEffect5, useCallback as useCallback5, useRef as useRef5 } from "react";
2418
+ import { useState as useState6, useEffect as useEffect6, useCallback as useCallback7, useRef as useRef7 } from "react";
2309
2419
  import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
2310
2420
  var SIZE_PRESETS = [
2311
2421
  { name: "S", value: "0.875rem" },
@@ -2363,28 +2473,28 @@ function normalizeValue(input) {
2363
2473
  return `${num}${unit}`;
2364
2474
  }
2365
2475
  function FontSizePicker({ value, onChange, onClose }) {
2366
- const [inputValue, setInputValue] = useState4(value || "");
2367
- const inputRef = useRef5(null);
2368
- useEffect5(() => {
2476
+ const [inputValue, setInputValue] = useState6(value || "");
2477
+ const inputRef = useRef7(null);
2478
+ useEffect6(() => {
2369
2479
  inputRef.current?.focus();
2370
2480
  inputRef.current?.select();
2371
2481
  }, []);
2372
- useEffect5(() => {
2482
+ useEffect6(() => {
2373
2483
  setInputValue(value || "");
2374
2484
  }, [value]);
2375
- const handlePresetClick = useCallback5((e, presetValue) => {
2485
+ const handlePresetClick = useCallback7((e, presetValue) => {
2376
2486
  e.stopPropagation();
2377
2487
  onChange(presetValue);
2378
2488
  onClose();
2379
2489
  }, [onChange, onClose]);
2380
- const handlePresetMouseDown = useCallback5((e) => {
2490
+ const handlePresetMouseDown = useCallback7((e) => {
2381
2491
  e.preventDefault();
2382
2492
  e.stopPropagation();
2383
2493
  }, []);
2384
- const handleInputChange = useCallback5((e) => {
2494
+ const handleInputChange = useCallback7((e) => {
2385
2495
  setInputValue(e.target.value);
2386
2496
  }, []);
2387
- const handleInputKeyDown = useCallback5((e) => {
2497
+ const handleInputKeyDown = useCallback7((e) => {
2388
2498
  if (e.key === "ArrowUp" || e.key === "ArrowDown") {
2389
2499
  e.preventDefault();
2390
2500
  e.stopPropagation();
@@ -2460,7 +2570,7 @@ function FontSizePicker({ value, onChange, onClose }) {
2460
2570
  }
2461
2571
 
2462
2572
  // src/components/FontWeightPicker.tsx
2463
- import { useCallback as useCallback6 } from "react";
2573
+ import { useCallback as useCallback8 } from "react";
2464
2574
  import { jsx as jsx9 } from "react/jsx-runtime";
2465
2575
  var WEIGHT_PRESETS = [
2466
2576
  { name: "Regular", value: "400" },
@@ -2475,12 +2585,12 @@ function getFontWeightLabel(value) {
2475
2585
  return value;
2476
2586
  }
2477
2587
  function FontWeightPicker({ value, onChange, onClose }) {
2478
- const handleClick = useCallback6((e, weightValue) => {
2588
+ const handleClick = useCallback8((e, weightValue) => {
2479
2589
  e.stopPropagation();
2480
2590
  onChange(weightValue);
2481
2591
  onClose();
2482
2592
  }, [onChange, onClose]);
2483
- const handleMouseDown = useCallback6((e) => {
2593
+ const handleMouseDown = useCallback8((e) => {
2484
2594
  e.preventDefault();
2485
2595
  e.stopPropagation();
2486
2596
  }, []);
@@ -2632,6 +2742,18 @@ body.builder-selector-active .ya-text-editable:hover {
2632
2742
  .ProseMirror p {
2633
2743
  margin: 0;
2634
2744
  }
2745
+ .ya-text-inline-edit .ProseMirror p {
2746
+ display: inline;
2747
+ }
2748
+ .ya-text-inline-edit .ProseMirror p + p::before {
2749
+ content: " ";
2750
+ }
2751
+ .ProseMirror-gapcursor {
2752
+ display: none !important;
2753
+ }
2754
+ .ProseMirror .ProseMirror-dropcursor {
2755
+ display: none !important;
2756
+ }
2635
2757
  .ProseMirror a {
2636
2758
  color: var(--color-primary, #D4A574);
2637
2759
  text-decoration: underline;
@@ -2918,10 +3040,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2918
3040
  const { getValue, setValue, mode, saveToWorker, activeFieldId, setActiveField } = useContentStore();
2919
3041
  const storeContent = getValue(fieldId);
2920
3042
  const content = storeContent || (typeof children === "string" ? children : "");
2921
- const [isEditing, setIsEditing] = useState5(false);
2922
- const [showBubbleMenu, setShowBubbleMenu] = useState5(false);
2923
- const [fontSizeOpen, setFontSizeOpen] = useState5(false);
2924
- const [fontWeightOpen, setFontWeightOpen] = useState5(false);
3043
+ const [isEditing, setIsEditing] = useState7(false);
3044
+ const [showBubbleMenu, setShowBubbleMenu] = useState7(false);
3045
+ const [fontSizeOpen, setFontSizeOpen] = useState7(false);
3046
+ const [fontWeightOpen, setFontWeightOpen] = useState7(false);
2925
3047
  const {
2926
3048
  displayContent,
2927
3049
  isAnimating,
@@ -2929,15 +3051,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2929
3051
  } = useAnimatedText(fieldId, content, {
2930
3052
  enabled: mode === "inline-edit" && !isEditing
2931
3053
  });
2932
- const [originalContent, setOriginalContent] = useState5(content);
2933
- const containerRef = useRef6(null);
2934
- const originalContentRef = useRef6(content);
2935
- const [actionButtonsPos, setActionButtonsPos] = useState5(null);
2936
- const handleSaveRef = useRef6(() => {
3054
+ const [originalContent, setOriginalContent] = useState7(content);
3055
+ const containerRef = useRef8(null);
3056
+ const originalContentRef = useRef8(content);
3057
+ const originalHadLineBreaksRef = useRef8(false);
3058
+ const [actionButtonsPos, setActionButtonsPos] = useState7(null);
3059
+ const handleSaveRef = useRef8(() => {
2937
3060
  });
2938
- const handleCancelRef = useRef6(() => {
3061
+ const handleCancelRef = useRef8(() => {
2939
3062
  });
2940
- const handleCloseRef = useRef6(() => {
3063
+ const handleCloseRef = useRef8(() => {
2941
3064
  });
2942
3065
  const editor = useEditor({
2943
3066
  extensions: [
@@ -2949,6 +3072,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2949
3072
  blockquote: false,
2950
3073
  codeBlock: false,
2951
3074
  horizontalRule: false,
3075
+ // Disable gapcursor and dropcursor - show unwanted visual elements
3076
+ gapcursor: false,
3077
+ dropcursor: false,
2952
3078
  // Disable Link since we configure it separately below
2953
3079
  link: false
2954
3080
  }),
@@ -2963,7 +3089,6 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2963
3089
  FontWeight
2964
3090
  ],
2965
3091
  content,
2966
- // Content is now HTML, no conversion needed
2967
3092
  editable: true,
2968
3093
  editorProps: {
2969
3094
  attributes: {
@@ -2991,19 +3116,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2991
3116
  },
2992
3117
  parseOptions: { preserveWhitespace: "full" }
2993
3118
  });
2994
- useEffect6(() => {
3119
+ useEffect7(() => {
2995
3120
  if (editor && !isEditing) {
2996
3121
  if (editor.getHTML() !== content) {
2997
3122
  editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
2998
3123
  }
2999
3124
  }
3000
3125
  }, [content, editor, isEditing]);
3001
- useEffect6(() => {
3126
+ useEffect7(() => {
3002
3127
  if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
3003
3128
  setIsEditing(false);
3004
3129
  }
3005
3130
  }, [activeFieldId, fieldId, isEditing]);
3006
- useEffect6(() => {
3131
+ useEffect7(() => {
3007
3132
  if (!isEditing || !containerRef.current || !editor) {
3008
3133
  setActionButtonsPos(null);
3009
3134
  return;
@@ -3028,55 +3153,62 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3028
3153
  window.removeEventListener("resize", updatePosition);
3029
3154
  };
3030
3155
  }, [isEditing, editor]);
3031
- const handleSave = useCallback7(() => {
3156
+ const handleSave = useCallback9(() => {
3032
3157
  if (!editor) return;
3033
3158
  let html = editor.getHTML();
3034
- html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
3159
+ const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
3160
+ html = html.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
3035
3161
  if (html !== originalContentRef.current) {
3036
3162
  setValue(fieldId, html, "user");
3037
3163
  saveToWorker?.(fieldId, html);
3164
+ originalContentRef.current = html;
3038
3165
  }
3039
3166
  setShowBubbleMenu(false);
3040
3167
  setIsEditing(false);
3041
3168
  }, [editor, fieldId, setValue, saveToWorker]);
3042
- const handleCancel = useCallback7(() => {
3169
+ const handleCancel = useCallback9(() => {
3043
3170
  if (editor) {
3044
3171
  editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
3045
3172
  }
3046
3173
  setShowBubbleMenu(false);
3047
3174
  setIsEditing(false);
3048
3175
  }, [editor, originalContent]);
3049
- useEffect6(() => {
3176
+ useEffect7(() => {
3050
3177
  handleSaveRef.current = handleSave;
3051
3178
  handleCancelRef.current = handleCancel;
3052
3179
  }, [handleSave, handleCancel]);
3053
- useEffect6(() => {
3180
+ useEffect7(() => {
3054
3181
  if (mode !== "inline-edit") return;
3055
3182
  const handleEditRequest = (event) => {
3056
3183
  const customEvent = event;
3057
3184
  const parentFieldId = customEvent.detail.fieldId;
3058
3185
  const parentLink = containerRef.current?.closest(`[data-field-id="${parentFieldId}"]`);
3059
3186
  if (!parentLink) return;
3060
- setOriginalContent(content);
3061
- originalContentRef.current = content;
3187
+ originalHadLineBreaksRef.current = /<br\s*\/?>/i.test(content);
3062
3188
  setActiveField(fieldId, { close: handleCloseRef.current });
3063
3189
  setIsEditing(true);
3064
3190
  setTimeout(() => {
3065
3191
  editor?.chain().focus().selectAll().run();
3066
3192
  setShowBubbleMenu(true);
3193
+ if (editor) {
3194
+ const normalizedHtml = editor.getHTML();
3195
+ setOriginalContent(normalizedHtml);
3196
+ originalContentRef.current = normalizedHtml;
3197
+ }
3067
3198
  }, 20);
3068
3199
  };
3069
3200
  window.addEventListener("yatext:edit-mode", handleEditRequest);
3070
3201
  return () => window.removeEventListener("yatext:edit-mode", handleEditRequest);
3071
3202
  }, [mode, fieldId, content, editor, setActiveField]);
3072
- const handleClose = useCallback7(() => {
3203
+ const handleClose = useCallback9(() => {
3073
3204
  if (!editor) {
3074
3205
  setShowBubbleMenu(false);
3075
3206
  setIsEditing(false);
3076
3207
  return;
3077
3208
  }
3078
3209
  let currentHtml = editor.getHTML();
3079
- currentHtml = currentHtml.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
3210
+ const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
3211
+ currentHtml = currentHtml.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
3080
3212
  if (currentHtml !== originalContentRef.current) {
3081
3213
  setValue(fieldId, currentHtml, "user");
3082
3214
  saveToWorker?.(fieldId, currentHtml);
@@ -3084,10 +3216,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3084
3216
  setShowBubbleMenu(false);
3085
3217
  setIsEditing(false);
3086
3218
  }, [editor, fieldId, setValue, saveToWorker]);
3087
- useEffect6(() => {
3219
+ useEffect7(() => {
3088
3220
  handleCloseRef.current = handleClose;
3089
3221
  }, [handleClose]);
3090
- const handleClick = useCallback7((e) => {
3222
+ const handleClick = useCallback9((e) => {
3091
3223
  if (isEditing) {
3092
3224
  e.preventDefault();
3093
3225
  e.stopPropagation();
@@ -3104,17 +3236,21 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3104
3236
  if (mode === "inline-edit" && !isEditing) {
3105
3237
  e.preventDefault();
3106
3238
  e.stopPropagation();
3107
- setOriginalContent(content);
3108
- originalContentRef.current = content;
3239
+ originalHadLineBreaksRef.current = /<br\s*\/?>/i.test(content);
3109
3240
  setActiveField(fieldId, { close: handleClose });
3110
3241
  setIsEditing(true);
3111
3242
  setTimeout(() => {
3112
3243
  editor?.chain().focus().selectAll().run();
3113
3244
  setShowBubbleMenu(true);
3245
+ if (editor) {
3246
+ const normalizedHtml = editor.getHTML();
3247
+ setOriginalContent(normalizedHtml);
3248
+ originalContentRef.current = normalizedHtml;
3249
+ }
3114
3250
  }, 20);
3115
3251
  }
3116
3252
  }, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
3117
- const handleKeyDown = useCallback7(
3253
+ const handleKeyDown = useCallback9(
3118
3254
  (event) => {
3119
3255
  if (!isEditing) return;
3120
3256
  if (event.key === "Enter" && !event.shiftKey) {
@@ -3135,7 +3271,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3135
3271
  },
3136
3272
  [isEditing, handleSave, handleCancel]
3137
3273
  );
3138
- const handleLink = useCallback7(() => {
3274
+ const handleLink = useCallback9(() => {
3139
3275
  if (!editor) return;
3140
3276
  const previousUrl = editor.getAttributes("link").href;
3141
3277
  const url = window.prompt("Enter URL:", previousUrl || "https://");
@@ -3146,7 +3282,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3146
3282
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
3147
3283
  }
3148
3284
  }, [editor]);
3149
- const handleFontSizeChange = useCallback7(
3285
+ const handleFontSizeChange = useCallback9(
3150
3286
  (size) => {
3151
3287
  if (!editor) return;
3152
3288
  if (size === "") {
@@ -3157,7 +3293,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3157
3293
  },
3158
3294
  [editor]
3159
3295
  );
3160
- const handleFontWeightChange = useCallback7(
3296
+ const handleFontWeightChange = useCallback9(
3161
3297
  (weight) => {
3162
3298
  if (!editor) return;
3163
3299
  if (weight === "") {
@@ -3213,9 +3349,12 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3213
3349
  }
3214
3350
  );
3215
3351
  }
3352
+ const hasExplicitLineBreaks = /<br\s*\/?>/i.test(content);
3353
+ const shouldForceInline = !hasExplicitLineBreaks;
3216
3354
  const combinedClassName = [
3217
3355
  className || "",
3218
3356
  isEditing ? "ya-text-editing" : "ya-text-editable",
3357
+ isEditing && shouldForceInline ? "ya-text-inline-edit" : "",
3219
3358
  wrapperClassName
3220
3359
  ].filter(Boolean).join(" ");
3221
3360
  const EditSafeComponent = isEditing && Component === "p" ? "div" : Component;
@@ -3308,7 +3447,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3308
3447
  ),
3309
3448
  isEditing ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3310
3449
  /* @__PURE__ */ jsx10(EditorContent, { editor }),
3311
- actionButtonsPos && createPortal3(
3450
+ actionButtonsPos && createPortal4(
3312
3451
  /* @__PURE__ */ jsxs5(
3313
3452
  "div",
3314
3453
  {
@@ -3357,7 +3496,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3357
3496
  }
3358
3497
 
3359
3498
  // src/components/YaImage.tsx
3360
- import { useCallback as useCallback9, useEffect as useEffect8, useRef as useRef8, useState as useState7 } from "react";
3499
+ import { useCallback as useCallback12, useEffect as useEffect10, useRef as useRef11, useState as useState10 } from "react";
3361
3500
 
3362
3501
  // src/lib/asset-resolver.ts
3363
3502
  var assetResolver = (path) => path;
@@ -3373,8 +3512,8 @@ function resolveAssetUrl(path) {
3373
3512
  }
3374
3513
 
3375
3514
  // src/components/YaTooltip.tsx
3376
- import { useEffect as useEffect7, useRef as useRef7, useState as useState6, useCallback as useCallback8 } from "react";
3377
- import { createPortal as createPortal4 } from "react-dom";
3515
+ import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback10 } from "react";
3516
+ import { createPortal as createPortal5 } from "react-dom";
3378
3517
 
3379
3518
  // src/components/ya-tooltip.css
3380
3519
  styleInject('.ya-tooltip {\n position: fixed;\n z-index: 9999;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n animation: ya-tooltip-fade-in 0.15s ease;\n pointer-events: none;\n}\n@keyframes ya-tooltip-fade-in {\n from {\n transform: scale(0.95);\n }\n to {\n transform: scale(1);\n }\n}\n.ya-tooltip svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n.ya-tooltip-bottom {\n transform: translateX(-50%);\n}\n.ya-tooltip-bottom::before {\n content: "";\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-bottom-color: #1a1a1a;\n}\n.ya-tooltip-top {\n transform: translateX(-50%);\n}\n.ya-tooltip-top::before {\n content: "";\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-top-color: #1a1a1a;\n}\n.ya-tooltip-right {\n transform: translateY(-50%);\n}\n.ya-tooltip-right::before {\n content: "";\n position: absolute;\n right: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-right-color: #1a1a1a;\n}\n.ya-tooltip-left {\n transform: translateY(-50%);\n}\n.ya-tooltip-left::before {\n content: "";\n position: absolute;\n left: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: #1a1a1a;\n}\n');
@@ -3387,11 +3526,11 @@ function YaTooltip({
3387
3526
  show,
3388
3527
  preferredPosition = "bottom"
3389
3528
  }) {
3390
- const [position, setPosition] = useState6(preferredPosition);
3391
- const [coords, setCoords] = useState6({ top: 0, left: 0 });
3392
- const [isPositioned, setIsPositioned] = useState6(false);
3393
- const tooltipRef = useRef7(null);
3394
- const calculatePosition = useCallback8(() => {
3529
+ const [position, setPosition] = useState8(preferredPosition);
3530
+ const [coords, setCoords] = useState8({ top: 0, left: 0 });
3531
+ const [isPositioned, setIsPositioned] = useState8(false);
3532
+ const tooltipRef = useRef9(null);
3533
+ const calculatePosition = useCallback10(() => {
3395
3534
  if (!anchorRef.current) return;
3396
3535
  const anchor = anchorRef.current.getBoundingClientRect();
3397
3536
  const tooltip = tooltipRef.current?.getBoundingClientRect();
@@ -3466,7 +3605,7 @@ function YaTooltip({
3466
3605
  setCoords({ top, left });
3467
3606
  setIsPositioned(true);
3468
3607
  }, [anchorRef, preferredPosition]);
3469
- useEffect7(() => {
3608
+ useEffect8(() => {
3470
3609
  if (!show) {
3471
3610
  setIsPositioned(false);
3472
3611
  return;
@@ -3479,13 +3618,13 @@ function YaTooltip({
3479
3618
  window.removeEventListener("resize", calculatePosition);
3480
3619
  };
3481
3620
  }, [show, calculatePosition]);
3482
- useEffect7(() => {
3621
+ useEffect8(() => {
3483
3622
  if (show && tooltipRef.current) {
3484
3623
  calculatePosition();
3485
3624
  }
3486
3625
  }, [show, children, calculatePosition]);
3487
3626
  if (!show) return null;
3488
- return createPortal4(
3627
+ return createPortal5(
3489
3628
  /* @__PURE__ */ jsx11(
3490
3629
  "div",
3491
3630
  {
@@ -3504,6 +3643,345 @@ function YaTooltip({
3504
3643
  );
3505
3644
  }
3506
3645
 
3646
+ // src/hooks/useImageShaderTransition.ts
3647
+ import { useCallback as useCallback11, useEffect as useEffect9, useRef as useRef10, useState as useState9 } from "react";
3648
+
3649
+ // src/lib/image-shader-transition.ts
3650
+ var VERTEX_SHADER = `
3651
+ attribute vec2 a_position;
3652
+ attribute vec2 a_texCoord;
3653
+ varying vec2 v_texCoord;
3654
+
3655
+ void main() {
3656
+ gl_Position = vec4(a_position, 0.0, 1.0);
3657
+ v_texCoord = a_texCoord;
3658
+ }
3659
+ `;
3660
+ var FLAG_WAVE_FRAGMENT_SHADER = `
3661
+ precision mediump float;
3662
+
3663
+ uniform sampler2D uTex1;
3664
+ uniform sampler2D uTex2;
3665
+ uniform float uTime;
3666
+ uniform float uProgress;
3667
+
3668
+ varying vec2 v_texCoord;
3669
+
3670
+ void main() {
3671
+ vec2 uv = v_texCoord;
3672
+ float p = uProgress;
3673
+
3674
+ // Smooth easing (smoothstep)
3675
+ float slide = p * p * (3.0 - 2.0 * p);
3676
+
3677
+ // Wave physics - amplitude peaks mid-transition
3678
+ float waveStrength = sin(p * 3.14159) * 0.1;
3679
+ float wave = sin(uv.y * 15.0 + uTime * 5.0) * waveStrength;
3680
+
3681
+ // Distort UVs horizontally
3682
+ vec2 distortedUv = uv;
3683
+ distortedUv.x -= wave;
3684
+
3685
+ // Slide logic with boundary clamping
3686
+ if (uv.x > (1.0 - slide)) {
3687
+ vec2 newUv = distortedUv - vec2(1.0 - slide, 0.0);
3688
+ // Clamp to valid texture coordinates
3689
+ newUv = clamp(newUv, 0.0, 1.0);
3690
+ gl_FragColor = texture2D(uTex2, newUv);
3691
+ } else {
3692
+ vec2 oldUv = distortedUv + vec2(slide, 0.0);
3693
+ // Clamp to valid texture coordinates
3694
+ oldUv = clamp(oldUv, 0.0, 1.0);
3695
+ gl_FragColor = texture2D(uTex1, oldUv);
3696
+ }
3697
+ }
3698
+ `;
3699
+ function compileShader(gl, source, type) {
3700
+ const shader = gl.createShader(type);
3701
+ if (!shader) return null;
3702
+ gl.shaderSource(shader, source);
3703
+ gl.compileShader(shader);
3704
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
3705
+ console.error("Shader compile error:", gl.getShaderInfoLog(shader));
3706
+ gl.deleteShader(shader);
3707
+ return null;
3708
+ }
3709
+ return shader;
3710
+ }
3711
+ function createShaderProgram(gl) {
3712
+ const vertexShader = compileShader(gl, VERTEX_SHADER, gl.VERTEX_SHADER);
3713
+ const fragmentShader = compileShader(gl, FLAG_WAVE_FRAGMENT_SHADER, gl.FRAGMENT_SHADER);
3714
+ if (!vertexShader || !fragmentShader) return null;
3715
+ const program = gl.createProgram();
3716
+ if (!program) return null;
3717
+ gl.attachShader(program, vertexShader);
3718
+ gl.attachShader(program, fragmentShader);
3719
+ gl.linkProgram(program);
3720
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
3721
+ console.error("Program link error:", gl.getProgramInfoLog(program));
3722
+ gl.deleteProgram(program);
3723
+ return null;
3724
+ }
3725
+ gl.deleteShader(vertexShader);
3726
+ gl.deleteShader(fragmentShader);
3727
+ return program;
3728
+ }
3729
+ function setupGeometry(gl, program) {
3730
+ const positions = new Float32Array([
3731
+ -1,
3732
+ -1,
3733
+ 1,
3734
+ -1,
3735
+ -1,
3736
+ 1,
3737
+ // Triangle 1
3738
+ -1,
3739
+ 1,
3740
+ 1,
3741
+ -1,
3742
+ 1,
3743
+ 1
3744
+ // Triangle 2
3745
+ ]);
3746
+ const texCoords = new Float32Array([
3747
+ 0,
3748
+ 1,
3749
+ 1,
3750
+ 1,
3751
+ 0,
3752
+ 0,
3753
+ // Triangle 1
3754
+ 0,
3755
+ 0,
3756
+ 1,
3757
+ 1,
3758
+ 1,
3759
+ 0
3760
+ // Triangle 2
3761
+ ]);
3762
+ const positionBuffer = gl.createBuffer();
3763
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
3764
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
3765
+ const positionLocation = gl.getAttribLocation(program, "a_position");
3766
+ gl.enableVertexAttribArray(positionLocation);
3767
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
3768
+ const texCoordBuffer = gl.createBuffer();
3769
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
3770
+ gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
3771
+ const texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
3772
+ gl.enableVertexAttribArray(texCoordLocation);
3773
+ gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
3774
+ }
3775
+ function loadImageAsTexture(gl, src, onLoad) {
3776
+ const texture = gl.createTexture();
3777
+ if (!texture) return null;
3778
+ gl.bindTexture(gl.TEXTURE_2D, texture);
3779
+ const placeholder = new Uint8Array([128, 128, 128, 255]);
3780
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, placeholder);
3781
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
3782
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
3783
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
3784
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
3785
+ if (!src || src.startsWith("data:image/svg+xml")) {
3786
+ const transparent = new Uint8Array([0, 0, 0, 0]);
3787
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, transparent);
3788
+ onLoad?.();
3789
+ return texture;
3790
+ }
3791
+ const image2 = document.createElement("img");
3792
+ image2.crossOrigin = "anonymous";
3793
+ image2.onload = () => {
3794
+ gl.bindTexture(gl.TEXTURE_2D, texture);
3795
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image2);
3796
+ onLoad?.();
3797
+ };
3798
+ image2.onerror = () => {
3799
+ console.warn("Failed to load image for shader transition:", src);
3800
+ onLoad?.();
3801
+ };
3802
+ image2.src = src;
3803
+ return texture;
3804
+ }
3805
+ function isWebGLAvailable() {
3806
+ try {
3807
+ const canvas = document.createElement("canvas");
3808
+ const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
3809
+ return gl !== null;
3810
+ } catch {
3811
+ return false;
3812
+ }
3813
+ }
3814
+ function createTransitionRenderer(canvas) {
3815
+ const gl = canvas.getContext("webgl", {
3816
+ alpha: true,
3817
+ premultipliedAlpha: false,
3818
+ preserveDrawingBuffer: false
3819
+ });
3820
+ if (!gl) {
3821
+ console.warn("WebGL not available for image transition");
3822
+ return null;
3823
+ }
3824
+ const program = createShaderProgram(gl);
3825
+ if (!program) {
3826
+ console.error("Failed to create shader program");
3827
+ return null;
3828
+ }
3829
+ gl.useProgram(program);
3830
+ setupGeometry(gl, program);
3831
+ const uTex1 = gl.getUniformLocation(program, "uTex1");
3832
+ const uTex2 = gl.getUniformLocation(program, "uTex2");
3833
+ const uTime = gl.getUniformLocation(program, "uTime");
3834
+ const uProgress = gl.getUniformLocation(program, "uProgress");
3835
+ if (!uTex1 || !uTex2 || !uTime || !uProgress) {
3836
+ console.error("Failed to get uniform locations");
3837
+ return null;
3838
+ }
3839
+ gl.enable(gl.BLEND);
3840
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
3841
+ const renderer = {
3842
+ canvas,
3843
+ gl,
3844
+ program,
3845
+ uniforms: { uTex1, uTex2, uTime, uProgress },
3846
+ textures: { tex1: null, tex2: null },
3847
+ destroy: () => {
3848
+ if (renderer.textures.tex1) gl.deleteTexture(renderer.textures.tex1);
3849
+ if (renderer.textures.tex2) gl.deleteTexture(renderer.textures.tex2);
3850
+ gl.deleteProgram(program);
3851
+ const ext = gl.getExtension("WEBGL_lose_context");
3852
+ ext?.loseContext();
3853
+ }
3854
+ };
3855
+ return renderer;
3856
+ }
3857
+ function renderTransitionFrame(renderer, progress, time) {
3858
+ const { gl, program, uniforms, textures } = renderer;
3859
+ const canvas = renderer.canvas;
3860
+ if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
3861
+ canvas.width = canvas.clientWidth;
3862
+ canvas.height = canvas.clientHeight;
3863
+ gl.viewport(0, 0, canvas.width, canvas.height);
3864
+ }
3865
+ gl.clearColor(0, 0, 0, 0);
3866
+ gl.clear(gl.COLOR_BUFFER_BIT);
3867
+ gl.useProgram(program);
3868
+ gl.activeTexture(gl.TEXTURE0);
3869
+ gl.bindTexture(gl.TEXTURE_2D, textures.tex1);
3870
+ gl.uniform1i(uniforms.uTex1, 0);
3871
+ gl.activeTexture(gl.TEXTURE1);
3872
+ gl.bindTexture(gl.TEXTURE_2D, textures.tex2);
3873
+ gl.uniform1i(uniforms.uTex2, 1);
3874
+ gl.uniform1f(uniforms.uTime, time);
3875
+ gl.uniform1f(uniforms.uProgress, progress);
3876
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
3877
+ }
3878
+ function setTransitionTextures(renderer, oldSrc, newSrc, onReady) {
3879
+ const { gl } = renderer;
3880
+ let loadedCount = 0;
3881
+ const checkReady = () => {
3882
+ loadedCount++;
3883
+ if (loadedCount === 2) onReady();
3884
+ };
3885
+ if (renderer.textures.tex1) gl.deleteTexture(renderer.textures.tex1);
3886
+ if (renderer.textures.tex2) gl.deleteTexture(renderer.textures.tex2);
3887
+ renderer.textures.tex1 = loadImageAsTexture(gl, oldSrc, checkReady);
3888
+ renderer.textures.tex2 = loadImageAsTexture(gl, newSrc, checkReady);
3889
+ }
3890
+
3891
+ // src/hooks/useImageShaderTransition.ts
3892
+ function preloadImage(src) {
3893
+ return new Promise((resolve) => {
3894
+ if (!src || src.startsWith("data:")) {
3895
+ resolve();
3896
+ return;
3897
+ }
3898
+ const img = document.createElement("img");
3899
+ img.onload = () => resolve();
3900
+ img.onerror = () => resolve();
3901
+ img.src = src;
3902
+ });
3903
+ }
3904
+ var TRANSITION_DURATION = 500;
3905
+ function useImageShaderTransition(options = {}) {
3906
+ const { duration = TRANSITION_DURATION, onComplete } = options;
3907
+ const canvasRef = useRef10(null);
3908
+ const rendererRef = useRef10(null);
3909
+ const rafRef = useRef10(null);
3910
+ const startTimeRef = useRef10(0);
3911
+ const newSrcRef = useRef10("");
3912
+ const [isTransitioning, setIsTransitioning] = useState9(false);
3913
+ const [webglAvailable] = useState9(() => isWebGLAvailable());
3914
+ useEffect9(() => {
3915
+ return () => {
3916
+ if (rafRef.current) {
3917
+ cancelAnimationFrame(rafRef.current);
3918
+ }
3919
+ rendererRef.current?.destroy();
3920
+ };
3921
+ }, []);
3922
+ const animate = useCallback11(() => {
3923
+ const renderer = rendererRef.current;
3924
+ if (!renderer) return;
3925
+ const elapsed = performance.now() - startTimeRef.current;
3926
+ const progress = Math.min(elapsed / duration, 1);
3927
+ renderTransitionFrame(renderer, progress, elapsed / 1e3);
3928
+ if (progress < 1) {
3929
+ rafRef.current = requestAnimationFrame(animate);
3930
+ } else {
3931
+ preloadImage(newSrcRef.current).then(() => {
3932
+ setIsTransitioning(false);
3933
+ onComplete?.();
3934
+ });
3935
+ }
3936
+ }, [duration, onComplete]);
3937
+ const startTransition = useCallback11(
3938
+ (oldSrc, newSrc) => {
3939
+ if (!webglAvailable) {
3940
+ return;
3941
+ }
3942
+ if (rafRef.current) {
3943
+ cancelAnimationFrame(rafRef.current);
3944
+ rafRef.current = null;
3945
+ }
3946
+ newSrcRef.current = newSrc;
3947
+ const canvas = canvasRef.current;
3948
+ if (!canvas) {
3949
+ console.warn("Canvas not available for shader transition");
3950
+ return;
3951
+ }
3952
+ if (!rendererRef.current) {
3953
+ rendererRef.current = createTransitionRenderer(canvas);
3954
+ }
3955
+ const renderer = rendererRef.current;
3956
+ if (!renderer) {
3957
+ console.warn("Failed to create transition renderer");
3958
+ return;
3959
+ }
3960
+ setTransitionTextures(renderer, oldSrc, newSrc, () => {
3961
+ renderTransitionFrame(renderer, 0, 0);
3962
+ setIsTransitioning(true);
3963
+ startTimeRef.current = performance.now();
3964
+ rafRef.current = requestAnimationFrame(animate);
3965
+ });
3966
+ },
3967
+ [webglAvailable, animate]
3968
+ );
3969
+ const cancelTransition = useCallback11(() => {
3970
+ if (rafRef.current) {
3971
+ cancelAnimationFrame(rafRef.current);
3972
+ rafRef.current = null;
3973
+ }
3974
+ setIsTransitioning(false);
3975
+ }, []);
3976
+ return {
3977
+ canvasRef,
3978
+ isTransitioning,
3979
+ startTransition,
3980
+ cancelTransition,
3981
+ webglAvailable
3982
+ };
3983
+ }
3984
+
3507
3985
  // src/components/ya-image.css
3508
3986
  styleInject('.ya-image-container {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 45px;\n min-height: 45px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-image-container img {\n display: block;\n}\n.ya-image-editable {\n cursor: pointer;\n}\n.ya-image-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-image-editable:hover .ya-image-overlay {\n opacity: 1;\n}\n.ya-image-selected .ya-image-overlay {\n opacity: 0;\n}\n.ya-image-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-image-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-image-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n@keyframes ya-image-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #D4A574);\n outline-width: 2px;\n }\n}\n.ya-image-success {\n animation: ya-image-success 0.4s ease;\n}\n.ya-image-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-image-shimmer 1.5s infinite;\n}\n@keyframes ya-image-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-image-container:focus {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-image-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-small .ya-image-overlay {\n display: none;\n}\n.ya-image-drop-target {\n outline: 2px dashed var(--ya-drop-color, #3b82f6) !important;\n outline-offset: 4px;\n}\n.ya-image-drop-target .ya-image-overlay {\n display: none !important;\n}\n.ya-image-drop-hover {\n outline: 3px solid var(--ya-drop-color, #3b82f6) !important;\n outline-offset: 4px;\n background-color: rgba(59, 130, 246, 0.1);\n}\n.ya-image-drop-hover::before {\n content: "";\n position: absolute;\n inset: -4px;\n border: 2px solid var(--ya-drop-color, #3b82f6);\n border-radius: inherit;\n animation: ya-drop-pulse 1s ease-in-out infinite;\n pointer-events: none;\n}\n@keyframes ya-drop-pulse {\n 0%, 100% {\n opacity: 0.4;\n transform: scale(1);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.02);\n }\n}\n');
3509
3987
 
@@ -3552,15 +4030,16 @@ function YaImage({
3552
4030
  fallbackSrc,
3553
4031
  fallbackAlt
3554
4032
  }) {
3555
- const { getValue, setValue, mode } = useContentStore();
3556
- const containerRef = useRef8(null);
3557
- const imgRef = useRef8(null);
3558
- const [isSelected, setIsSelected] = useState7(false);
3559
- const [isHovered, setIsHovered] = useState7(false);
3560
- const [isSmallImage, setIsSmallImage] = useState7(false);
3561
- const [isDropMode, setIsDropMode] = useState7(false);
3562
- const [isDropHover, setIsDropHover] = useState7(false);
3563
- const [previewOverride, setPreviewOverride] = useState7(null);
4033
+ const { getValue, setValue, mode, getChangeSource, clearChangeSource } = useContentStore();
4034
+ const containerRef = useRef11(null);
4035
+ const imgRef = useRef11(null);
4036
+ const [isSelected, setIsSelected] = useState10(false);
4037
+ const [isHovered, setIsHovered] = useState10(false);
4038
+ const [isSmallImage, setIsSmallImage] = useState10(false);
4039
+ const [isDropMode, setIsDropMode] = useState10(false);
4040
+ const [isDropHover, setIsDropHover] = useState10(false);
4041
+ const [previewOverride, setPreviewOverride] = useState10(null);
4042
+ const prevSrcRef = useRef11(null);
3564
4043
  const rawValue = getValue(fieldId);
3565
4044
  const imageData = parseImageValue(rawValue);
3566
4045
  const displayData = previewOverride || imageData;
@@ -3568,7 +4047,45 @@ function YaImage({
3568
4047
  const altText = displayData.alt || alt || fallbackAlt || "";
3569
4048
  const objectFit = displayData.objectFit || propObjectFit || "cover";
3570
4049
  const objectPosition = getObjectPosition(displayData) || propObjectPosition || "50% 50%";
3571
- const handleClick = useCallback9(() => {
4050
+ const {
4051
+ canvasRef,
4052
+ isTransitioning,
4053
+ startTransition,
4054
+ cancelTransition,
4055
+ webglAvailable
4056
+ } = useImageShaderTransition({
4057
+ duration: 500,
4058
+ onComplete: () => {
4059
+ clearChangeSource(fieldId);
4060
+ }
4061
+ });
4062
+ useEffect10(() => {
4063
+ const changeSource = getChangeSource(fieldId);
4064
+ const resolvedSrc = resolveAssetUrl(src);
4065
+ const prevResolvedSrc = prevSrcRef.current;
4066
+ if (changeSource === "ai") {
4067
+ if (prevResolvedSrc !== null && prevResolvedSrc !== resolvedSrc && webglAvailable) {
4068
+ startTransition(prevResolvedSrc, resolvedSrc);
4069
+ } else {
4070
+ clearChangeSource(fieldId);
4071
+ }
4072
+ }
4073
+ prevSrcRef.current = resolvedSrc;
4074
+ }, [
4075
+ rawValue,
4076
+ src,
4077
+ fieldId,
4078
+ getChangeSource,
4079
+ clearChangeSource,
4080
+ startTransition,
4081
+ webglAvailable
4082
+ ]);
4083
+ useEffect10(() => {
4084
+ return () => {
4085
+ cancelTransition();
4086
+ };
4087
+ }, [cancelTransition]);
4088
+ const handleClick = useCallback12(() => {
3572
4089
  if (mode !== "inline-edit") return;
3573
4090
  if (document.body.classList.contains("builder-selector-active")) return;
3574
4091
  setIsSelected(true);
@@ -3596,7 +4113,7 @@ function YaImage({
3596
4113
  "*"
3597
4114
  );
3598
4115
  }, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
3599
- useEffect8(() => {
4116
+ useEffect10(() => {
3600
4117
  if (mode !== "inline-edit") return;
3601
4118
  const handleMessage2 = (event) => {
3602
4119
  if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -3617,7 +4134,7 @@ function YaImage({
3617
4134
  window.addEventListener("message", handleMessage2);
3618
4135
  return () => window.removeEventListener("message", handleMessage2);
3619
4136
  }, [mode, fieldId, setValue]);
3620
- useEffect8(() => {
4137
+ useEffect10(() => {
3621
4138
  if (mode !== "inline-edit") return;
3622
4139
  const handleDropModeMessage = (event) => {
3623
4140
  if (event.data?.type === "DROP_MODE_START") {
@@ -3631,7 +4148,7 @@ function YaImage({
3631
4148
  window.addEventListener("message", handleDropModeMessage);
3632
4149
  return () => window.removeEventListener("message", handleDropModeMessage);
3633
4150
  }, [mode]);
3634
- const handleDragEnter = useCallback9(
4151
+ const handleDragEnter = useCallback12(
3635
4152
  (e) => {
3636
4153
  if (!isDropMode) return;
3637
4154
  e.preventDefault();
@@ -3655,7 +4172,7 @@ function YaImage({
3655
4172
  },
3656
4173
  [isDropMode, fieldId]
3657
4174
  );
3658
- const handleDragOver = useCallback9(
4175
+ const handleDragOver = useCallback12(
3659
4176
  (e) => {
3660
4177
  if (!isDropMode) return;
3661
4178
  e.preventDefault();
@@ -3663,7 +4180,7 @@ function YaImage({
3663
4180
  },
3664
4181
  [isDropMode]
3665
4182
  );
3666
- const handleDragLeave = useCallback9(
4183
+ const handleDragLeave = useCallback12(
3667
4184
  (e) => {
3668
4185
  if (!isDropMode) return;
3669
4186
  e.preventDefault();
@@ -3677,7 +4194,7 @@ function YaImage({
3677
4194
  },
3678
4195
  [isDropMode]
3679
4196
  );
3680
- const handleDrop = useCallback9(
4197
+ const handleDrop = useCallback12(
3681
4198
  (e) => {
3682
4199
  if (!isDropMode) return;
3683
4200
  e.preventDefault();
@@ -3695,7 +4212,7 @@ function YaImage({
3695
4212
  },
3696
4213
  [isDropMode, fieldId]
3697
4214
  );
3698
- useEffect8(() => {
4215
+ useEffect10(() => {
3699
4216
  if (mode !== "inline-edit") return;
3700
4217
  const checkSize = () => {
3701
4218
  if (imgRef.current) {
@@ -3717,7 +4234,7 @@ function YaImage({
3717
4234
  window.removeEventListener("resize", checkSize);
3718
4235
  };
3719
4236
  }, [mode]);
3720
- useEffect8(() => {
4237
+ useEffect10(() => {
3721
4238
  if (!isSelected || mode !== "inline-edit") return;
3722
4239
  let lastRectKey = "";
3723
4240
  let lastTime = 0;
@@ -3752,19 +4269,48 @@ function YaImage({
3752
4269
  return () => cancelAnimationFrame(rafId);
3753
4270
  }, [isSelected, fieldId, mode]);
3754
4271
  if (mode === "read-only") {
3755
- return /* @__PURE__ */ jsx12(
3756
- "img",
4272
+ return /* @__PURE__ */ jsxs6(
4273
+ "div",
3757
4274
  {
3758
- src: resolveAssetUrl(src),
3759
- alt: altText,
3760
- className,
3761
- style: {
3762
- objectFit,
3763
- objectPosition
3764
- },
3765
- loading,
4275
+ style: { position: "relative", display: "inline-block" },
3766
4276
  "data-ya-restricted": "true",
3767
- "data-field-id": fieldId
4277
+ "data-field-id": fieldId,
4278
+ children: [
4279
+ /* @__PURE__ */ jsx12(
4280
+ "img",
4281
+ {
4282
+ src: resolveAssetUrl(src),
4283
+ alt: altText,
4284
+ className,
4285
+ style: {
4286
+ objectFit,
4287
+ objectPosition,
4288
+ // Smooth crossfade: hide img during transition (canvas takes over)
4289
+ opacity: isTransitioning ? 0 : 1,
4290
+ transition: "opacity 0.05s ease-out"
4291
+ },
4292
+ loading
4293
+ }
4294
+ ),
4295
+ /* @__PURE__ */ jsx12(
4296
+ "canvas",
4297
+ {
4298
+ ref: canvasRef,
4299
+ className,
4300
+ style: {
4301
+ position: "absolute",
4302
+ top: 0,
4303
+ left: 0,
4304
+ width: "100%",
4305
+ height: "100%",
4306
+ // Smooth crossfade: show canvas during transition
4307
+ opacity: isTransitioning ? 1 : 0,
4308
+ pointerEvents: isTransitioning ? "auto" : "none",
4309
+ transition: "opacity 0.05s ease-out"
4310
+ }
4311
+ }
4312
+ )
4313
+ ]
3768
4314
  }
3769
4315
  );
3770
4316
  }
@@ -3827,11 +4373,32 @@ function YaImage({
3827
4373
  className,
3828
4374
  style: {
3829
4375
  objectFit,
3830
- objectPosition
4376
+ objectPosition,
4377
+ // Smooth crossfade: hide img during transition (canvas takes over)
4378
+ opacity: isTransitioning ? 0 : 1,
4379
+ transition: "opacity 0.05s ease-out"
3831
4380
  },
3832
4381
  loading
3833
4382
  }
3834
4383
  ),
4384
+ /* @__PURE__ */ jsx12(
4385
+ "canvas",
4386
+ {
4387
+ ref: canvasRef,
4388
+ className,
4389
+ style: {
4390
+ position: "absolute",
4391
+ top: 0,
4392
+ left: 0,
4393
+ width: "100%",
4394
+ height: "100%",
4395
+ // Smooth crossfade: show canvas during transition
4396
+ opacity: isTransitioning ? 1 : 0,
4397
+ pointerEvents: isTransitioning ? "auto" : "none",
4398
+ transition: "opacity 0.05s ease-out"
4399
+ }
4400
+ }
4401
+ ),
3835
4402
  isSmallImage ? /* @__PURE__ */ jsxs6(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3836
4403
  editIcon,
3837
4404
  /* @__PURE__ */ jsx12("span", { children: "Click to edit" })
@@ -3848,7 +4415,7 @@ function YaImage({
3848
4415
  }
3849
4416
 
3850
4417
  // src/components/YaVideo.tsx
3851
- import { useCallback as useCallback10, useEffect as useEffect9, useRef as useRef9, useState as useState8 } from "react";
4418
+ import { useCallback as useCallback13, useEffect as useEffect11, useRef as useRef12, useState as useState11 } from "react";
3852
4419
 
3853
4420
  // src/components/ya-video.css
3854
4421
  styleInject('.ya-video-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-video-wrapper video,\n.ya-video-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-video-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 45px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-video-container video,\n.ya-video-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-video-editable {\n cursor: pointer;\n}\n.ya-video-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-video-editable:hover .ya-video-overlay {\n opacity: 1;\n}\n.ya-video-selected .ya-video-overlay {\n opacity: 0;\n}\n.ya-video-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-video-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-video-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-video-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-video-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-video-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #D4A574);\n outline-width: 2px;\n }\n}\n.ya-video-success {\n animation: ya-video-success 0.4s ease;\n}\n.ya-video-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-video-shimmer 1.5s infinite;\n}\n@keyframes ya-video-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-video-container:focus {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-video-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-small .ya-video-overlay {\n display: none;\n}\n.ya-video-background {\n position: absolute;\n inset: 0;\n z-index: -1;\n}\n.ya-video-background video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n');
@@ -3927,12 +4494,12 @@ function YaVideo({
3927
4494
  fallbackPoster
3928
4495
  }) {
3929
4496
  const { getValue, mode } = useContentStore();
3930
- const containerRef = useRef9(null);
3931
- const videoRef = useRef9(null);
3932
- const [isSelected, setIsSelected] = useState8(false);
3933
- const [isHovered, setIsHovered] = useState8(false);
3934
- const [isSmallVideo, setIsSmallVideo] = useState8(false);
3935
- const [isInView, setIsInView] = useState8(loading === "eager");
4497
+ const containerRef = useRef12(null);
4498
+ const videoRef = useRef12(null);
4499
+ const [isSelected, setIsSelected] = useState11(false);
4500
+ const [isHovered, setIsHovered] = useState11(false);
4501
+ const [isSmallVideo, setIsSmallVideo] = useState11(false);
4502
+ const [isInView, setIsInView] = useState11(loading === "eager");
3936
4503
  const rawValue = getValue(fieldId);
3937
4504
  const parsedValue = parseVideoValue(rawValue);
3938
4505
  const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
@@ -3946,8 +4513,8 @@ function YaVideo({
3946
4513
  const controls = videoData.controls ?? true;
3947
4514
  const playsinline = videoData.playsinline ?? true;
3948
4515
  const preload = videoData.preload ?? "metadata";
3949
- const [prefersReducedMotion, setPrefersReducedMotion] = useState8(false);
3950
- useEffect9(() => {
4516
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState11(false);
4517
+ useEffect11(() => {
3951
4518
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
3952
4519
  setPrefersReducedMotion(mediaQuery.matches);
3953
4520
  const handleChange = (e) => {
@@ -3957,7 +4524,7 @@ function YaVideo({
3957
4524
  return () => mediaQuery.removeEventListener("change", handleChange);
3958
4525
  }, []);
3959
4526
  const effectiveAutoplay = autoplay && !prefersReducedMotion;
3960
- useEffect9(() => {
4527
+ useEffect11(() => {
3961
4528
  if (loading === "eager" || isInView) return;
3962
4529
  const observer = new IntersectionObserver(
3963
4530
  (entries) => {
@@ -3974,7 +4541,7 @@ function YaVideo({
3974
4541
  }
3975
4542
  return () => observer.disconnect();
3976
4543
  }, [loading, isInView]);
3977
- const handleKeyDown = useCallback10(
4544
+ const handleKeyDown = useCallback13(
3978
4545
  (e) => {
3979
4546
  if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
3980
4547
  e.preventDefault();
@@ -3990,7 +4557,7 @@ function YaVideo({
3990
4557
  },
3991
4558
  [videoData.type, controls]
3992
4559
  );
3993
- const handleClick = useCallback10(() => {
4560
+ const handleClick = useCallback13(() => {
3994
4561
  if (mode !== "inline-edit") return;
3995
4562
  if (document.body.classList.contains("builder-selector-active")) return;
3996
4563
  setIsSelected(true);
@@ -4010,7 +4577,7 @@ function YaVideo({
4010
4577
  "*"
4011
4578
  );
4012
4579
  }, [mode, fieldId, videoData]);
4013
- useEffect9(() => {
4580
+ useEffect11(() => {
4014
4581
  if (mode !== "inline-edit") return;
4015
4582
  const handleMessage2 = (event) => {
4016
4583
  if (event.data?.type === "YA_VIDEO_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4023,7 +4590,7 @@ function YaVideo({
4023
4590
  window.addEventListener("message", handleMessage2);
4024
4591
  return () => window.removeEventListener("message", handleMessage2);
4025
4592
  }, [mode, fieldId]);
4026
- useEffect9(() => {
4593
+ useEffect11(() => {
4027
4594
  if (mode !== "inline-edit") return;
4028
4595
  const checkSize = () => {
4029
4596
  if (containerRef.current) {
@@ -4035,7 +4602,7 @@ function YaVideo({
4035
4602
  window.addEventListener("resize", checkSize);
4036
4603
  return () => window.removeEventListener("resize", checkSize);
4037
4604
  }, [mode]);
4038
- useEffect9(() => {
4605
+ useEffect11(() => {
4039
4606
  if (!isSelected || mode !== "inline-edit") return;
4040
4607
  let lastRectKey = "";
4041
4608
  let lastTime = 0;
@@ -4235,7 +4802,7 @@ function YaVideo({
4235
4802
  }
4236
4803
 
4237
4804
  // src/components/YaEmbed.tsx
4238
- import { useCallback as useCallback11, useEffect as useEffect10, useRef as useRef10, useState as useState9 } from "react";
4805
+ import { useCallback as useCallback14, useEffect as useEffect12, useRef as useRef13, useState as useState12 } from "react";
4239
4806
 
4240
4807
  // src/components/ya-embed.css
4241
4808
  styleInject('.ya-embed-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-embed-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-embed-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 80px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-embed-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-embed-editable {\n cursor: pointer;\n}\n.ya-embed-editable:hover {\n outline: 2px dashed var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-selected {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-embed-editable:hover .ya-embed-overlay {\n opacity: 1;\n}\n.ya-embed-selected .ya-embed-overlay {\n opacity: 0;\n}\n.ya-embed-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-embed-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-embed-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-embed-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-embed-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-embed-success {\n 0% {\n outline-color: var(--color-primary, #d4a574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #d4a574);\n outline-width: 2px;\n }\n}\n.ya-embed-success {\n animation: ya-embed-success 0.4s ease;\n}\n.ya-embed-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-embed-shimmer 1.5s infinite;\n}\n@keyframes ya-embed-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-embed-container:focus {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-embed-container:focus-visible {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-small .ya-embed-overlay {\n display: none;\n}\n.ya-embed-twitter {\n min-height: 200px;\n}\n.ya-embed-twitter .twitter-tweet {\n margin: 0 auto !important;\n}\n.ya-embed-wrapper[data-embed-type=spotify],\n.ya-embed-container[data-embed-type=spotify] {\n min-height: 80px;\n}\n.ya-embed-wrapper[data-embed-type=soundcloud],\n.ya-embed-container[data-embed-type=soundcloud] {\n min-height: 166px;\n}\n.ya-embed-wrapper[data-embed-type=instagram] iframe,\n.ya-embed-container[data-embed-type=instagram] iframe {\n min-height: 400px;\n}\n');
@@ -4355,11 +4922,11 @@ function YaEmbed({
4355
4922
  defaultValue
4356
4923
  }) {
4357
4924
  const { getValue, mode } = useContentStore();
4358
- const containerRef = useRef10(null);
4359
- const [isSelected, setIsSelected] = useState9(false);
4360
- const [isHovered, setIsHovered] = useState9(false);
4361
- const [isSmallEmbed, setIsSmallEmbed] = useState9(false);
4362
- const [isInView, setIsInView] = useState9(loading === "eager");
4925
+ const containerRef = useRef13(null);
4926
+ const [isSelected, setIsSelected] = useState12(false);
4927
+ const [isHovered, setIsHovered] = useState12(false);
4928
+ const [isSmallEmbed, setIsSmallEmbed] = useState12(false);
4929
+ const [isInView, setIsInView] = useState12(loading === "eager");
4363
4930
  const rawValue = getValue(fieldId);
4364
4931
  const parsedValue = parseEmbedValue(rawValue);
4365
4932
  const embedData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
@@ -4367,7 +4934,7 @@ function YaEmbed({
4367
4934
  const embedType = embedData.type || "custom";
4368
4935
  const height = embedData.height;
4369
4936
  const aspectRatio = embedData.aspectRatio || propAspectRatio || "16/9";
4370
- useEffect10(() => {
4937
+ useEffect12(() => {
4371
4938
  if (loading === "eager" || isInView) return;
4372
4939
  const observer = new IntersectionObserver(
4373
4940
  (entries) => {
@@ -4384,7 +4951,7 @@ function YaEmbed({
4384
4951
  }
4385
4952
  return () => observer.disconnect();
4386
4953
  }, [loading, isInView]);
4387
- const handleClick = useCallback11(() => {
4954
+ const handleClick = useCallback14(() => {
4388
4955
  if (mode !== "inline-edit") return;
4389
4956
  if (document.body.classList.contains("builder-selector-active")) return;
4390
4957
  setIsSelected(true);
@@ -4404,7 +4971,7 @@ function YaEmbed({
4404
4971
  "*"
4405
4972
  );
4406
4973
  }, [mode, fieldId, embedData]);
4407
- useEffect10(() => {
4974
+ useEffect12(() => {
4408
4975
  if (mode !== "inline-edit") return;
4409
4976
  const handleMessage2 = (event) => {
4410
4977
  if (event.data?.type === "YA_EMBED_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4417,7 +4984,7 @@ function YaEmbed({
4417
4984
  window.addEventListener("message", handleMessage2);
4418
4985
  return () => window.removeEventListener("message", handleMessage2);
4419
4986
  }, [mode, fieldId]);
4420
- useEffect10(() => {
4987
+ useEffect12(() => {
4421
4988
  if (mode !== "inline-edit") return;
4422
4989
  const checkSize = () => {
4423
4990
  if (containerRef.current) {
@@ -4429,7 +4996,7 @@ function YaEmbed({
4429
4996
  window.addEventListener("resize", checkSize);
4430
4997
  return () => window.removeEventListener("resize", checkSize);
4431
4998
  }, [mode]);
4432
- useEffect10(() => {
4999
+ useEffect12(() => {
4433
5000
  if (!isSelected || mode !== "inline-edit") return;
4434
5001
  let lastRectKey = "";
4435
5002
  let lastTime = 0;
@@ -4625,7 +5192,7 @@ function YaEmbed({
4625
5192
  );
4626
5193
  }
4627
5194
  function TwitterWidgetLoader() {
4628
- useEffect10(() => {
5195
+ useEffect12(() => {
4629
5196
  if (window.twttr?.widgets) {
4630
5197
  ;
4631
5198
  window.twttr.widgets.load();
@@ -4646,8 +5213,8 @@ function TwitterWidgetLoader() {
4646
5213
  }
4647
5214
 
4648
5215
  // src/components/YaLink.tsx
4649
- import { useEffect as useEffect13, useRef as useRef13, useState as useState12, useCallback as useCallback14, useId } from "react";
4650
- import { createPortal as createPortal5 } from "react-dom";
5216
+ import { useEffect as useEffect15, useRef as useRef16, useState as useState15, useCallback as useCallback17, useId } from "react";
5217
+ import { createPortal as createPortal6 } from "react-dom";
4651
5218
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
4652
5219
  import { BubbleMenu } from "@tiptap/react/menus";
4653
5220
  import StarterKit2 from "@tiptap/starter-kit";
@@ -4656,7 +5223,7 @@ import { Extension as Extension2 } from "@tiptap/core";
4656
5223
  import { Link as WouterLink, useLocation } from "wouter";
4657
5224
 
4658
5225
  // src/components/SafeTriangleBelow.tsx
4659
- import { useEffect as useEffect11, useState as useState10, useRef as useRef11, useCallback as useCallback12 } from "react";
5226
+ import { useEffect as useEffect13, useState as useState13, useRef as useRef14, useCallback as useCallback15 } from "react";
4660
5227
  function SafeTriangleBelow({
4661
5228
  triggerRef,
4662
5229
  popoverRef,
@@ -4664,10 +5231,10 @@ function SafeTriangleBelow({
4664
5231
  onLeave,
4665
5232
  onStayInside
4666
5233
  }) {
4667
- const [bounds, setBounds] = useState10(null);
4668
- const boundsRef = useRef11(bounds);
5234
+ const [bounds, setBounds] = useState13(null);
5235
+ const boundsRef = useRef14(bounds);
4669
5236
  boundsRef.current = bounds;
4670
- useEffect11(() => {
5237
+ useEffect13(() => {
4671
5238
  if (!isVisible || !triggerRef.current || !popoverRef.current) {
4672
5239
  setBounds(null);
4673
5240
  return;
@@ -4685,7 +5252,7 @@ function SafeTriangleBelow({
4685
5252
  }, 10);
4686
5253
  return () => clearTimeout(timer);
4687
5254
  }, [isVisible, triggerRef, popoverRef]);
4688
- const checkMousePosition = useCallback12((e) => {
5255
+ const checkMousePosition = useCallback15((e) => {
4689
5256
  const b = boundsRef.current;
4690
5257
  if (!b) return;
4691
5258
  const { clientX: x, clientY: y } = e;
@@ -4697,7 +5264,7 @@ function SafeTriangleBelow({
4697
5264
  onStayInside?.();
4698
5265
  }
4699
5266
  }, [onLeave, onStayInside]);
4700
- useEffect11(() => {
5267
+ useEffect13(() => {
4701
5268
  if (!isVisible || !bounds) return;
4702
5269
  document.addEventListener("mousemove", checkMousePosition);
4703
5270
  return () => document.removeEventListener("mousemove", checkMousePosition);
@@ -4706,22 +5273,22 @@ function SafeTriangleBelow({
4706
5273
  }
4707
5274
 
4708
5275
  // src/hooks/useSafeTriangle.ts
4709
- import { useState as useState11, useRef as useRef12, useCallback as useCallback13, useEffect as useEffect12 } from "react";
5276
+ import { useState as useState14, useRef as useRef15, useCallback as useCallback16, useEffect as useEffect14 } from "react";
4710
5277
  function useSafeTriangle(options = {}) {
4711
5278
  const { showDelay = 0, hideDelay = 150, enabled = true } = options;
4712
- const [isVisible, setIsVisible] = useState11(false);
4713
- const [isHovering, setIsHovering] = useState11(false);
4714
- const triggerRef = useRef12(null);
4715
- const popoverRef = useRef12(null);
4716
- const showTimeoutRef = useRef12(null);
4717
- const hideTimeoutRef = useRef12(null);
4718
- useEffect12(() => {
5279
+ const [isVisible, setIsVisible] = useState14(false);
5280
+ const [isHovering, setIsHovering] = useState14(false);
5281
+ const triggerRef = useRef15(null);
5282
+ const popoverRef = useRef15(null);
5283
+ const showTimeoutRef = useRef15(null);
5284
+ const hideTimeoutRef = useRef15(null);
5285
+ useEffect14(() => {
4719
5286
  return () => {
4720
5287
  if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
4721
5288
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
4722
5289
  };
4723
5290
  }, []);
4724
- const show = useCallback13(() => {
5291
+ const show = useCallback16(() => {
4725
5292
  if (!enabled) return;
4726
5293
  if (hideTimeoutRef.current) {
4727
5294
  clearTimeout(hideTimeoutRef.current);
@@ -4729,7 +5296,7 @@ function useSafeTriangle(options = {}) {
4729
5296
  }
4730
5297
  setIsVisible(true);
4731
5298
  }, [enabled]);
4732
- const hide = useCallback13(() => {
5299
+ const hide = useCallback16(() => {
4733
5300
  if (showTimeoutRef.current) {
4734
5301
  clearTimeout(showTimeoutRef.current);
4735
5302
  showTimeoutRef.current = null;
@@ -4737,7 +5304,7 @@ function useSafeTriangle(options = {}) {
4737
5304
  setIsVisible(false);
4738
5305
  setIsHovering(false);
4739
5306
  }, []);
4740
- const handleMouseEnter = useCallback13(() => {
5307
+ const handleMouseEnter = useCallback16(() => {
4741
5308
  if (!enabled) return;
4742
5309
  setIsHovering(true);
4743
5310
  if (hideTimeoutRef.current) {
@@ -4752,7 +5319,7 @@ function useSafeTriangle(options = {}) {
4752
5319
  setIsVisible(true);
4753
5320
  }
4754
5321
  }, [showDelay, enabled]);
4755
- const handleMouseLeave = useCallback13(() => {
5322
+ const handleMouseLeave = useCallback16(() => {
4756
5323
  setIsHovering(false);
4757
5324
  if (showTimeoutRef.current) {
4758
5325
  clearTimeout(showTimeoutRef.current);
@@ -4762,16 +5329,16 @@ function useSafeTriangle(options = {}) {
4762
5329
  setIsVisible(false);
4763
5330
  }, hideDelay);
4764
5331
  }, [hideDelay]);
4765
- const handleFocus = useCallback13(() => {
5332
+ const handleFocus = useCallback16(() => {
4766
5333
  if (!enabled) return;
4767
5334
  setIsVisible(true);
4768
5335
  }, [enabled]);
4769
- const handleTriangleLeave = useCallback13(() => {
5336
+ const handleTriangleLeave = useCallback16(() => {
4770
5337
  if (!isHovering) {
4771
5338
  setIsVisible(false);
4772
5339
  }
4773
5340
  }, [isHovering]);
4774
- const handleStayInside = useCallback13(() => {
5341
+ const handleStayInside = useCallback16(() => {
4775
5342
  if (hideTimeoutRef.current) {
4776
5343
  clearTimeout(hideTimeoutRef.current);
4777
5344
  hideTimeoutRef.current = null;
@@ -4799,7 +5366,7 @@ function useSafeTriangle(options = {}) {
4799
5366
  }
4800
5367
 
4801
5368
  // src/components/ya-link.css
4802
- styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-editing .ProseMirror {\n color: #1a1a1a !important;\n caret-color: #1a1a1a;\n}\n.ya-link-editing .ProseMirror p::selection,\n.ya-link-editing .ProseMirror::selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ya-link-editing .ProseMirror p::-moz-selection,\n.ya-link-editing .ProseMirror::-moz-selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::selection {\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::-moz-selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::-moz-selection {\n color: inherit;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n z-index: 9999;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n transform: translateX(-50%);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 8px;\n animation: ya-href-popover-fade-in-above 0.15s ease;\n}\n@keyframes ya-href-popover-fade-in-above {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n.ya-link-edit-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transform: translateX(-50%);\n animation: ya-edit-popover-fade-in 0.1s ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n@keyframes ya-edit-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
5369
+ styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-editing .ProseMirror {\n color: #1a1a1a !important;\n caret-color: #1a1a1a;\n}\n.ya-link-editing .ProseMirror p::selection,\n.ya-link-editing .ProseMirror::selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ya-link-editing .ProseMirror p::-moz-selection,\n.ya-link-editing .ProseMirror::-moz-selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ProseMirror-gapcursor {\n display: none !important;\n}\n.ProseMirror .ProseMirror-dropcursor {\n display: none !important;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::selection {\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::-moz-selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::-moz-selection {\n color: inherit;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n z-index: 9999;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n transform: translateX(-50%);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 8px;\n animation: ya-href-popover-fade-in-above 0.15s ease;\n}\n@keyframes ya-href-popover-fade-in-above {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n.ya-link-edit-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transform: translateX(-50%);\n animation: ya-edit-popover-fade-in 0.1s ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n@keyframes ya-edit-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
4803
5370
 
4804
5371
  // src/components/YaLink.tsx
4805
5372
  import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
@@ -4903,8 +5470,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
4903
5470
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
4904
5471
  const [, navigate] = useLocation();
4905
5472
  const pages = availablePages ?? getPages();
4906
- const [sections, setSections] = useState12([]);
4907
- const [sectionsExpanded, setSectionsExpanded] = useState12(false);
5473
+ const [sections, setSections] = useState15([]);
5474
+ const [sectionsExpanded, setSectionsExpanded] = useState15(false);
4908
5475
  const textFieldId = `${fieldId}.text`;
4909
5476
  const hrefFieldId = `${fieldId}.href`;
4910
5477
  const storeText = getValue(textFieldId);
@@ -4915,19 +5482,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
4915
5482
  const isExternal = isExternalHref(href);
4916
5483
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
4917
5484
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
4918
- const [editingMode, setEditingMode] = useState12(null);
4919
- const [originalText, setOriginalText] = useState12(text2);
4920
- const [originalHref, setOriginalHref] = useState12(href);
4921
- const [currentHref, setCurrentHref] = useState12(href);
4922
- const [isExternalUrl, setIsExternalUrl] = useState12(false);
4923
- const [externalUrl, setExternalUrl] = useState12("");
4924
- const [popoverPosition, setPopoverPosition] = useState12("below");
4925
- const containerRef = useRef13(null);
4926
- const hrefPopoverRef = useRef13(null);
4927
- const [actionButtonsPos, setActionButtonsPos] = useState12(null);
4928
- const handleSaveTextRef = useRef13(() => {
5485
+ const [editingMode, setEditingMode] = useState15(null);
5486
+ const [originalText, setOriginalText] = useState15(text2);
5487
+ const [originalHref, setOriginalHref] = useState15(href);
5488
+ const [currentHref, setCurrentHref] = useState15(href);
5489
+ const [isExternalUrl, setIsExternalUrl] = useState15(false);
5490
+ const [externalUrl, setExternalUrl] = useState15("");
5491
+ const [popoverPosition, setPopoverPosition] = useState15("below");
5492
+ const containerRef = useRef16(null);
5493
+ const hrefPopoverRef = useRef16(null);
5494
+ const [actionButtonsPos, setActionButtonsPos] = useState15(null);
5495
+ const handleSaveTextRef = useRef16(() => {
4929
5496
  });
4930
- const handleCancelTextRef = useRef13(() => {
5497
+ const handleCancelTextRef = useRef16(() => {
4931
5498
  });
4932
5499
  const {
4933
5500
  popoverRef: editPopoverRef,
@@ -4941,12 +5508,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
4941
5508
  });
4942
5509
  const triggerRef = containerRef;
4943
5510
  const instanceId = useId();
4944
- useEffect13(() => {
5511
+ useEffect15(() => {
4945
5512
  if (showEditPopover && mode === "inline-edit" && !editingMode) {
4946
5513
  window.dispatchEvent(new CustomEvent("yalink:popover-open", { detail: { id: instanceId } }));
4947
5514
  }
4948
5515
  }, [showEditPopover, mode, editingMode, instanceId]);
4949
- useEffect13(() => {
5516
+ useEffect15(() => {
4950
5517
  const handleOtherPopoverOpen = (event) => {
4951
5518
  const customEvent = event;
4952
5519
  if (customEvent.detail.id !== instanceId && showEditPopover) {
@@ -4964,7 +5531,10 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
4964
5531
  orderedList: false,
4965
5532
  blockquote: false,
4966
5533
  codeBlock: false,
4967
- horizontalRule: false
5534
+ horizontalRule: false,
5535
+ // Disable gapcursor and dropcursor - show unwanted visual elements
5536
+ gapcursor: false,
5537
+ dropcursor: false
4968
5538
  }),
4969
5539
  TextStyle2,
4970
5540
  FontSize2,
@@ -4997,19 +5567,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
4997
5567
  }
4998
5568
  }
4999
5569
  });
5000
- useEffect13(() => {
5570
+ useEffect15(() => {
5001
5571
  if (editor && editingMode !== "text") {
5002
5572
  if (editor.getHTML() !== text2) {
5003
5573
  editor.commands.setContent(text2);
5004
5574
  }
5005
5575
  }
5006
5576
  }, [text2, editor, editingMode]);
5007
- useEffect13(() => {
5577
+ useEffect15(() => {
5008
5578
  if (editingMode !== "link") {
5009
5579
  setCurrentHref(href);
5010
5580
  }
5011
5581
  }, [href, editingMode]);
5012
- useEffect13(() => {
5582
+ useEffect15(() => {
5013
5583
  if (editingMode !== "text" || !containerRef.current) {
5014
5584
  setActionButtonsPos(null);
5015
5585
  return;
@@ -5030,7 +5600,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5030
5600
  window.removeEventListener("resize", updatePosition);
5031
5601
  };
5032
5602
  }, [editingMode]);
5033
- useEffect13(() => {
5603
+ useEffect15(() => {
5034
5604
  if (editingMode !== "link") return;
5035
5605
  const handleClickOutside = (event) => {
5036
5606
  const target2 = event.target;
@@ -5044,7 +5614,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5044
5614
  document.addEventListener("mousedown", handleClickOutside);
5045
5615
  return () => document.removeEventListener("mousedown", handleClickOutside);
5046
5616
  }, [editingMode, originalHref]);
5047
- useEffect13(() => {
5617
+ useEffect15(() => {
5048
5618
  if (editingMode !== "link" || !containerRef.current) return;
5049
5619
  const updatePosition = () => {
5050
5620
  if (!containerRef.current) return;
@@ -5057,7 +5627,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5057
5627
  window.addEventListener("resize", updatePosition);
5058
5628
  return () => window.removeEventListener("resize", updatePosition);
5059
5629
  }, [editingMode]);
5060
- const handleSaveText = useCallback14(() => {
5630
+ const handleSaveText = useCallback17(() => {
5061
5631
  if (!editor) return;
5062
5632
  let html = editor.getHTML();
5063
5633
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -5065,30 +5635,30 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5065
5635
  saveToWorker?.(textFieldId, html);
5066
5636
  setEditingMode(null);
5067
5637
  }, [editor, textFieldId, setValue, saveToWorker]);
5068
- const handleSaveLink = useCallback14(() => {
5638
+ const handleSaveLink = useCallback17(() => {
5069
5639
  setValue(hrefFieldId, currentHref, "user");
5070
5640
  saveToWorker?.(hrefFieldId, currentHref);
5071
5641
  setEditingMode(null);
5072
5642
  setIsExternalUrl(false);
5073
5643
  setExternalUrl("");
5074
5644
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
5075
- const handleCancelText = useCallback14(() => {
5645
+ const handleCancelText = useCallback17(() => {
5076
5646
  if (editor) {
5077
5647
  editor.commands.setContent(originalText);
5078
5648
  }
5079
5649
  setEditingMode(null);
5080
5650
  }, [editor, originalText]);
5081
- const handleCancelLink = useCallback14(() => {
5651
+ const handleCancelLink = useCallback17(() => {
5082
5652
  setCurrentHref(originalHref);
5083
5653
  setEditingMode(null);
5084
5654
  setIsExternalUrl(false);
5085
5655
  setExternalUrl("");
5086
5656
  }, [originalHref]);
5087
- useEffect13(() => {
5657
+ useEffect15(() => {
5088
5658
  handleSaveTextRef.current = handleSaveText;
5089
5659
  handleCancelTextRef.current = handleCancelText;
5090
5660
  }, [handleSaveText, handleCancelText]);
5091
- const handleClick = useCallback14(
5661
+ const handleClick = useCallback17(
5092
5662
  (e) => {
5093
5663
  const selectModeEnabled = window.__builderSelectModeEnabled;
5094
5664
  if (selectModeEnabled) {
@@ -5120,7 +5690,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5120
5690
  },
5121
5691
  [href, navigate, onClick]
5122
5692
  );
5123
- const startEditText = useCallback14(() => {
5693
+ const startEditText = useCallback17(() => {
5124
5694
  hideEditPopover();
5125
5695
  if (isIconMode) {
5126
5696
  window.dispatchEvent(new CustomEvent("yatext:edit-mode", {
@@ -5134,7 +5704,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5134
5704
  }, 20);
5135
5705
  }
5136
5706
  }, [text2, editor, hideEditPopover, isIconMode, fieldId]);
5137
- const startEditLink = useCallback14(() => {
5707
+ const startEditLink = useCallback17(() => {
5138
5708
  hideEditPopover();
5139
5709
  setEditingMode("link");
5140
5710
  setOriginalHref(href);
@@ -5148,7 +5718,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5148
5718
  setPopoverPosition(spaceBelow < popoverHeight && spaceAbove > spaceBelow ? "above" : "below");
5149
5719
  }
5150
5720
  }, [href, hideEditPopover]);
5151
- const handleKeyDown = useCallback14(
5721
+ const handleKeyDown = useCallback17(
5152
5722
  (event) => {
5153
5723
  if (editingMode !== "text") return;
5154
5724
  if (event.key === "Enter" && !event.shiftKey) {
@@ -5169,7 +5739,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5169
5739
  },
5170
5740
  [editingMode, handleSaveText, handleCancelText]
5171
5741
  );
5172
- const handleFontSizeChange = useCallback14(
5742
+ const handleFontSizeChange = useCallback17(
5173
5743
  (e) => {
5174
5744
  if (!editor) return;
5175
5745
  const size = e.target.value;
@@ -5181,7 +5751,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5181
5751
  },
5182
5752
  [editor]
5183
5753
  );
5184
- const handleFontWeightChange = useCallback14(
5754
+ const handleFontWeightChange = useCallback17(
5185
5755
  (e) => {
5186
5756
  if (!editor) return;
5187
5757
  const weight = e.target.value;
@@ -5193,11 +5763,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5193
5763
  },
5194
5764
  [editor]
5195
5765
  );
5196
- const handlePageSelect = useCallback14((path) => {
5766
+ const handlePageSelect = useCallback17((path) => {
5197
5767
  setCurrentHref(path);
5198
5768
  setIsExternalUrl(false);
5199
5769
  }, []);
5200
- const handleExternalUrlApply = useCallback14(() => {
5770
+ const handleExternalUrlApply = useCallback17(() => {
5201
5771
  if (externalUrl) {
5202
5772
  setCurrentHref(externalUrl);
5203
5773
  }
@@ -5263,7 +5833,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5263
5833
  // Icon mode: render children directly, no text editing
5264
5834
  children
5265
5835
  ) : editor ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
5266
- createPortal5(
5836
+ createPortal6(
5267
5837
  /* @__PURE__ */ jsxs9(
5268
5838
  BubbleMenu,
5269
5839
  {
@@ -5326,7 +5896,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5326
5896
  ),
5327
5897
  editingMode === "text" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
5328
5898
  /* @__PURE__ */ jsx15(EditorContent2, { editor }),
5329
- actionButtonsPos && createPortal5(
5899
+ actionButtonsPos && createPortal6(
5330
5900
  /* @__PURE__ */ jsxs9(
5331
5901
  "div",
5332
5902
  {
@@ -5457,23 +6027,223 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
5457
6027
  }
5458
6028
 
5459
6029
  // src/components/YaContainer.tsx
5460
- import { useCallback as useCallback15, useEffect as useEffect14, useRef as useRef14, useState as useState13 } from "react";
5461
- import { createPortal as createPortal6 } from "react-dom";
5462
- import {
5463
- useFloating as useFloating3,
5464
- useHover,
5465
- useInteractions as useInteractions2,
5466
- offset as offset3,
5467
- flip as flip3,
5468
- shift as shift3,
5469
- FloatingPortal as FloatingPortal2
5470
- } from "@floating-ui/react";
6030
+ import { useCallback as useCallback19, useEffect as useEffect17, useRef as useRef18, useState as useState17 } from "react";
6031
+ import { createPortal as createPortal8 } from "react-dom";
6032
+
6033
+ // src/components/Tooltip.tsx
6034
+ import { useState as useState16, useRef as useRef17, useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useCallback as useCallback18 } from "react";
6035
+ import { createPortal as createPortal7 } from "react-dom";
6036
+
6037
+ // src/components/tooltip.css
6038
+ styleInject('.ya-tooltip-trigger {\n display: inline-flex;\n}\n.ya-tooltip-v2 {\n position: fixed;\n z-index: 10000;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n animation: ya-tooltip-v2-fade-in 0.15s ease-out;\n}\n@keyframes ya-tooltip-v2-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-tooltip-v2-arrow {\n position: absolute;\n width: 0;\n height: 0;\n left: 50%;\n transform: translateX(-50%);\n}\n.ya-tooltip-v2-bottom .ya-tooltip-v2-arrow {\n top: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-top .ya-tooltip-v2-arrow {\n bottom: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-left .ya-tooltip-v2-arrow {\n right: -6px;\n left: auto;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-left: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-right .ya-tooltip-v2-arrow {\n left: -6px;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-right: 6px solid #1a1a1a;\n}\n');
6039
+
6040
+ // src/components/Tooltip.tsx
6041
+ import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
6042
+ function Tooltip({
6043
+ content,
6044
+ children,
6045
+ position = "bottom",
6046
+ delay = 0
6047
+ }) {
6048
+ const [isVisible, setIsVisible] = useState16(false);
6049
+ const [tooltipPosition, setTooltipPosition] = useState16(null);
6050
+ const [isMounted, setIsMounted] = useState16(false);
6051
+ const triggerRef = useRef17(null);
6052
+ const tooltipRef = useRef17(null);
6053
+ const timeoutRef = useRef17(null);
6054
+ useEffect16(() => {
6055
+ setIsMounted(true);
6056
+ }, []);
6057
+ const calculatePosition = useCallback18(() => {
6058
+ if (!triggerRef.current) return null;
6059
+ const triggerRect = triggerRef.current.getBoundingClientRect();
6060
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
6061
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
6062
+ const gap = 8;
6063
+ const arrowSize = 6;
6064
+ const tooltipWidth = 200;
6065
+ const tooltipHeight = 40;
6066
+ const padding = 12;
6067
+ let top = 0;
6068
+ let left = 0;
6069
+ let finalPosition = position;
6070
+ let useTransformX = false;
6071
+ let arrowOffset = 0;
6072
+ switch (position) {
6073
+ case "top":
6074
+ top = triggerRect.top + scrollTop - tooltipHeight - gap - arrowSize;
6075
+ left = triggerRect.left + scrollLeft + triggerRect.width / 2;
6076
+ useTransformX = true;
6077
+ if (triggerRect.top < tooltipHeight + gap + arrowSize) {
6078
+ finalPosition = "bottom";
6079
+ top = triggerRect.bottom + scrollTop + gap + arrowSize;
6080
+ }
6081
+ break;
6082
+ case "bottom":
6083
+ top = triggerRect.bottom + scrollTop + gap + arrowSize;
6084
+ left = triggerRect.left + scrollLeft + triggerRect.width / 2;
6085
+ useTransformX = true;
6086
+ if (window.innerHeight - triggerRect.bottom < tooltipHeight + gap + arrowSize) {
6087
+ finalPosition = "top";
6088
+ top = triggerRect.top + scrollTop - tooltipHeight - gap - arrowSize;
6089
+ }
6090
+ break;
6091
+ case "left":
6092
+ top = triggerRect.top + scrollTop + triggerRect.height / 2 - tooltipHeight / 2;
6093
+ left = triggerRect.left + scrollLeft - tooltipWidth - gap - arrowSize;
6094
+ if (triggerRect.left < tooltipWidth + gap + arrowSize) {
6095
+ finalPosition = "right";
6096
+ left = triggerRect.right + scrollLeft + gap + arrowSize;
6097
+ }
6098
+ break;
6099
+ case "right":
6100
+ top = triggerRect.top + scrollTop + triggerRect.height / 2 - tooltipHeight / 2;
6101
+ left = triggerRect.right + scrollLeft + gap + arrowSize;
6102
+ if (window.innerWidth - triggerRect.right < tooltipWidth + gap + arrowSize) {
6103
+ finalPosition = "left";
6104
+ left = triggerRect.left + scrollLeft - tooltipWidth - gap - arrowSize;
6105
+ }
6106
+ break;
6107
+ }
6108
+ const triggerCenterX = triggerRect.left + triggerRect.width / 2;
6109
+ if (finalPosition === "top" || finalPosition === "bottom") {
6110
+ const tooltipLeftEdge = triggerCenterX - tooltipWidth / 2;
6111
+ const tooltipRightEdge = triggerCenterX + tooltipWidth / 2;
6112
+ if (tooltipLeftEdge < padding) {
6113
+ const adjustment = padding - tooltipLeftEdge;
6114
+ left = padding + tooltipWidth / 2 + scrollLeft;
6115
+ arrowOffset = -adjustment;
6116
+ useTransformX = true;
6117
+ } else if (tooltipRightEdge > window.innerWidth - padding) {
6118
+ const adjustment = tooltipRightEdge - (window.innerWidth - padding);
6119
+ left = window.innerWidth - padding - tooltipWidth / 2 + scrollLeft;
6120
+ arrowOffset = adjustment;
6121
+ useTransformX = true;
6122
+ }
6123
+ }
6124
+ return { top, left, position: finalPosition, useTransformX, arrowOffset, triggerCenterX, adjusted: false };
6125
+ }, [position]);
6126
+ const handleMouseEnter = () => {
6127
+ timeoutRef.current = setTimeout(() => {
6128
+ const pos = calculatePosition();
6129
+ if (pos) {
6130
+ setTooltipPosition(pos);
6131
+ setIsVisible(true);
6132
+ }
6133
+ }, delay);
6134
+ };
6135
+ const handleMouseLeave = () => {
6136
+ if (timeoutRef.current) {
6137
+ clearTimeout(timeoutRef.current);
6138
+ }
6139
+ setIsVisible(false);
6140
+ setTooltipPosition(null);
6141
+ };
6142
+ useEffect16(() => {
6143
+ return () => {
6144
+ if (timeoutRef.current) {
6145
+ clearTimeout(timeoutRef.current);
6146
+ }
6147
+ };
6148
+ }, []);
6149
+ const edgePadding = 12;
6150
+ useLayoutEffect3(() => {
6151
+ if (!isVisible || !tooltipRef.current || !tooltipPosition || tooltipPosition.adjusted) {
6152
+ return;
6153
+ }
6154
+ const rect = tooltipRef.current.getBoundingClientRect();
6155
+ const viewportWidth = window.innerWidth;
6156
+ const viewportHeight = window.innerHeight;
6157
+ const triggerCenterX = tooltipPosition.triggerCenterX ?? 0;
6158
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
6159
+ if (tooltipPosition.position === "top" || tooltipPosition.position === "bottom") {
6160
+ const actualWidth = rect.width;
6161
+ const idealLeft = triggerCenterX - actualWidth / 2;
6162
+ const idealRight = triggerCenterX + actualWidth / 2;
6163
+ let finalLeft;
6164
+ let newArrowOffset = 0;
6165
+ if (idealLeft >= edgePadding && idealRight <= viewportWidth - edgePadding) {
6166
+ finalLeft = triggerCenterX + scrollLeft;
6167
+ } else if (idealLeft < edgePadding) {
6168
+ finalLeft = edgePadding + actualWidth / 2 + scrollLeft;
6169
+ newArrowOffset = triggerCenterX - (edgePadding + actualWidth / 2);
6170
+ } else {
6171
+ finalLeft = viewportWidth - edgePadding - actualWidth / 2 + scrollLeft;
6172
+ newArrowOffset = triggerCenterX - (viewportWidth - edgePadding - actualWidth / 2);
6173
+ }
6174
+ let adjustedTop = tooltipPosition.top;
6175
+ if (rect.bottom > viewportHeight - edgePadding) {
6176
+ adjustedTop -= rect.bottom - viewportHeight + edgePadding;
6177
+ }
6178
+ if (rect.top < edgePadding) {
6179
+ adjustedTop += edgePadding - rect.top;
6180
+ }
6181
+ setTooltipPosition(
6182
+ (prev) => prev ? { ...prev, left: finalLeft, top: adjustedTop, arrowOffset: newArrowOffset, useTransformX: true, adjusted: true } : null
6183
+ );
6184
+ } else {
6185
+ let adjustedTop = tooltipPosition.top;
6186
+ if (rect.bottom > viewportHeight - edgePadding) {
6187
+ adjustedTop -= rect.bottom - viewportHeight + edgePadding;
6188
+ }
6189
+ if (rect.top < edgePadding) {
6190
+ adjustedTop += edgePadding - rect.top;
6191
+ }
6192
+ if (adjustedTop !== tooltipPosition.top) {
6193
+ setTooltipPosition(
6194
+ (prev) => prev ? { ...prev, top: adjustedTop, adjusted: true } : null
6195
+ );
6196
+ } else {
6197
+ setTooltipPosition((prev) => prev ? { ...prev, adjusted: true } : null);
6198
+ }
6199
+ }
6200
+ }, [isVisible, tooltipPosition]);
6201
+ const tooltipContent = isMounted && isVisible && tooltipPosition ? createPortal7(
6202
+ /* @__PURE__ */ jsxs10(
6203
+ "div",
6204
+ {
6205
+ ref: tooltipRef,
6206
+ className: `ya-tooltip-v2 ya-tooltip-v2-${tooltipPosition.position}`,
6207
+ style: {
6208
+ top: `${tooltipPosition.top}px`,
6209
+ left: `${tooltipPosition.left}px`,
6210
+ transform: tooltipPosition.useTransformX ? "translateX(-50%)" : void 0
6211
+ },
6212
+ role: "tooltip",
6213
+ children: [
6214
+ content,
6215
+ /* @__PURE__ */ jsx16(
6216
+ "div",
6217
+ {
6218
+ className: "ya-tooltip-v2-arrow",
6219
+ style: tooltipPosition.arrowOffset ? { left: `calc(50% + ${tooltipPosition.arrowOffset}px)`, transform: "translateX(-50%)" } : void 0
6220
+ }
6221
+ )
6222
+ ]
6223
+ }
6224
+ ),
6225
+ document.body
6226
+ ) : null;
6227
+ return /* @__PURE__ */ jsxs10(Fragment5, { children: [
6228
+ /* @__PURE__ */ jsx16(
6229
+ "div",
6230
+ {
6231
+ ref: triggerRef,
6232
+ onMouseEnter: handleMouseEnter,
6233
+ onMouseLeave: handleMouseLeave,
6234
+ className: "ya-tooltip-trigger",
6235
+ children
6236
+ }
6237
+ ),
6238
+ tooltipContent
6239
+ ] });
6240
+ }
5471
6241
 
5472
6242
  // src/components/ya-container.css
5473
6243
  styleInject('.ya-container {\n position: relative;\n}\n.ya-container-has-overlay::after {\n content: "";\n position: absolute;\n inset: 0;\n background: var(--ya-overlay-color, transparent);\n opacity: var(--ya-overlay-opacity, 0);\n pointer-events: none;\n z-index: 0;\n}\n.ya-container > *:not(.ya-container-toolbar) {\n position: relative;\n z-index: 1;\n}\n.ya-container-editable {\n transition: outline 0.15s ease;\n pointer-events: none;\n}\n.ya-container-editable > * {\n pointer-events: auto;\n}\n.ya-container-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: -2px;\n}\nbody.builder-selector-active .ya-container-editable:hover {\n outline: none;\n}\n.ya-container-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar {\n display: flex;\n gap: 4px;\n background: rgba(26, 26, 26, 0.95);\n padding: 6px 8px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: ya-container-toolbar-fade-in 0.15s ease;\n}\n@keyframes ya-container-toolbar-fade-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ya-container-toolbar button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: #3a3a3a;\n border: none;\n border-radius: 6px;\n color: #ffffff;\n cursor: pointer;\n transition: background 0.15s ease, transform 0.1s ease;\n}\n.ya-container-toolbar button:hover {\n background: #4a4a4a;\n transform: scale(1.05);\n}\n.ya-container-toolbar button:active {\n transform: scale(0.98);\n}\n.ya-container-toolbar button.active {\n background: var(--color-primary, #D4A574);\n color: #1a1a1a;\n}\n.ya-container-toolbar button svg {\n width: 18px;\n height: 18px;\n}\n.ya-container-toolbar button[aria-label="Clear background"] {\n background: #3a2a2a;\n}\n.ya-container-toolbar button[aria-label="Clear background"]:hover {\n background: #5a3a3a;\n}\n.ya-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar button:focus-visible {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 2px;\n}\n.ya-container-drop-target {\n outline: 2px dashed var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -2px;\n pointer-events: auto !important;\n}\n.ya-container-drop-target .ya-container-toolbar {\n display: none !important;\n}\n.ya-container-drop-hover {\n outline: 3px solid var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -3px;\n}\n.ya-container-drop-hover::before {\n content: "";\n position: absolute;\n inset: 0;\n background: rgba(59, 130, 246, 0.08);\n pointer-events: none;\n z-index: 10;\n animation: ya-container-drop-pulse 1s ease-in-out infinite;\n}\n@keyframes ya-container-drop-pulse {\n 0%, 100% {\n background: rgba(59, 130, 246, 0.05);\n }\n 50% {\n background: rgba(59, 130, 246, 0.12);\n }\n}\n.ya-container-tooltip {\n background: #1a1a1a;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n z-index: 10000;\n pointer-events: none;\n animation: ya-container-tooltip-fade-in 0.1s ease;\n}\n@keyframes ya-container-tooltip-fade-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n');
5474
6244
 
5475
6245
  // src/components/YaContainer.tsx
5476
- import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
6246
+ import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
5477
6247
  function parseBackgroundConfig(value) {
5478
6248
  if (!value) {
5479
6249
  return { type: "none" };
@@ -5514,61 +6284,9 @@ function deriveContainerLabel(element) {
5514
6284
  };
5515
6285
  return tagLabels[tagName] || "Section";
5516
6286
  }
5517
- function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearClick, hasBackground }) {
5518
- const [position, setPosition] = useState13(null);
5519
- const [imageOpen, setImageOpen] = useState13(false);
5520
- const [colorOpen, setColorOpen] = useState13(false);
5521
- const [aiOpen, setAiOpen] = useState13(false);
5522
- const [clearOpen, setClearOpen] = useState13(false);
5523
- const {
5524
- refs: imageRefs,
5525
- floatingStyles: imageStyles,
5526
- context: imageContext
5527
- } = useFloating3({
5528
- open: imageOpen,
5529
- onOpenChange: setImageOpen,
5530
- middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
5531
- placement: "bottom"
5532
- });
5533
- const imageHover = useHover(imageContext, { delay: { open: 0, close: 0 } });
5534
- const { getReferenceProps: getImageRefProps, getFloatingProps: getImageFloatProps } = useInteractions2([imageHover]);
5535
- const {
5536
- refs: colorRefs,
5537
- floatingStyles: colorStyles,
5538
- context: colorContext
5539
- } = useFloating3({
5540
- open: colorOpen,
5541
- onOpenChange: setColorOpen,
5542
- middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
5543
- placement: "bottom"
5544
- });
5545
- const colorHover = useHover(colorContext, { delay: { open: 0, close: 0 } });
5546
- const { getReferenceProps: getColorRefProps, getFloatingProps: getColorFloatProps } = useInteractions2([colorHover]);
5547
- const {
5548
- refs: aiRefs,
5549
- floatingStyles: aiStyles,
5550
- context: aiContext
5551
- } = useFloating3({
5552
- open: aiOpen,
5553
- onOpenChange: setAiOpen,
5554
- middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
5555
- placement: "bottom"
5556
- });
5557
- const aiHover = useHover(aiContext, { delay: { open: 0, close: 0 } });
5558
- const { getReferenceProps: getAiRefProps, getFloatingProps: getAiFloatProps } = useInteractions2([aiHover]);
5559
- const {
5560
- refs: clearRefs,
5561
- floatingStyles: clearStyles,
5562
- context: clearContext
5563
- } = useFloating3({
5564
- open: clearOpen,
5565
- onOpenChange: setClearOpen,
5566
- middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
5567
- placement: "bottom"
5568
- });
5569
- const clearHover = useHover(clearContext, { delay: { open: 0, close: 0 } });
5570
- const { getReferenceProps: getClearRefProps, getFloatingProps: getClearFloatProps } = useInteractions2([clearHover]);
5571
- useEffect14(() => {
6287
+ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAIClick, onClearClick, hasBackground }) {
6288
+ const [position, setPosition] = useState17(null);
6289
+ useEffect17(() => {
5572
6290
  const updatePosition = () => {
5573
6291
  if (containerRef.current) {
5574
6292
  const rect = containerRef.current.getBoundingClientRect();
@@ -5587,8 +6305,8 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
5587
6305
  };
5588
6306
  }, [containerRef]);
5589
6307
  if (!position) return null;
5590
- return createPortal6(
5591
- /* @__PURE__ */ jsxs10(
6308
+ return createPortal8(
6309
+ /* @__PURE__ */ jsxs11(
5592
6310
  "div",
5593
6311
  {
5594
6312
  className: "ya-container-toolbar",
@@ -5599,81 +6317,43 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
5599
6317
  },
5600
6318
  onClick: (e) => e.stopPropagation(),
5601
6319
  children: [
5602
- /* @__PURE__ */ jsx16(
6320
+ /* @__PURE__ */ jsx17(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx17(
5603
6321
  "button",
5604
6322
  {
5605
- ref: imageRefs.setReference,
5606
6323
  type: "button",
5607
6324
  onClick: onImageClick,
5608
6325
  "aria-label": "Edit background image",
5609
- ...getImageRefProps(),
5610
- children: /* @__PURE__ */ jsxs10("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
5611
- /* @__PURE__ */ jsx16("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
5612
- /* @__PURE__ */ jsx16("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
5613
- /* @__PURE__ */ jsx16("polyline", { points: "21 15 16 10 5 21" })
6326
+ children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6327
+ /* @__PURE__ */ jsx17("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
6328
+ /* @__PURE__ */ jsx17("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
6329
+ /* @__PURE__ */ jsx17("polyline", { points: "21 15 16 10 5 21" })
5614
6330
  ] })
5615
6331
  }
5616
- ),
5617
- imageOpen && /* @__PURE__ */ jsx16(FloatingPortal2, { children: /* @__PURE__ */ jsx16(
5618
- "div",
5619
- {
5620
- ref: imageRefs.setFloating,
5621
- className: "ya-container-tooltip",
5622
- style: imageStyles,
5623
- ...getImageFloatProps(),
5624
- children: "Background Image"
5625
- }
5626
6332
  ) }),
5627
- /* @__PURE__ */ jsx16(
6333
+ /* @__PURE__ */ jsx17(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx17(
5628
6334
  "button",
5629
6335
  {
5630
- ref: colorRefs.setReference,
5631
6336
  type: "button",
5632
6337
  onClick: onColorClick,
5633
6338
  "aria-label": "Edit background color",
5634
- ...getColorRefProps(),
5635
- children: /* @__PURE__ */ jsxs10("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
5636
- /* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "10" }),
5637
- /* @__PURE__ */ jsx16("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
6339
+ children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6340
+ /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "10" }),
6341
+ /* @__PURE__ */ jsx17("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
5638
6342
  ] })
5639
6343
  }
5640
- ),
5641
- colorOpen && /* @__PURE__ */ jsx16(FloatingPortal2, { children: /* @__PURE__ */ jsx16(
5642
- "div",
6344
+ ) }),
6345
+ hasBackground && /* @__PURE__ */ jsx17(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx17(
6346
+ "button",
5643
6347
  {
5644
- ref: colorRefs.setFloating,
5645
- className: "ya-container-tooltip",
5646
- style: colorStyles,
5647
- ...getColorFloatProps(),
5648
- children: "Background Color"
6348
+ type: "button",
6349
+ onClick: onClearClick,
6350
+ "aria-label": "Clear background",
6351
+ children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6352
+ /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "10" }),
6353
+ /* @__PURE__ */ jsx17("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
6354
+ ] })
5649
6355
  }
5650
- ) }),
5651
- hasBackground && /* @__PURE__ */ jsxs10(Fragment5, { children: [
5652
- /* @__PURE__ */ jsx16(
5653
- "button",
5654
- {
5655
- ref: clearRefs.setReference,
5656
- type: "button",
5657
- onClick: onClearClick,
5658
- "aria-label": "Clear background",
5659
- ...getClearRefProps(),
5660
- children: /* @__PURE__ */ jsxs10("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
5661
- /* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "10" }),
5662
- /* @__PURE__ */ jsx16("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
5663
- ] })
5664
- }
5665
- ),
5666
- clearOpen && /* @__PURE__ */ jsx16(FloatingPortal2, { children: /* @__PURE__ */ jsx16(
5667
- "div",
5668
- {
5669
- ref: clearRefs.setFloating,
5670
- className: "ya-container-tooltip",
5671
- style: clearStyles,
5672
- ...getClearFloatProps(),
5673
- children: "Remove Background"
5674
- }
5675
- ) })
5676
- ] })
6356
+ ) })
5677
6357
  ]
5678
6358
  }
5679
6359
  ),
@@ -5689,13 +6369,13 @@ function YaContainer({
5689
6369
  defaultBackground
5690
6370
  }) {
5691
6371
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
5692
- const containerRef = useRef14(null);
5693
- const [isHovered, setIsHovered] = useState13(false);
5694
- const [isSelected, setIsSelected] = useState13(false);
5695
- const [isDropMode, setIsDropMode] = useState13(false);
5696
- const [isDropHover, setIsDropHover] = useState13(false);
5697
- const [previewConfig, setPreviewConfig] = useState13(null);
5698
- useEffect14(() => {
6372
+ const containerRef = useRef18(null);
6373
+ const [isHovered, setIsHovered] = useState17(false);
6374
+ const [isSelected, setIsSelected] = useState17(false);
6375
+ const [isDropMode, setIsDropMode] = useState17(false);
6376
+ const [isDropHover, setIsDropHover] = useState17(false);
6377
+ const [previewConfig, setPreviewConfig] = useState17(null);
6378
+ useEffect17(() => {
5699
6379
  if (mode !== "inline-edit") return;
5700
6380
  const containerEl = containerRef.current;
5701
6381
  if (!containerEl) return;
@@ -5738,7 +6418,7 @@ function YaContainer({
5738
6418
  overlayCustomProps["--ya-overlay-color"] = displayConfig.overlay.color;
5739
6419
  overlayCustomProps["--ya-overlay-opacity"] = displayConfig.overlay.opacity;
5740
6420
  }
5741
- const handleImageClick = useCallback15(() => {
6421
+ const handleImageClick = useCallback19(() => {
5742
6422
  if (mode !== "inline-edit") return;
5743
6423
  setIsSelected(true);
5744
6424
  const rect = containerRef.current?.getBoundingClientRect();
@@ -5758,7 +6438,7 @@ function YaContainer({
5758
6438
  "*"
5759
6439
  );
5760
6440
  }, [mode, fieldId, backgroundConfig]);
5761
- const handleColorClick = useCallback15(() => {
6441
+ const handleColorClick = useCallback19(() => {
5762
6442
  if (mode !== "inline-edit") return;
5763
6443
  setIsSelected(true);
5764
6444
  const rect = containerRef.current?.getBoundingClientRect();
@@ -5778,7 +6458,7 @@ function YaContainer({
5778
6458
  "*"
5779
6459
  );
5780
6460
  }, [mode, fieldId, backgroundConfig]);
5781
- const handleAIClick = useCallback15(() => {
6461
+ const handleAIClick = useCallback19(() => {
5782
6462
  if (mode !== "inline-edit") return;
5783
6463
  const label = deriveContainerLabel(containerRef.current);
5784
6464
  window.parent.postMessage(
@@ -5791,14 +6471,14 @@ function YaContainer({
5791
6471
  "*"
5792
6472
  );
5793
6473
  }, [mode, fieldId, backgroundConfig]);
5794
- const handleClearClick = useCallback15(() => {
6474
+ const handleClearClick = useCallback19(() => {
5795
6475
  if (mode !== "inline-edit") return;
5796
6476
  const clearedConfig = { type: "none" };
5797
6477
  const serialized = serializeBackgroundConfig(clearedConfig);
5798
6478
  setValue(fieldId, serialized);
5799
6479
  saveToWorker?.(fieldId, serialized);
5800
6480
  }, [mode, fieldId, setValue, saveToWorker]);
5801
- useEffect14(() => {
6481
+ useEffect17(() => {
5802
6482
  if (mode !== "inline-edit") return;
5803
6483
  const handleMessage2 = (event) => {
5804
6484
  if (event.data?.type === "YA_CONTAINER_UPDATE_PREVIEW" && event.data.fieldId === fieldId) {
@@ -5819,7 +6499,7 @@ function YaContainer({
5819
6499
  window.addEventListener("message", handleMessage2);
5820
6500
  return () => window.removeEventListener("message", handleMessage2);
5821
6501
  }, [mode, fieldId]);
5822
- useEffect14(() => {
6502
+ useEffect17(() => {
5823
6503
  if (mode !== "inline-edit") return;
5824
6504
  const handleDropModeMessage = (event) => {
5825
6505
  if (event.data?.type === "DROP_MODE_START") {
@@ -5833,7 +6513,7 @@ function YaContainer({
5833
6513
  window.addEventListener("message", handleDropModeMessage);
5834
6514
  return () => window.removeEventListener("message", handleDropModeMessage);
5835
6515
  }, [mode]);
5836
- const handleDragEnter = useCallback15(
6516
+ const handleDragEnter = useCallback19(
5837
6517
  (e) => {
5838
6518
  if (!isDropMode) return;
5839
6519
  e.preventDefault();
@@ -5857,7 +6537,7 @@ function YaContainer({
5857
6537
  },
5858
6538
  [isDropMode, fieldId]
5859
6539
  );
5860
- const handleDragOver = useCallback15(
6540
+ const handleDragOver = useCallback19(
5861
6541
  (e) => {
5862
6542
  if (!isDropMode) return;
5863
6543
  e.preventDefault();
@@ -5865,7 +6545,7 @@ function YaContainer({
5865
6545
  },
5866
6546
  [isDropMode]
5867
6547
  );
5868
- const handleDragLeave = useCallback15(
6548
+ const handleDragLeave = useCallback19(
5869
6549
  (e) => {
5870
6550
  if (!isDropMode) return;
5871
6551
  e.preventDefault();
@@ -5879,7 +6559,7 @@ function YaContainer({
5879
6559
  },
5880
6560
  [isDropMode]
5881
6561
  );
5882
- const handleDrop = useCallback15(
6562
+ const handleDrop = useCallback19(
5883
6563
  (e) => {
5884
6564
  if (!isDropMode) return;
5885
6565
  e.preventDefault();
@@ -5897,7 +6577,7 @@ function YaContainer({
5897
6577
  },
5898
6578
  [isDropMode, fieldId]
5899
6579
  );
5900
- useEffect14(() => {
6580
+ useEffect17(() => {
5901
6581
  if (!isSelected || mode !== "inline-edit") return;
5902
6582
  let lastRectKey = "";
5903
6583
  let lastTime = 0;
@@ -5932,7 +6612,7 @@ function YaContainer({
5932
6612
  return () => cancelAnimationFrame(rafId);
5933
6613
  }, [isSelected, fieldId, mode]);
5934
6614
  if (mode === "read-only") {
5935
- return /* @__PURE__ */ jsx16(
6615
+ return /* @__PURE__ */ jsx17(
5936
6616
  Tag,
5937
6617
  {
5938
6618
  className: `ya-container ${className || ""}`,
@@ -5956,7 +6636,7 @@ function YaContainer({
5956
6636
  isDropHover ? "ya-container-drop-hover" : "",
5957
6637
  className || ""
5958
6638
  ].filter(Boolean).join(" ");
5959
- return /* @__PURE__ */ jsxs10(
6639
+ return /* @__PURE__ */ jsxs11(
5960
6640
  Tag,
5961
6641
  {
5962
6642
  ref: containerRef,
@@ -5975,7 +6655,7 @@ function YaContainer({
5975
6655
  onDrop: handleDrop,
5976
6656
  children: [
5977
6657
  children,
5978
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx16(
6658
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx17(
5979
6659
  Toolbar,
5980
6660
  {
5981
6661
  containerRef,
@@ -5992,10 +6672,10 @@ function YaContainer({
5992
6672
  }
5993
6673
 
5994
6674
  // src/components/StaticText.tsx
5995
- import { jsx as jsx17 } from "react/jsx-runtime";
6675
+ import { jsx as jsx18 } from "react/jsx-runtime";
5996
6676
  function MpText({ fieldId, className, as: Component = "span", children }) {
5997
6677
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
5998
- return /* @__PURE__ */ jsx17(
6678
+ return /* @__PURE__ */ jsx18(
5999
6679
  Component,
6000
6680
  {
6001
6681
  className,
@@ -6006,7 +6686,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
6006
6686
  }
6007
6687
 
6008
6688
  // src/components/StaticImage.tsx
6009
- import { jsx as jsx18 } from "react/jsx-runtime";
6689
+ import { jsx as jsx19 } from "react/jsx-runtime";
6010
6690
  function parseImageValue2(value) {
6011
6691
  if (!value) {
6012
6692
  return { src: "" };
@@ -6042,7 +6722,7 @@ function MpImage({
6042
6722
  const altText = imageData.alt || alt || fallbackAlt || "";
6043
6723
  const objectFit = imageData.objectFit || propObjectFit || "cover";
6044
6724
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
6045
- return /* @__PURE__ */ jsx18(
6725
+ return /* @__PURE__ */ jsx19(
6046
6726
  "img",
6047
6727
  {
6048
6728
  src: resolveAssetUrl(src),
@@ -6060,7 +6740,7 @@ function MpImage({
6060
6740
 
6061
6741
  // src/components/MarkdownText.tsx
6062
6742
  import { Fragment as Fragment6 } from "react";
6063
- import { jsx as jsx19 } from "react/jsx-runtime";
6743
+ import { jsx as jsx20 } from "react/jsx-runtime";
6064
6744
  function tokenize(text2) {
6065
6745
  const tokens = [];
6066
6746
  let remaining = text2;
@@ -6122,13 +6802,13 @@ function tokensToElements(tokens) {
6122
6802
  return tokens.map((token, index) => {
6123
6803
  switch (token.type) {
6124
6804
  case "text":
6125
- return /* @__PURE__ */ jsx19(Fragment6, { children: token.content }, index);
6805
+ return /* @__PURE__ */ jsx20(Fragment6, { children: token.content }, index);
6126
6806
  case "bold":
6127
- return /* @__PURE__ */ jsx19("strong", { children: token.content }, index);
6807
+ return /* @__PURE__ */ jsx20("strong", { children: token.content }, index);
6128
6808
  case "italic":
6129
- return /* @__PURE__ */ jsx19("em", { children: token.content }, index);
6809
+ return /* @__PURE__ */ jsx20("em", { children: token.content }, index);
6130
6810
  case "link":
6131
- return /* @__PURE__ */ jsx19(
6811
+ return /* @__PURE__ */ jsx20(
6132
6812
  "a",
6133
6813
  {
6134
6814
  href: token.url,
@@ -6140,7 +6820,7 @@ function tokensToElements(tokens) {
6140
6820
  index
6141
6821
  );
6142
6822
  case "newline":
6143
- return /* @__PURE__ */ jsx19("br", {}, index);
6823
+ return /* @__PURE__ */ jsx20("br", {}, index);
6144
6824
  default:
6145
6825
  return null;
6146
6826
  }
@@ -6152,15 +6832,15 @@ function parseMarkdownToElements(content) {
6152
6832
  }
6153
6833
  function MarkdownText({ content, className }) {
6154
6834
  const elements = parseMarkdownToElements(content);
6155
- return /* @__PURE__ */ jsx19("span", { className, children: elements });
6835
+ return /* @__PURE__ */ jsx20("span", { className, children: elements });
6156
6836
  }
6157
6837
 
6158
6838
  // src/router/Link.tsx
6159
6839
  import { Link as WouterLink2 } from "wouter";
6160
- import { jsx as jsx20 } from "react/jsx-runtime";
6840
+ import { jsx as jsx21 } from "react/jsx-runtime";
6161
6841
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
6162
6842
  const target = href ?? to ?? "/";
6163
- return /* @__PURE__ */ jsx20(WouterLink2, { href: target, className, onClick, replace, ...props, children });
6843
+ return /* @__PURE__ */ jsx21(WouterLink2, { href: target, className, onClick, replace, ...props, children });
6164
6844
  }
6165
6845
 
6166
6846
  // src/router/useNavigate.ts
@@ -6179,7 +6859,7 @@ function useNavigate() {
6179
6859
 
6180
6860
  // src/router/Router.tsx
6181
6861
  import { Router as WouterRouter } from "wouter";
6182
- import { jsx as jsx21 } from "react/jsx-runtime";
6862
+ import { jsx as jsx22 } from "react/jsx-runtime";
6183
6863
  function detectBasename() {
6184
6864
  if (typeof window === "undefined") return "";
6185
6865
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -6194,11 +6874,11 @@ function detectBasename() {
6194
6874
  }
6195
6875
  function Router({ children, base }) {
6196
6876
  const basename = base ?? detectBasename();
6197
- return /* @__PURE__ */ jsx21(WouterRouter, { base: basename, children });
6877
+ return /* @__PURE__ */ jsx22(WouterRouter, { base: basename, children });
6198
6878
  }
6199
6879
 
6200
6880
  // src/router/ScrollRestoration.tsx
6201
- import { useEffect as useEffect15, useRef as useRef15 } from "react";
6881
+ import { useEffect as useEffect18, useRef as useRef19 } from "react";
6202
6882
  import { useLocation as useLocation3 } from "wouter";
6203
6883
  var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
6204
6884
  var HISTORY_INDEX_KEY = "yoamigo-history-index";
@@ -6234,10 +6914,10 @@ function setHistoryIndex(index) {
6234
6914
  var globalHistoryIndex = 0;
6235
6915
  function ScrollRestoration() {
6236
6916
  const [location] = useLocation3();
6237
- const previousLocation = useRef15(location);
6238
- const isPopState = useRef15(false);
6239
- const scrollPositionsRef = useRef15({});
6240
- useEffect15(() => {
6917
+ const previousLocation = useRef19(location);
6918
+ const isPopState = useRef19(false);
6919
+ const scrollPositionsRef = useRef19({});
6920
+ useEffect18(() => {
6241
6921
  if (typeof history !== "undefined" && "scrollRestoration" in history) {
6242
6922
  history.scrollRestoration = "manual";
6243
6923
  }
@@ -6255,7 +6935,7 @@ function ScrollRestoration() {
6255
6935
  window.addEventListener("popstate", handlePopState);
6256
6936
  return () => window.removeEventListener("popstate", handlePopState);
6257
6937
  }, []);
6258
- useEffect15(() => {
6938
+ useEffect18(() => {
6259
6939
  if (previousLocation.current === location) return;
6260
6940
  const prevHistoryIndex = globalHistoryIndex;
6261
6941
  const currentScrollY = window.scrollY;
@@ -6275,7 +6955,7 @@ function ScrollRestoration() {
6275
6955
  }
6276
6956
  previousLocation.current = location;
6277
6957
  }, [location]);
6278
- useEffect15(() => {
6958
+ useEffect18(() => {
6279
6959
  let timeoutId;
6280
6960
  const handleScroll = () => {
6281
6961
  clearTimeout(timeoutId);
@@ -6326,6 +7006,7 @@ export {
6326
7006
  MpImage as StaticImage,
6327
7007
  MpText as StaticText,
6328
7008
  Switch,
7009
+ Tooltip,
6329
7010
  YaContainer,
6330
7011
  YaEmbed,
6331
7012
  YaImage,