@yoamigo.com/core 0.4.0 → 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.
- package/dist/content-helpers-kWphH5Tn.d.ts +376 -0
- package/dist/index.d.ts +15 -222
- package/dist/index.js +1146 -465
- package/dist/prod.d.ts +1 -1
- package/dist/prod.js +30 -8
- package/package.json +1 -2
- package/dist/MarkdownText-_ykp-njt.d.ts +0 -157
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
|
|
1325
|
-
import { createPortal as
|
|
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
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
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
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
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
|
-
|
|
1368
|
-
|
|
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:
|
|
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
|
|
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 =
|
|
1489
|
-
const showTimerRef =
|
|
1490
|
-
const hideTimerRef =
|
|
1491
|
-
const [popoverState, setPopoverState] =
|
|
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 =
|
|
1564
|
+
const hidePopover = useCallback3(() => {
|
|
1503
1565
|
clearTimeout(showTimerRef.current);
|
|
1504
1566
|
setPopoverState((prev) => ({ ...prev, isVisible: false }));
|
|
1505
1567
|
}, []);
|
|
1506
|
-
const scheduleHide =
|
|
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 =
|
|
1574
|
+
const cancelHide = useCallback3(() => {
|
|
1513
1575
|
clearTimeout(hideTimerRef.current);
|
|
1514
1576
|
}, []);
|
|
1515
|
-
const handlePopoverClick =
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
1627
|
-
const listenersRef =
|
|
1628
|
-
const queueRef =
|
|
1629
|
-
const processingRef =
|
|
1630
|
-
const notifyListeners =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1754
|
+
const getAnimationState = useCallback4((fieldId) => {
|
|
1693
1755
|
return animationsRef.current.get(fieldId);
|
|
1694
1756
|
}, []);
|
|
1695
|
-
const subscribe =
|
|
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 =
|
|
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 =
|
|
1744
|
-
const isFirstRender =
|
|
1745
|
-
const [phase, setPhase] =
|
|
1746
|
-
const [progress, setProgress] =
|
|
1747
|
-
const [displayValue, setDisplayValue] =
|
|
1748
|
-
const metadataRef =
|
|
1749
|
-
const animationFrameRef =
|
|
1750
|
-
const startTimeRef =
|
|
1751
|
-
const cancel =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2217
|
-
import {
|
|
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
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
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 () =>
|
|
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:
|
|
2390
|
+
ref: triggerRef,
|
|
2280
2391
|
type: "button",
|
|
2281
2392
|
className: `ya-bubble-dropdown-trigger ${open ? "is-open" : ""} ${triggerClassName}`,
|
|
2282
|
-
|
|
2283
|
-
|
|
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
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
onClick: handlePanelClick
|
|
2300
|
-
|
|
2301
|
-
|
|
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
|
|
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] =
|
|
2367
|
-
const inputRef =
|
|
2368
|
-
|
|
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
|
-
|
|
2482
|
+
useEffect6(() => {
|
|
2373
2483
|
setInputValue(value || "");
|
|
2374
2484
|
}, [value]);
|
|
2375
|
-
const handlePresetClick =
|
|
2485
|
+
const handlePresetClick = useCallback7((e, presetValue) => {
|
|
2376
2486
|
e.stopPropagation();
|
|
2377
2487
|
onChange(presetValue);
|
|
2378
2488
|
onClose();
|
|
2379
2489
|
}, [onChange, onClose]);
|
|
2380
|
-
const handlePresetMouseDown =
|
|
2490
|
+
const handlePresetMouseDown = useCallback7((e) => {
|
|
2381
2491
|
e.preventDefault();
|
|
2382
2492
|
e.stopPropagation();
|
|
2383
2493
|
}, []);
|
|
2384
|
-
const handleInputChange =
|
|
2494
|
+
const handleInputChange = useCallback7((e) => {
|
|
2385
2495
|
setInputValue(e.target.value);
|
|
2386
2496
|
}, []);
|
|
2387
|
-
const handleInputKeyDown =
|
|
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
|
|
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 =
|
|
2588
|
+
const handleClick = useCallback8((e, weightValue) => {
|
|
2479
2589
|
e.stopPropagation();
|
|
2480
2590
|
onChange(weightValue);
|
|
2481
2591
|
onClose();
|
|
2482
2592
|
}, [onChange, onClose]);
|
|
2483
|
-
const handleMouseDown =
|
|
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] =
|
|
2922
|
-
const [showBubbleMenu, setShowBubbleMenu] =
|
|
2923
|
-
const [fontSizeOpen, setFontSizeOpen] =
|
|
2924
|
-
const [fontWeightOpen, setFontWeightOpen] =
|
|
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] =
|
|
2933
|
-
const containerRef =
|
|
2934
|
-
const originalContentRef =
|
|
2935
|
-
const
|
|
2936
|
-
const
|
|
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 =
|
|
3061
|
+
const handleCancelRef = useRef8(() => {
|
|
2939
3062
|
});
|
|
2940
|
-
const handleCloseRef =
|
|
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
|
-
|
|
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
|
-
|
|
3126
|
+
useEffect7(() => {
|
|
3002
3127
|
if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
|
|
3003
3128
|
setIsEditing(false);
|
|
3004
3129
|
}
|
|
3005
3130
|
}, [activeFieldId, fieldId, isEditing]);
|
|
3006
|
-
|
|
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 =
|
|
3156
|
+
const handleSave = useCallback9(() => {
|
|
3032
3157
|
if (!editor) return;
|
|
3033
3158
|
let html = editor.getHTML();
|
|
3034
|
-
|
|
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 =
|
|
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
|
-
|
|
3176
|
+
useEffect7(() => {
|
|
3050
3177
|
handleSaveRef.current = handleSave;
|
|
3051
3178
|
handleCancelRef.current = handleCancel;
|
|
3052
3179
|
}, [handleSave, handleCancel]);
|
|
3053
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
3219
|
+
useEffect7(() => {
|
|
3088
3220
|
handleCloseRef.current = handleClose;
|
|
3089
3221
|
}, [handleClose]);
|
|
3090
|
-
const handleClick =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
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
|
|
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
|
|
3377
|
-
import { createPortal as
|
|
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] =
|
|
3391
|
-
const [coords, setCoords] =
|
|
3392
|
-
const [isPositioned, setIsPositioned] =
|
|
3393
|
-
const tooltipRef =
|
|
3394
|
-
const calculatePosition =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
3557
|
-
const imgRef =
|
|
3558
|
-
const [isSelected, setIsSelected] =
|
|
3559
|
-
const [isHovered, setIsHovered] =
|
|
3560
|
-
const [isSmallImage, setIsSmallImage] =
|
|
3561
|
-
const [isDropMode, setIsDropMode] =
|
|
3562
|
-
const [isDropHover, setIsDropHover] =
|
|
3563
|
-
const [previewOverride, setPreviewOverride] =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
3756
|
-
"
|
|
4272
|
+
return /* @__PURE__ */ jsxs6(
|
|
4273
|
+
"div",
|
|
3757
4274
|
{
|
|
3758
|
-
|
|
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
|
|
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 =
|
|
3931
|
-
const videoRef =
|
|
3932
|
-
const [isSelected, setIsSelected] =
|
|
3933
|
-
const [isHovered, setIsHovered] =
|
|
3934
|
-
const [isSmallVideo, setIsSmallVideo] =
|
|
3935
|
-
const [isInView, setIsInView] =
|
|
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] =
|
|
3950
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
4359
|
-
const [isSelected, setIsSelected] =
|
|
4360
|
-
const [isHovered, setIsHovered] =
|
|
4361
|
-
const [isSmallEmbed, setIsSmallEmbed] =
|
|
4362
|
-
const [isInView, setIsInView] =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4650
|
-
import { createPortal as
|
|
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
|
|
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] =
|
|
4668
|
-
const boundsRef =
|
|
5234
|
+
const [bounds, setBounds] = useState13(null);
|
|
5235
|
+
const boundsRef = useRef14(bounds);
|
|
4669
5236
|
boundsRef.current = bounds;
|
|
4670
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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] =
|
|
4713
|
-
const [isHovering, setIsHovering] =
|
|
4714
|
-
const triggerRef =
|
|
4715
|
-
const popoverRef =
|
|
4716
|
-
const showTimeoutRef =
|
|
4717
|
-
const hideTimeoutRef =
|
|
4718
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5332
|
+
const handleFocus = useCallback16(() => {
|
|
4766
5333
|
if (!enabled) return;
|
|
4767
5334
|
setIsVisible(true);
|
|
4768
5335
|
}, [enabled]);
|
|
4769
|
-
const handleTriangleLeave =
|
|
5336
|
+
const handleTriangleLeave = useCallback16(() => {
|
|
4770
5337
|
if (!isHovering) {
|
|
4771
5338
|
setIsVisible(false);
|
|
4772
5339
|
}
|
|
4773
5340
|
}, [isHovering]);
|
|
4774
|
-
const handleStayInside =
|
|
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] =
|
|
4907
|
-
const [sectionsExpanded, setSectionsExpanded] =
|
|
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] =
|
|
4919
|
-
const [originalText, setOriginalText] =
|
|
4920
|
-
const [originalHref, setOriginalHref] =
|
|
4921
|
-
const [currentHref, setCurrentHref] =
|
|
4922
|
-
const [isExternalUrl, setIsExternalUrl] =
|
|
4923
|
-
const [externalUrl, setExternalUrl] =
|
|
4924
|
-
const [popoverPosition, setPopoverPosition] =
|
|
4925
|
-
const containerRef =
|
|
4926
|
-
const hrefPopoverRef =
|
|
4927
|
-
const [actionButtonsPos, setActionButtonsPos] =
|
|
4928
|
-
const handleSaveTextRef =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5577
|
+
useEffect15(() => {
|
|
5008
5578
|
if (editingMode !== "link") {
|
|
5009
5579
|
setCurrentHref(href);
|
|
5010
5580
|
}
|
|
5011
5581
|
}, [href, editingMode]);
|
|
5012
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5651
|
+
const handleCancelLink = useCallback17(() => {
|
|
5082
5652
|
setCurrentHref(originalHref);
|
|
5083
5653
|
setEditingMode(null);
|
|
5084
5654
|
setIsExternalUrl(false);
|
|
5085
5655
|
setExternalUrl("");
|
|
5086
5656
|
}, [originalHref]);
|
|
5087
|
-
|
|
5657
|
+
useEffect15(() => {
|
|
5088
5658
|
handleSaveTextRef.current = handleSaveText;
|
|
5089
5659
|
handleCancelTextRef.current = handleCancelText;
|
|
5090
5660
|
}, [handleSaveText, handleCancelText]);
|
|
5091
|
-
const handleClick =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
5766
|
+
const handlePageSelect = useCallback17((path) => {
|
|
5197
5767
|
setCurrentHref(path);
|
|
5198
5768
|
setIsExternalUrl(false);
|
|
5199
5769
|
}, []);
|
|
5200
|
-
const handleExternalUrlApply =
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
5461
|
-
import { createPortal as
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
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 {
|
|
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] =
|
|
5519
|
-
|
|
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
|
|
5591
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
-
|
|
5610
|
-
|
|
5611
|
-
/* @__PURE__ */
|
|
5612
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
-
|
|
5635
|
-
|
|
5636
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
5642
|
-
"
|
|
6344
|
+
) }),
|
|
6345
|
+
hasBackground && /* @__PURE__ */ jsx17(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx17(
|
|
6346
|
+
"button",
|
|
5643
6347
|
{
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
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 =
|
|
5693
|
-
const [isHovered, setIsHovered] =
|
|
5694
|
-
const [isSelected, setIsSelected] =
|
|
5695
|
-
const [isDropMode, setIsDropMode] =
|
|
5696
|
-
const [isDropHover, setIsDropHover] =
|
|
5697
|
-
const [previewConfig, setPreviewConfig] =
|
|
5698
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
6805
|
+
return /* @__PURE__ */ jsx20(Fragment6, { children: token.content }, index);
|
|
6126
6806
|
case "bold":
|
|
6127
|
-
return /* @__PURE__ */
|
|
6807
|
+
return /* @__PURE__ */ jsx20("strong", { children: token.content }, index);
|
|
6128
6808
|
case "italic":
|
|
6129
|
-
return /* @__PURE__ */
|
|
6809
|
+
return /* @__PURE__ */ jsx20("em", { children: token.content }, index);
|
|
6130
6810
|
case "link":
|
|
6131
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
6877
|
+
return /* @__PURE__ */ jsx22(WouterRouter, { base: basename, children });
|
|
6198
6878
|
}
|
|
6199
6879
|
|
|
6200
6880
|
// src/router/ScrollRestoration.tsx
|
|
6201
|
-
import { useEffect as
|
|
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 =
|
|
6238
|
-
const isPopState =
|
|
6239
|
-
const scrollPositionsRef =
|
|
6240
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|