@yoamigo.com/core 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +390 -1
  2. package/dist/index.js +699 -146
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -938,7 +938,7 @@ function ContentStoreProvider2({ children }) {
938
938
  }
939
939
 
940
940
  // src/components/YaText.tsx
941
- import { useEffect as useEffect3, useRef as useRef3, useState as useState3, useCallback as useCallback3 } from "react";
941
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState4, useCallback as useCallback5 } from "react";
942
942
  import { createPortal as createPortal2 } from "react-dom";
943
943
  import { useEditor, EditorContent } from "@tiptap/react";
944
944
  import { BubbleMenu } from "@tiptap/react/menus";
@@ -1165,6 +1165,523 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1165
1165
  ] });
1166
1166
  }
1167
1167
 
1168
+ // src/hooks/useAnimatedText.ts
1169
+ import { useMemo as useMemo3 } from "react";
1170
+
1171
+ // src/hooks/useAIEditAnimation.ts
1172
+ import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4, useMemo as useMemo2 } from "react";
1173
+
1174
+ // src/contexts/AIEditContext.tsx
1175
+ import { createContext as createContext3, useContext as useContext3, useCallback as useCallback3, useRef as useRef3, useMemo } from "react";
1176
+ import { jsx as jsx4 } from "react/jsx-runtime";
1177
+ var AIEditContext = createContext3(null);
1178
+ function useAIEditContext() {
1179
+ const context = useContext3(AIEditContext);
1180
+ if (!context) {
1181
+ throw new Error("useAIEditContext must be used within an AIEditProvider");
1182
+ }
1183
+ return context;
1184
+ }
1185
+ function useAIEditContextOptional() {
1186
+ return useContext3(AIEditContext);
1187
+ }
1188
+ function AIEditProvider({ children, staggerDelay = 100 }) {
1189
+ const animationsRef = useRef3(/* @__PURE__ */ new Map());
1190
+ const listenersRef = useRef3(/* @__PURE__ */ new Map());
1191
+ const queueRef = useRef3([]);
1192
+ const processingRef = useRef3(false);
1193
+ const notifyListeners = useCallback3((fieldId) => {
1194
+ const listeners = listenersRef.current.get(fieldId);
1195
+ if (listeners) {
1196
+ listeners.forEach((listener) => listener());
1197
+ }
1198
+ }, []);
1199
+ const processQueue = useCallback3(() => {
1200
+ if (processingRef.current || queueRef.current.length === 0) return;
1201
+ processingRef.current = true;
1202
+ const fieldId = queueRef.current.shift();
1203
+ const state = animationsRef.current.get(fieldId);
1204
+ if (state && state.status === "pending") {
1205
+ state.status = "animating";
1206
+ state.startTime = performance.now();
1207
+ notifyListeners(fieldId);
1208
+ }
1209
+ setTimeout(() => {
1210
+ processingRef.current = false;
1211
+ processQueue();
1212
+ }, staggerDelay);
1213
+ }, [staggerDelay, notifyListeners]);
1214
+ const queueAnimation = useCallback3(
1215
+ (fieldId, config) => {
1216
+ const existing = animationsRef.current.get(fieldId);
1217
+ if (existing && existing.status === "animating") {
1218
+ animationsRef.current.delete(fieldId);
1219
+ }
1220
+ const state = {
1221
+ fieldId,
1222
+ status: "pending",
1223
+ startTime: 0,
1224
+ duration: config.duration,
1225
+ onComplete: config.onComplete
1226
+ };
1227
+ animationsRef.current.set(fieldId, state);
1228
+ config.onStart?.();
1229
+ if (!queueRef.current.includes(fieldId)) {
1230
+ queueRef.current.push(fieldId);
1231
+ }
1232
+ notifyListeners(fieldId);
1233
+ processQueue();
1234
+ },
1235
+ [notifyListeners, processQueue]
1236
+ );
1237
+ const cancelAnimation = useCallback3(
1238
+ (fieldId) => {
1239
+ const state = animationsRef.current.get(fieldId);
1240
+ if (state) {
1241
+ animationsRef.current.delete(fieldId);
1242
+ const queueIndex = queueRef.current.indexOf(fieldId);
1243
+ if (queueIndex >= 0) {
1244
+ queueRef.current.splice(queueIndex, 1);
1245
+ }
1246
+ notifyListeners(fieldId);
1247
+ }
1248
+ },
1249
+ [notifyListeners]
1250
+ );
1251
+ const isAnimating = useCallback3((fieldId) => {
1252
+ const state = animationsRef.current.get(fieldId);
1253
+ return state?.status === "animating" || state?.status === "pending";
1254
+ }, []);
1255
+ const getAnimationState = useCallback3((fieldId) => {
1256
+ return animationsRef.current.get(fieldId);
1257
+ }, []);
1258
+ const subscribe = useCallback3((fieldId, listener) => {
1259
+ let listeners = listenersRef.current.get(fieldId);
1260
+ if (!listeners) {
1261
+ listeners = /* @__PURE__ */ new Set();
1262
+ listenersRef.current.set(fieldId, listeners);
1263
+ }
1264
+ listeners.add(listener);
1265
+ return () => {
1266
+ listeners?.delete(listener);
1267
+ if (listeners?.size === 0) {
1268
+ listenersRef.current.delete(fieldId);
1269
+ }
1270
+ };
1271
+ }, []);
1272
+ const completeAnimation = useCallback3(
1273
+ (fieldId) => {
1274
+ const state = animationsRef.current.get(fieldId);
1275
+ if (state) {
1276
+ state.status = "complete";
1277
+ state.onComplete?.();
1278
+ setTimeout(() => {
1279
+ animationsRef.current.delete(fieldId);
1280
+ notifyListeners(fieldId);
1281
+ }, 500);
1282
+ notifyListeners(fieldId);
1283
+ }
1284
+ },
1285
+ [notifyListeners]
1286
+ );
1287
+ const value = useMemo(
1288
+ () => ({
1289
+ queueAnimation,
1290
+ cancelAnimation,
1291
+ isAnimating,
1292
+ getAnimationState,
1293
+ subscribe,
1294
+ completeAnimation
1295
+ }),
1296
+ [queueAnimation, cancelAnimation, isAnimating, getAnimationState, subscribe, completeAnimation]
1297
+ );
1298
+ return /* @__PURE__ */ jsx4(AIEditContext.Provider, { value, children });
1299
+ }
1300
+
1301
+ // src/hooks/useAIEditAnimation.ts
1302
+ function useAIEditAnimation(fieldId, value, options) {
1303
+ const { enabled = true, strategy, maxDuration = 2e3, onStart, onComplete } = options;
1304
+ const context = useAIEditContextOptional();
1305
+ const previousValueRef = useRef4(value);
1306
+ const isFirstRender = useRef4(true);
1307
+ const [phase, setPhase] = useState3("idle");
1308
+ const [progress, setProgress] = useState3(0);
1309
+ const [displayValue, setDisplayValue] = useState3(value);
1310
+ const metadataRef = useRef4(null);
1311
+ const animationFrameRef = useRef4(null);
1312
+ const startTimeRef = useRef4(0);
1313
+ const cancel = useCallback4(() => {
1314
+ if (animationFrameRef.current !== null) {
1315
+ cancelAnimationFrame(animationFrameRef.current);
1316
+ animationFrameRef.current = null;
1317
+ }
1318
+ setPhase("idle");
1319
+ setProgress(0);
1320
+ setDisplayValue(value);
1321
+ metadataRef.current = null;
1322
+ context?.cancelAnimation(fieldId);
1323
+ }, [value, context, fieldId]);
1324
+ const runAnimation = useCallback4(() => {
1325
+ if (!metadataRef.current) return;
1326
+ const metadata = metadataRef.current;
1327
+ const elapsed = performance.now() - startTimeRef.current;
1328
+ const duration = Math.min(metadata.duration, maxDuration);
1329
+ if (elapsed >= duration) {
1330
+ setProgress(1);
1331
+ setDisplayValue(metadata.newValue);
1332
+ setPhase("complete");
1333
+ metadataRef.current = null;
1334
+ animationFrameRef.current = null;
1335
+ context?.completeAnimation(fieldId);
1336
+ onComplete?.();
1337
+ setTimeout(() => {
1338
+ setPhase("idle");
1339
+ }, 400);
1340
+ return;
1341
+ }
1342
+ const currentProgress = elapsed / duration;
1343
+ setProgress(currentProgress);
1344
+ const interpolatedValue = strategy.interpolate(metadata, currentProgress);
1345
+ setDisplayValue(interpolatedValue);
1346
+ animationFrameRef.current = requestAnimationFrame(runAnimation);
1347
+ }, [strategy, maxDuration, context, fieldId, onComplete]);
1348
+ useEffect3(() => {
1349
+ if (isFirstRender.current) {
1350
+ isFirstRender.current = false;
1351
+ previousValueRef.current = value;
1352
+ return;
1353
+ }
1354
+ if (!enabled) {
1355
+ setDisplayValue(value);
1356
+ previousValueRef.current = value;
1357
+ return;
1358
+ }
1359
+ const oldValue = previousValueRef.current;
1360
+ const newValue = value;
1361
+ if (!strategy.canAnimate(oldValue, newValue)) {
1362
+ setDisplayValue(newValue);
1363
+ previousValueRef.current = newValue;
1364
+ return;
1365
+ }
1366
+ if (animationFrameRef.current !== null) {
1367
+ cancelAnimationFrame(animationFrameRef.current);
1368
+ }
1369
+ const metadata = strategy.prepare(oldValue, newValue);
1370
+ metadataRef.current = metadata;
1371
+ startTimeRef.current = performance.now();
1372
+ context?.queueAnimation(fieldId, {
1373
+ duration: Math.min(metadata.duration, maxDuration),
1374
+ onComplete: () => {
1375
+ }
1376
+ });
1377
+ onStart?.();
1378
+ setPhase("animating");
1379
+ setProgress(0);
1380
+ animationFrameRef.current = requestAnimationFrame(runAnimation);
1381
+ previousValueRef.current = newValue;
1382
+ return () => {
1383
+ if (animationFrameRef.current !== null) {
1384
+ cancelAnimationFrame(animationFrameRef.current);
1385
+ }
1386
+ };
1387
+ }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation]);
1388
+ useEffect3(() => {
1389
+ return () => {
1390
+ if (animationFrameRef.current !== null) {
1391
+ cancelAnimationFrame(animationFrameRef.current);
1392
+ }
1393
+ };
1394
+ }, []);
1395
+ const wrapperProps = useMemo2(
1396
+ () => ({
1397
+ className: phase === "animating" ? "ya-ai-editing" : phase === "complete" ? "ya-ai-complete" : "",
1398
+ "data-ai-editing": phase === "animating"
1399
+ }),
1400
+ [phase]
1401
+ );
1402
+ return {
1403
+ displayValue,
1404
+ isAnimating: phase === "animating",
1405
+ phase,
1406
+ progress,
1407
+ cancel,
1408
+ wrapperProps
1409
+ };
1410
+ }
1411
+
1412
+ // src/lib/text-diff.ts
1413
+ function containsHtml(text) {
1414
+ return /<[^>]+>/.test(text);
1415
+ }
1416
+ function stripHtml(html) {
1417
+ const withNewlines = html.replace(/<br\s*\/?>/gi, "\n");
1418
+ return withNewlines.replace(/<[^>]+>/g, "");
1419
+ }
1420
+ function commonPrefixLength(a, b) {
1421
+ const minLen = Math.min(a.length, b.length);
1422
+ let i = 0;
1423
+ while (i < minLen && a[i] === b[i]) {
1424
+ i++;
1425
+ }
1426
+ return i;
1427
+ }
1428
+ function commonSuffixLength(a, b, prefixLen) {
1429
+ const maxSuffixA = a.length - prefixLen;
1430
+ const maxSuffixB = b.length - prefixLen;
1431
+ const maxSuffix = Math.min(maxSuffixA, maxSuffixB);
1432
+ let i = 0;
1433
+ while (i < maxSuffix && a[a.length - 1 - i] === b[b.length - 1 - i]) {
1434
+ i++;
1435
+ }
1436
+ return i;
1437
+ }
1438
+ function computeTextDiff(oldText, newText) {
1439
+ const normalizedOld = oldText ?? "";
1440
+ const normalizedNew = newText ?? "";
1441
+ const hasHtml = containsHtml(normalizedOld) || containsHtml(normalizedNew);
1442
+ if (hasHtml) {
1443
+ return {
1444
+ type: "complex",
1445
+ deletions: normalizedOld,
1446
+ additions: normalizedNew,
1447
+ commonPrefix: "",
1448
+ commonSuffix: "",
1449
+ oldText: normalizedOld,
1450
+ newText: normalizedNew
1451
+ };
1452
+ }
1453
+ const prefixLen = commonPrefixLength(normalizedOld, normalizedNew);
1454
+ const suffixLen = commonSuffixLength(normalizedOld, normalizedNew, prefixLen);
1455
+ const commonPrefix = normalizedOld.slice(0, prefixLen);
1456
+ const commonSuffix = suffixLen > 0 ? normalizedOld.slice(-suffixLen) : "";
1457
+ const deletions = normalizedOld.slice(prefixLen, normalizedOld.length - suffixLen);
1458
+ const additions = normalizedNew.slice(prefixLen, normalizedNew.length - suffixLen);
1459
+ return {
1460
+ type: "simple",
1461
+ deletions,
1462
+ additions,
1463
+ commonPrefix,
1464
+ commonSuffix,
1465
+ oldText: normalizedOld,
1466
+ newText: normalizedNew
1467
+ };
1468
+ }
1469
+ function buildIntermediateText(diff, deleteProgress, typeProgress) {
1470
+ if (diff.type === "complex") {
1471
+ return typeProgress >= 1 ? diff.newText : diff.oldText;
1472
+ }
1473
+ const deletionsRemaining = Math.floor(diff.deletions.length * (1 - deleteProgress));
1474
+ const additionsShown = Math.floor(diff.additions.length * typeProgress);
1475
+ const remainingDeletions = diff.deletions.slice(0, deletionsRemaining);
1476
+ const typedAdditions = diff.additions.slice(0, additionsShown);
1477
+ return diff.commonPrefix + remainingDeletions + typedAdditions + diff.commonSuffix;
1478
+ }
1479
+ function calculateAnimationTiming(diff, options = {}) {
1480
+ const { charDelay = 50, maxDuration = 2e3 } = options;
1481
+ if (diff.type === "complex") {
1482
+ return { deleteDuration: 150, typeDuration: 150 };
1483
+ }
1484
+ const deleteChars = diff.deletions.length;
1485
+ const typeChars = diff.additions.length;
1486
+ const totalChars = deleteChars + typeChars;
1487
+ if (totalChars === 0) {
1488
+ return { deleteDuration: 0, typeDuration: 0 };
1489
+ }
1490
+ const baseDuration = totalChars * charDelay;
1491
+ const scale = baseDuration > maxDuration ? maxDuration / baseDuration : 1;
1492
+ const deleteDuration = Math.round(deleteChars * charDelay * scale);
1493
+ const typeDuration = Math.round(typeChars * charDelay * scale);
1494
+ return { deleteDuration, typeDuration };
1495
+ }
1496
+
1497
+ // src/lib/animation-strategies.ts
1498
+ var textTypingStrategy = {
1499
+ name: "text-typing",
1500
+ canAnimate(oldValue, newValue) {
1501
+ if (oldValue === newValue) return false;
1502
+ if (!oldValue && !newValue) return false;
1503
+ return true;
1504
+ },
1505
+ prepare(oldValue, newValue) {
1506
+ const diff = computeTextDiff(oldValue, newValue);
1507
+ const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
1508
+ charDelay: 50,
1509
+ // Fast & snappy
1510
+ maxDuration: 2e3
1511
+ });
1512
+ return {
1513
+ oldValue,
1514
+ newValue,
1515
+ duration: deleteDuration + typeDuration,
1516
+ data: {
1517
+ diff,
1518
+ deleteDuration,
1519
+ typeDuration
1520
+ }
1521
+ };
1522
+ },
1523
+ interpolate(metadata, progress) {
1524
+ const data = metadata.data;
1525
+ const { diff, deleteDuration, typeDuration } = data;
1526
+ const totalDuration = deleteDuration + typeDuration;
1527
+ if (totalDuration === 0) {
1528
+ return metadata.newValue;
1529
+ }
1530
+ const deleteEnd = deleteDuration / totalDuration;
1531
+ let deleteProgress;
1532
+ let typeProgress;
1533
+ if (progress <= deleteEnd) {
1534
+ deleteProgress = deleteEnd > 0 ? progress / deleteEnd : 1;
1535
+ typeProgress = 0;
1536
+ } else {
1537
+ deleteProgress = 1;
1538
+ const typeStart = deleteEnd;
1539
+ const typeRange = 1 - deleteEnd;
1540
+ typeProgress = typeRange > 0 ? (progress - typeStart) / typeRange : 1;
1541
+ }
1542
+ return buildIntermediateText(diff, deleteProgress, typeProgress);
1543
+ }
1544
+ };
1545
+ var imageCrossfadeStrategy = {
1546
+ name: "image-crossfade",
1547
+ canAnimate(oldValue, newValue) {
1548
+ if (oldValue?.src === newValue?.src) return false;
1549
+ return true;
1550
+ },
1551
+ prepare(oldValue, newValue) {
1552
+ return {
1553
+ oldValue,
1554
+ newValue,
1555
+ duration: 300
1556
+ // Quick crossfade
1557
+ };
1558
+ },
1559
+ interpolate(metadata, progress) {
1560
+ return progress >= 0.5 ? metadata.newValue : metadata.oldValue;
1561
+ }
1562
+ };
1563
+ var linkTransitionStrategy = {
1564
+ name: "link-transition",
1565
+ canAnimate(oldValue, newValue) {
1566
+ if (oldValue?.text === newValue?.text && oldValue?.href === newValue?.href) {
1567
+ return false;
1568
+ }
1569
+ return true;
1570
+ },
1571
+ prepare(oldValue, newValue) {
1572
+ const textDiff = computeTextDiff(oldValue?.text ?? "", newValue?.text ?? "");
1573
+ const { deleteDuration, typeDuration } = calculateAnimationTiming(textDiff, {
1574
+ charDelay: 50,
1575
+ maxDuration: 1500
1576
+ });
1577
+ return {
1578
+ oldValue,
1579
+ newValue,
1580
+ duration: deleteDuration + typeDuration + 100,
1581
+ // Extra for href highlight
1582
+ data: { textDiff }
1583
+ };
1584
+ },
1585
+ interpolate(metadata, progress) {
1586
+ return progress >= 0.5 ? metadata.newValue : metadata.oldValue;
1587
+ }
1588
+ };
1589
+ function getTextCursorPosition(metadata, progress) {
1590
+ const { diff, deleteDuration, typeDuration } = metadata.data;
1591
+ const totalDuration = deleteDuration + typeDuration;
1592
+ if (totalDuration === 0) return null;
1593
+ const deleteEnd = deleteDuration / totalDuration;
1594
+ let textLength;
1595
+ if (progress <= deleteEnd) {
1596
+ const deleteProgress = deleteEnd > 0 ? progress / deleteEnd : 1;
1597
+ const deletionsRemaining = Math.floor(diff.deletions.length * (1 - deleteProgress));
1598
+ textLength = diff.commonPrefix.length + deletionsRemaining;
1599
+ } else {
1600
+ const typeProgress = (progress - deleteEnd) / (1 - deleteEnd);
1601
+ const additionsShown = Math.floor(diff.additions.length * typeProgress);
1602
+ textLength = diff.commonPrefix.length + additionsShown;
1603
+ }
1604
+ return textLength;
1605
+ }
1606
+
1607
+ // src/hooks/useAnimatedText.ts
1608
+ function useAnimatedText(fieldId, content, options = {}) {
1609
+ const {
1610
+ enabled = true,
1611
+ charDelay = 50,
1612
+ maxDuration = 2e3,
1613
+ onStart,
1614
+ onComplete
1615
+ } = options;
1616
+ const customStrategy = useMemo3(() => {
1617
+ if (charDelay === 50) {
1618
+ return textTypingStrategy;
1619
+ }
1620
+ return {
1621
+ ...textTypingStrategy,
1622
+ prepare(oldValue, newValue) {
1623
+ const diff = computeTextDiff(oldValue, newValue);
1624
+ const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
1625
+ charDelay,
1626
+ maxDuration
1627
+ });
1628
+ return {
1629
+ oldValue,
1630
+ newValue,
1631
+ duration: deleteDuration + typeDuration,
1632
+ data: {
1633
+ diff,
1634
+ deleteDuration,
1635
+ typeDuration
1636
+ }
1637
+ };
1638
+ }
1639
+ };
1640
+ }, [charDelay, maxDuration]);
1641
+ const {
1642
+ displayValue,
1643
+ isAnimating,
1644
+ phase,
1645
+ progress,
1646
+ cancel,
1647
+ wrapperProps
1648
+ } = useAIEditAnimation(fieldId, content, {
1649
+ enabled,
1650
+ strategy: customStrategy,
1651
+ maxDuration,
1652
+ onStart,
1653
+ onComplete
1654
+ });
1655
+ const cursorPosition = useMemo3(() => {
1656
+ if (!isAnimating) return null;
1657
+ const diff = computeTextDiff(content, displayValue);
1658
+ const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
1659
+ charDelay,
1660
+ maxDuration
1661
+ });
1662
+ const metadata = {
1663
+ oldValue: content,
1664
+ newValue: displayValue,
1665
+ duration: deleteDuration + typeDuration,
1666
+ data: {
1667
+ diff,
1668
+ deleteDuration,
1669
+ typeDuration
1670
+ }
1671
+ };
1672
+ return getTextCursorPosition(metadata, progress);
1673
+ }, [isAnimating, content, displayValue, charDelay, maxDuration, progress]);
1674
+ return {
1675
+ displayContent: displayValue,
1676
+ isAnimating,
1677
+ phase,
1678
+ progress,
1679
+ cursorPosition,
1680
+ wrapperClassName: wrapperProps.className,
1681
+ cancel
1682
+ };
1683
+ }
1684
+
1168
1685
  // #style-inject:#style-inject
1169
1686
  function styleInject(css, { insertAt } = {}) {
1170
1687
  if (!css || typeof document === "undefined") return;
@@ -1415,8 +1932,11 @@ body.builder-selector-active .ya-text-editable:hover {
1415
1932
  }
1416
1933
  `);
1417
1934
 
1935
+ // src/styles/ai-animations.css
1936
+ styleInject('.ya-ai-editing {\n position: relative;\n}\n.ya-ai-editing::before {\n content: "";\n position: absolute;\n inset: -4px;\n border: 2px solid;\n border-radius: 6px;\n animation: ya-ai-focus-pulse 1.5s ease-in-out infinite;\n pointer-events: none;\n z-index: 10;\n}\n@keyframes ya-ai-focus-pulse {\n 0%, 100% {\n border-color: rgba(239, 68, 68, 0.6);\n box-shadow: 0 0 15px rgba(239, 68, 68, 0.2);\n }\n 50% {\n border-color: rgba(249, 115, 22, 0.8);\n box-shadow: 0 0 25px rgba(249, 115, 22, 0.3);\n }\n}\n.ya-typing-cursor {\n display: inline-block;\n width: 2px;\n height: 1.1em;\n background:\n linear-gradient(\n 180deg,\n #EF4444,\n #F97316);\n animation: ya-cursor-blink 0.5s step-end infinite;\n margin-left: 1px;\n vertical-align: text-bottom;\n border-radius: 1px;\n}\n@keyframes ya-cursor-blink {\n 50% {\n opacity: 0;\n }\n}\n.ya-ai-complete {\n animation: ya-complete-glow 0.4s ease-out forwards;\n}\n@keyframes ya-complete-glow {\n 0% {\n box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5);\n }\n 50% {\n box-shadow: 0 0 20px 5px rgba(16, 185, 129, 0.3);\n }\n 100% {\n box-shadow: 0 0 0 0 transparent;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .ya-ai-editing::before {\n animation: none;\n border-color: rgba(239, 68, 68, 0.6);\n box-shadow: 0 0 15px rgba(239, 68, 68, 0.2);\n }\n .ya-typing-cursor {\n animation: none;\n opacity: 1;\n }\n .ya-ai-complete {\n animation: ya-complete-glow-reduced 0.2s ease-out forwards;\n }\n @keyframes ya-complete-glow-reduced {\n 0% {\n background-color: rgba(16, 185, 129, 0.1);\n }\n 100% {\n background-color: transparent;\n }\n }\n}\n.ya-ai-hidden {\n opacity: 0;\n visibility: hidden;\n}\n.ya-ai-fade-in {\n animation: ya-fade-in 0.3s ease-out forwards;\n}\n@keyframes ya-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-ai-pulse {\n animation: ya-scale-pulse 0.3s ease-out forwards;\n}\n@keyframes ya-scale-pulse {\n 0% {\n transform: scale(1);\n }\n 50% {\n transform: scale(1.02);\n }\n 100% {\n transform: scale(1);\n }\n}\n');
1937
+
1418
1938
  // src/components/YaText.tsx
1419
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1939
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
1420
1940
  var FontSize = Extension.create({
1421
1941
  name: "fontSize",
1422
1942
  addOptions() {
@@ -1511,10 +2031,17 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1511
2031
  const { getValue, setValue, mode, saveToWorker, activeFieldId, setActiveField } = useContentStore();
1512
2032
  const storeContent = getValue(fieldId);
1513
2033
  const content = storeContent || (typeof children === "string" ? children : "");
1514
- const [isEditing, setIsEditing] = useState3(false);
1515
- const [originalContent, setOriginalContent] = useState3(content);
1516
- const containerRef = useRef3(null);
1517
- const originalContentRef = useRef3(content);
2034
+ const [isEditing, setIsEditing] = useState4(false);
2035
+ const {
2036
+ displayContent,
2037
+ isAnimating,
2038
+ wrapperClassName
2039
+ } = useAnimatedText(fieldId, content, {
2040
+ enabled: mode === "inline-edit" && !isEditing
2041
+ });
2042
+ const [originalContent, setOriginalContent] = useState4(content);
2043
+ const containerRef = useRef5(null);
2044
+ const originalContentRef = useRef5(content);
1518
2045
  const editor = useEditor({
1519
2046
  extensions: [
1520
2047
  StarterKit.configure({
@@ -1548,19 +2075,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1548
2075
  },
1549
2076
  parseOptions: { preserveWhitespace: "full" }
1550
2077
  });
1551
- useEffect3(() => {
2078
+ useEffect4(() => {
1552
2079
  if (editor && !isEditing) {
1553
2080
  if (editor.getHTML() !== content) {
1554
2081
  editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
1555
2082
  }
1556
2083
  }
1557
2084
  }, [content, editor, isEditing]);
1558
- useEffect3(() => {
2085
+ useEffect4(() => {
1559
2086
  if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
1560
2087
  setIsEditing(false);
1561
2088
  }
1562
2089
  }, [activeFieldId, fieldId, isEditing]);
1563
- const handleSave = useCallback3(() => {
2090
+ const handleSave = useCallback5(() => {
1564
2091
  if (!editor) return;
1565
2092
  let html = editor.getHTML();
1566
2093
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -1568,13 +2095,13 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1568
2095
  saveToWorker?.(fieldId, html);
1569
2096
  setIsEditing(false);
1570
2097
  }, [editor, fieldId, setValue, saveToWorker]);
1571
- const handleCancel = useCallback3(() => {
2098
+ const handleCancel = useCallback5(() => {
1572
2099
  if (editor) {
1573
2100
  editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
1574
2101
  }
1575
2102
  setIsEditing(false);
1576
2103
  }, [editor, originalContent]);
1577
- const handleClose = useCallback3(() => {
2104
+ const handleClose = useCallback5(() => {
1578
2105
  if (!editor) {
1579
2106
  setIsEditing(false);
1580
2107
  return;
@@ -1587,7 +2114,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1587
2114
  }
1588
2115
  setIsEditing(false);
1589
2116
  }, [editor, fieldId, setValue, saveToWorker]);
1590
- const handleClick = useCallback3((e) => {
2117
+ const handleClick = useCallback5((e) => {
1591
2118
  if (isEditing) {
1592
2119
  e.preventDefault();
1593
2120
  e.stopPropagation();
@@ -1613,7 +2140,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1613
2140
  }, 20);
1614
2141
  }
1615
2142
  }, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
1616
- const handleKeyDown = useCallback3(
2143
+ const handleKeyDown = useCallback5(
1617
2144
  (event) => {
1618
2145
  if (!isEditing) return;
1619
2146
  if (event.key === "Enter" && !event.shiftKey) {
@@ -1634,7 +2161,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1634
2161
  },
1635
2162
  [isEditing, handleSave, handleCancel]
1636
2163
  );
1637
- const handleLink = useCallback3(() => {
2164
+ const handleLink = useCallback5(() => {
1638
2165
  if (!editor) return;
1639
2166
  const previousUrl = editor.getAttributes("link").href;
1640
2167
  const url = window.prompt("Enter URL:", previousUrl || "https://");
@@ -1645,7 +2172,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1645
2172
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
1646
2173
  }
1647
2174
  }, [editor]);
1648
- const handleFontSizeChange = useCallback3(
2175
+ const handleFontSizeChange = useCallback5(
1649
2176
  (e) => {
1650
2177
  if (!editor) return;
1651
2178
  const size = e.target.value;
@@ -1657,7 +2184,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1657
2184
  },
1658
2185
  [editor]
1659
2186
  );
1660
- const handleFontWeightChange = useCallback3(
2187
+ const handleFontWeightChange = useCallback5(
1661
2188
  (e) => {
1662
2189
  if (!editor) return;
1663
2190
  const weight = e.target.value;
@@ -1680,24 +2207,30 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1680
2207
  return attrs.fontWeight || "";
1681
2208
  };
1682
2209
  if (mode === "read-only") {
1683
- return /* @__PURE__ */ jsx4(
2210
+ return /* @__PURE__ */ jsx5(
1684
2211
  Component,
1685
2212
  {
1686
2213
  ref: containerRef,
1687
2214
  className,
1688
2215
  "data-ya-restricted": "true",
1689
2216
  "data-field-id": fieldId,
1690
- children: /* @__PURE__ */ jsx4(SafeHtml, { content, mode })
2217
+ children: /* @__PURE__ */ jsx5(SafeHtml, { content, mode })
1691
2218
  }
1692
2219
  );
1693
2220
  }
1694
- return /* @__PURE__ */ jsx4(
2221
+ const combinedClassName = [
2222
+ className || "",
2223
+ isEditing ? "ya-text-editing" : "ya-text-editable",
2224
+ wrapperClassName
2225
+ ].filter(Boolean).join(" ");
2226
+ return /* @__PURE__ */ jsx5(
1695
2227
  Component,
1696
2228
  {
1697
2229
  ref: containerRef,
1698
- className: `${className || ""} ${isEditing ? "ya-text-editing" : "ya-text-editable"}`,
2230
+ className: combinedClassName,
1699
2231
  "data-ya-restricted": "true",
1700
2232
  "data-field-id": fieldId,
2233
+ "data-ai-editing": isAnimating || void 0,
1701
2234
  onClick: handleClick,
1702
2235
  onKeyDown: handleKeyDown,
1703
2236
  children: editor ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
@@ -1710,37 +2243,37 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1710
2243
  options: { offset: 6, placement: "top" },
1711
2244
  className: "ya-bubble-menu",
1712
2245
  children: [
1713
- /* @__PURE__ */ jsx4(
2246
+ /* @__PURE__ */ jsx5(
1714
2247
  "button",
1715
2248
  {
1716
2249
  type: "button",
1717
2250
  onClick: () => editor.chain().focus().toggleBold().run(),
1718
2251
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
1719
2252
  title: "Bold",
1720
- children: /* @__PURE__ */ jsx4("strong", { children: "B" })
2253
+ children: /* @__PURE__ */ jsx5("strong", { children: "B" })
1721
2254
  }
1722
2255
  ),
1723
- /* @__PURE__ */ jsx4(
2256
+ /* @__PURE__ */ jsx5(
1724
2257
  "button",
1725
2258
  {
1726
2259
  type: "button",
1727
2260
  onClick: () => editor.chain().focus().toggleItalic().run(),
1728
2261
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
1729
2262
  title: "Italic",
1730
- children: /* @__PURE__ */ jsx4("em", { children: "I" })
2263
+ children: /* @__PURE__ */ jsx5("em", { children: "I" })
1731
2264
  }
1732
2265
  ),
1733
- /* @__PURE__ */ jsx4(
2266
+ /* @__PURE__ */ jsx5(
1734
2267
  "button",
1735
2268
  {
1736
2269
  type: "button",
1737
2270
  onClick: handleLink,
1738
2271
  className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
1739
2272
  title: "Link",
1740
- children: /* @__PURE__ */ jsx4("span", { children: "\u{1F517}" })
2273
+ children: /* @__PURE__ */ jsx5("span", { children: "\u{1F517}" })
1741
2274
  }
1742
2275
  ),
1743
- /* @__PURE__ */ jsx4("span", { className: "ya-bubble-divider" }),
2276
+ /* @__PURE__ */ jsx5("span", { className: "ya-bubble-divider" }),
1744
2277
  /* @__PURE__ */ jsxs2(
1745
2278
  "select",
1746
2279
  {
@@ -1749,8 +2282,8 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1749
2282
  className: "ya-bubble-select",
1750
2283
  title: "Font Size",
1751
2284
  children: [
1752
- /* @__PURE__ */ jsx4("option", { value: "", children: "Size" }),
1753
- Object.entries(SIZE_PRESETS).map(([name, size]) => /* @__PURE__ */ jsx4("option", { value: size, children: name }, name))
2285
+ /* @__PURE__ */ jsx5("option", { value: "", children: "Size" }),
2286
+ Object.entries(SIZE_PRESETS).map(([name, size]) => /* @__PURE__ */ jsx5("option", { value: size, children: name }, name))
1754
2287
  ]
1755
2288
  }
1756
2289
  ),
@@ -1762,8 +2295,8 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1762
2295
  className: "ya-bubble-select",
1763
2296
  title: "Font Weight",
1764
2297
  children: [
1765
- /* @__PURE__ */ jsx4("option", { value: "", children: "Weight" }),
1766
- Object.entries(WEIGHT_PRESETS).map(([name, weight]) => /* @__PURE__ */ jsx4("option", { value: weight, children: name }, name))
2298
+ /* @__PURE__ */ jsx5("option", { value: "", children: "Weight" }),
2299
+ Object.entries(WEIGHT_PRESETS).map(([name, weight]) => /* @__PURE__ */ jsx5("option", { value: weight, children: name }, name))
1767
2300
  ]
1768
2301
  }
1769
2302
  )
@@ -1773,9 +2306,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1773
2306
  document.body
1774
2307
  ),
1775
2308
  isEditing ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1776
- /* @__PURE__ */ jsx4(EditorContent, { editor }),
2309
+ /* @__PURE__ */ jsx5(EditorContent, { editor }),
1777
2310
  /* @__PURE__ */ jsxs2("div", { className: "ya-text-actions", children: [
1778
- /* @__PURE__ */ jsx4(
2311
+ /* @__PURE__ */ jsx5(
1779
2312
  "button",
1780
2313
  {
1781
2314
  type: "button",
@@ -1784,7 +2317,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1784
2317
  children: "Cancel"
1785
2318
  }
1786
2319
  ),
1787
- /* @__PURE__ */ jsx4(
2320
+ /* @__PURE__ */ jsx5(
1788
2321
  "button",
1789
2322
  {
1790
2323
  type: "button",
@@ -1794,14 +2327,20 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1794
2327
  }
1795
2328
  )
1796
2329
  ] })
1797
- ] }) : /* @__PURE__ */ jsx4(SafeHtml, { content, mode })
1798
- ] }) : /* @__PURE__ */ jsx4(SafeHtml, { content, mode })
2330
+ ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
2331
+ /* @__PURE__ */ jsx5(SafeHtml, { content: displayContent, mode }),
2332
+ isAnimating && /* @__PURE__ */ jsx5("span", { className: "ya-typing-cursor" })
2333
+ ] })
2334
+ ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
2335
+ /* @__PURE__ */ jsx5(SafeHtml, { content: displayContent, mode }),
2336
+ isAnimating && /* @__PURE__ */ jsx5("span", { className: "ya-typing-cursor" })
2337
+ ] })
1799
2338
  }
1800
2339
  );
1801
2340
  }
1802
2341
 
1803
2342
  // src/components/YaImage.tsx
1804
- import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef5, useState as useState5 } from "react";
2343
+ import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef7, useState as useState6 } from "react";
1805
2344
 
1806
2345
  // src/lib/asset-resolver.ts
1807
2346
  var assetResolver = (path) => path;
@@ -1817,25 +2356,25 @@ function resolveAssetUrl(path) {
1817
2356
  }
1818
2357
 
1819
2358
  // src/components/YaTooltip.tsx
1820
- import { useEffect as useEffect4, useRef as useRef4, useState as useState4, useCallback as useCallback4 } from "react";
2359
+ import { useEffect as useEffect5, useRef as useRef6, useState as useState5, useCallback as useCallback6 } from "react";
1821
2360
  import { createPortal as createPortal3 } from "react-dom";
1822
2361
 
1823
2362
  // src/components/ya-tooltip.css
1824
2363
  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 opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\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');
1825
2364
 
1826
2365
  // src/components/YaTooltip.tsx
1827
- import { jsx as jsx5 } from "react/jsx-runtime";
2366
+ import { jsx as jsx6 } from "react/jsx-runtime";
1828
2367
  function YaTooltip({
1829
2368
  anchorRef,
1830
2369
  children,
1831
2370
  show,
1832
2371
  preferredPosition = "bottom"
1833
2372
  }) {
1834
- const [position, setPosition] = useState4(preferredPosition);
1835
- const [coords, setCoords] = useState4({ top: 0, left: 0 });
1836
- const [isPositioned, setIsPositioned] = useState4(false);
1837
- const tooltipRef = useRef4(null);
1838
- const calculatePosition = useCallback4(() => {
2373
+ const [position, setPosition] = useState5(preferredPosition);
2374
+ const [coords, setCoords] = useState5({ top: 0, left: 0 });
2375
+ const [isPositioned, setIsPositioned] = useState5(false);
2376
+ const tooltipRef = useRef6(null);
2377
+ const calculatePosition = useCallback6(() => {
1839
2378
  if (!anchorRef.current) return;
1840
2379
  const anchor = anchorRef.current.getBoundingClientRect();
1841
2380
  const tooltip = tooltipRef.current?.getBoundingClientRect();
@@ -1910,7 +2449,7 @@ function YaTooltip({
1910
2449
  setCoords({ top, left });
1911
2450
  setIsPositioned(true);
1912
2451
  }, [anchorRef, preferredPosition]);
1913
- useEffect4(() => {
2452
+ useEffect5(() => {
1914
2453
  if (!show) {
1915
2454
  setIsPositioned(false);
1916
2455
  return;
@@ -1923,14 +2462,14 @@ function YaTooltip({
1923
2462
  window.removeEventListener("resize", calculatePosition);
1924
2463
  };
1925
2464
  }, [show, calculatePosition]);
1926
- useEffect4(() => {
2465
+ useEffect5(() => {
1927
2466
  if (show && tooltipRef.current) {
1928
2467
  calculatePosition();
1929
2468
  }
1930
2469
  }, [show, children, calculatePosition]);
1931
2470
  if (!show) return null;
1932
2471
  return createPortal3(
1933
- /* @__PURE__ */ jsx5(
2472
+ /* @__PURE__ */ jsx6(
1934
2473
  "div",
1935
2474
  {
1936
2475
  ref: tooltipRef,
@@ -1953,7 +2492,7 @@ function YaTooltip({
1953
2492
  styleInject('.ya-image-container {\n position: relative;\n display: inline-block;\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');
1954
2493
 
1955
2494
  // src/components/YaImage.tsx
1956
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2495
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1957
2496
  function parseImageValue(value) {
1958
2497
  if (!value) {
1959
2498
  return { src: "" };
@@ -1988,18 +2527,18 @@ function YaImage({
1988
2527
  fallbackAlt
1989
2528
  }) {
1990
2529
  const { getValue, mode } = useContentStore();
1991
- const containerRef = useRef5(null);
1992
- const imgRef = useRef5(null);
1993
- const [isSelected, setIsSelected] = useState5(false);
1994
- const [isHovered, setIsHovered] = useState5(false);
1995
- const [isSmallImage, setIsSmallImage] = useState5(false);
2530
+ const containerRef = useRef7(null);
2531
+ const imgRef = useRef7(null);
2532
+ const [isSelected, setIsSelected] = useState6(false);
2533
+ const [isHovered, setIsHovered] = useState6(false);
2534
+ const [isSmallImage, setIsSmallImage] = useState6(false);
1996
2535
  const rawValue = getValue(fieldId);
1997
2536
  const imageData = parseImageValue(rawValue);
1998
2537
  const src = imageData.src || fallbackSrc || "";
1999
2538
  const altText = imageData.alt || alt || fallbackAlt || "";
2000
2539
  const objectFit = imageData.objectFit || propObjectFit || "cover";
2001
2540
  const objectPosition = getObjectPosition(imageData) || propObjectPosition || "50% 50%";
2002
- const handleClick = useCallback5(() => {
2541
+ const handleClick = useCallback7(() => {
2003
2542
  if (mode !== "inline-edit") return;
2004
2543
  if (document.body.classList.contains("builder-selector-active")) return;
2005
2544
  setIsSelected(true);
@@ -2027,7 +2566,7 @@ function YaImage({
2027
2566
  "*"
2028
2567
  );
2029
2568
  }, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
2030
- useEffect5(() => {
2569
+ useEffect6(() => {
2031
2570
  if (mode !== "inline-edit") return;
2032
2571
  const handleMessage2 = (event) => {
2033
2572
  if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -2042,7 +2581,7 @@ function YaImage({
2042
2581
  window.addEventListener("message", handleMessage2);
2043
2582
  return () => window.removeEventListener("message", handleMessage2);
2044
2583
  }, [mode, fieldId]);
2045
- useEffect5(() => {
2584
+ useEffect6(() => {
2046
2585
  if (mode !== "inline-edit") return;
2047
2586
  const checkSize = () => {
2048
2587
  if (imgRef.current) {
@@ -2064,7 +2603,7 @@ function YaImage({
2064
2603
  window.removeEventListener("resize", checkSize);
2065
2604
  };
2066
2605
  }, [mode]);
2067
- useEffect5(() => {
2606
+ useEffect6(() => {
2068
2607
  if (!isSelected || mode !== "inline-edit") return;
2069
2608
  let lastRectKey = "";
2070
2609
  let lastTime = 0;
@@ -2099,7 +2638,7 @@ function YaImage({
2099
2638
  return () => cancelAnimationFrame(rafId);
2100
2639
  }, [isSelected, fieldId, mode]);
2101
2640
  if (mode === "read-only") {
2102
- return /* @__PURE__ */ jsx6(
2641
+ return /* @__PURE__ */ jsx7(
2103
2642
  "img",
2104
2643
  {
2105
2644
  src: resolveAssetUrl(src),
@@ -2127,9 +2666,9 @@ function YaImage({
2127
2666
  strokeLinecap: "round",
2128
2667
  strokeLinejoin: "round",
2129
2668
  children: [
2130
- /* @__PURE__ */ jsx6("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
2131
- /* @__PURE__ */ jsx6("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2132
- /* @__PURE__ */ jsx6("polyline", { points: "21 15 16 10 5 21" })
2669
+ /* @__PURE__ */ jsx7("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
2670
+ /* @__PURE__ */ jsx7("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2671
+ /* @__PURE__ */ jsx7("polyline", { points: "21 15 16 10 5 21" })
2133
2672
  ]
2134
2673
  }
2135
2674
  );
@@ -2154,7 +2693,7 @@ function YaImage({
2154
2693
  }
2155
2694
  },
2156
2695
  children: [
2157
- /* @__PURE__ */ jsx6(
2696
+ /* @__PURE__ */ jsx7(
2158
2697
  "img",
2159
2698
  {
2160
2699
  ref: imgRef,
@@ -2170,12 +2709,12 @@ function YaImage({
2170
2709
  ),
2171
2710
  isSmallImage ? /* @__PURE__ */ jsxs3(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
2172
2711
  editIcon,
2173
- /* @__PURE__ */ jsx6("span", { children: "Click to edit" })
2712
+ /* @__PURE__ */ jsx7("span", { children: "Click to edit" })
2174
2713
  ] }) : (
2175
2714
  /* For large images: show overlay inside the image */
2176
2715
  /* @__PURE__ */ jsxs3("div", { className: "ya-image-overlay", children: [
2177
- /* @__PURE__ */ jsx6("div", { className: "ya-image-edit-icon", children: editIcon }),
2178
- /* @__PURE__ */ jsx6("span", { className: "ya-image-edit-label", children: "Click to edit" })
2716
+ /* @__PURE__ */ jsx7("div", { className: "ya-image-edit-icon", children: editIcon }),
2717
+ /* @__PURE__ */ jsx7("span", { className: "ya-image-edit-label", children: "Click to edit" })
2179
2718
  ] })
2180
2719
  )
2181
2720
  ]
@@ -2184,7 +2723,7 @@ function YaImage({
2184
2723
  }
2185
2724
 
2186
2725
  // src/components/YaLink.tsx
2187
- import { useEffect as useEffect6, useRef as useRef6, useState as useState6, useCallback as useCallback6 } from "react";
2726
+ import { useEffect as useEffect7, useRef as useRef8, useState as useState7, useCallback as useCallback8 } from "react";
2188
2727
  import { createPortal as createPortal4 } from "react-dom";
2189
2728
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
2190
2729
  import { BubbleMenu as BubbleMenu2 } from "@tiptap/react/menus";
@@ -2197,7 +2736,7 @@ import { Link as WouterLink, useLocation } from "wouter";
2197
2736
  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-actions {\n display: flex;\n gap: 8px;\n position: absolute;\n bottom: -60px;\n right: 0;\n z-index: 10;\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: 10;\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-link-edit-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 10;\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');
2198
2737
 
2199
2738
  // src/components/YaLink.tsx
2200
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2739
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
2201
2740
  function isInternalPath(path) {
2202
2741
  if (!path) return false;
2203
2742
  if (path.startsWith("#")) return false;
@@ -2292,8 +2831,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2292
2831
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
2293
2832
  const [, navigate] = useLocation();
2294
2833
  const pages = availablePages ?? getPages();
2295
- const [sections, setSections] = useState6([]);
2296
- const [sectionsExpanded, setSectionsExpanded] = useState6(false);
2834
+ const [sections, setSections] = useState7([]);
2835
+ const [sectionsExpanded, setSectionsExpanded] = useState7(false);
2297
2836
  const textFieldId = `${fieldId}.text`;
2298
2837
  const hrefFieldId = `${fieldId}.href`;
2299
2838
  const storeText = getValue(textFieldId);
@@ -2301,16 +2840,16 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2301
2840
  const isIconMode = children != null && typeof children !== "string";
2302
2841
  const text = storeText || (typeof children === "string" ? children : "");
2303
2842
  const href = storeHref || defaultHref;
2304
- const [editingMode, setEditingMode] = useState6(null);
2305
- const [showEditPopover, setShowEditPopover] = useState6(false);
2306
- const [originalText, setOriginalText] = useState6(text);
2307
- const [originalHref, setOriginalHref] = useState6(href);
2308
- const [currentHref, setCurrentHref] = useState6(href);
2309
- const [isExternalUrl, setIsExternalUrl] = useState6(false);
2310
- const [externalUrl, setExternalUrl] = useState6("");
2311
- const containerRef = useRef6(null);
2312
- const hrefPopoverRef = useRef6(null);
2313
- const hidePopoverTimeoutRef = useRef6(null);
2843
+ const [editingMode, setEditingMode] = useState7(null);
2844
+ const [showEditPopover, setShowEditPopover] = useState7(false);
2845
+ const [originalText, setOriginalText] = useState7(text);
2846
+ const [originalHref, setOriginalHref] = useState7(href);
2847
+ const [currentHref, setCurrentHref] = useState7(href);
2848
+ const [isExternalUrl, setIsExternalUrl] = useState7(false);
2849
+ const [externalUrl, setExternalUrl] = useState7("");
2850
+ const containerRef = useRef8(null);
2851
+ const hrefPopoverRef = useRef8(null);
2852
+ const hidePopoverTimeoutRef = useRef8(null);
2314
2853
  const editor = useEditor2({
2315
2854
  extensions: [
2316
2855
  StarterKit2.configure({
@@ -2333,26 +2872,26 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2333
2872
  }
2334
2873
  }
2335
2874
  });
2336
- useEffect6(() => {
2875
+ useEffect7(() => {
2337
2876
  if (editor && editingMode !== "text") {
2338
2877
  if (editor.getHTML() !== text) {
2339
2878
  editor.commands.setContent(text);
2340
2879
  }
2341
2880
  }
2342
2881
  }, [text, editor, editingMode]);
2343
- useEffect6(() => {
2882
+ useEffect7(() => {
2344
2883
  if (editingMode !== "link") {
2345
2884
  setCurrentHref(href);
2346
2885
  }
2347
2886
  }, [href, editingMode]);
2348
- useEffect6(() => {
2887
+ useEffect7(() => {
2349
2888
  return () => {
2350
2889
  if (hidePopoverTimeoutRef.current) {
2351
2890
  clearTimeout(hidePopoverTimeoutRef.current);
2352
2891
  }
2353
2892
  };
2354
2893
  }, []);
2355
- useEffect6(() => {
2894
+ useEffect7(() => {
2356
2895
  if (editingMode !== "link") return;
2357
2896
  const handleClickOutside = (event) => {
2358
2897
  const target = event.target;
@@ -2366,7 +2905,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2366
2905
  document.addEventListener("mousedown", handleClickOutside);
2367
2906
  return () => document.removeEventListener("mousedown", handleClickOutside);
2368
2907
  }, [editingMode, originalHref]);
2369
- const handleSaveText = useCallback6(() => {
2908
+ const handleSaveText = useCallback8(() => {
2370
2909
  if (!editor) return;
2371
2910
  let html = editor.getHTML();
2372
2911
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -2374,26 +2913,26 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2374
2913
  saveToWorker?.(textFieldId, html);
2375
2914
  setEditingMode(null);
2376
2915
  }, [editor, textFieldId, setValue, saveToWorker]);
2377
- const handleSaveLink = useCallback6(() => {
2916
+ const handleSaveLink = useCallback8(() => {
2378
2917
  setValue(hrefFieldId, currentHref);
2379
2918
  saveToWorker?.(hrefFieldId, currentHref);
2380
2919
  setEditingMode(null);
2381
2920
  setIsExternalUrl(false);
2382
2921
  setExternalUrl("");
2383
2922
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
2384
- const handleCancelText = useCallback6(() => {
2923
+ const handleCancelText = useCallback8(() => {
2385
2924
  if (editor) {
2386
2925
  editor.commands.setContent(originalText);
2387
2926
  }
2388
2927
  setEditingMode(null);
2389
2928
  }, [editor, originalText]);
2390
- const handleCancelLink = useCallback6(() => {
2929
+ const handleCancelLink = useCallback8(() => {
2391
2930
  setCurrentHref(originalHref);
2392
2931
  setEditingMode(null);
2393
2932
  setIsExternalUrl(false);
2394
2933
  setExternalUrl("");
2395
2934
  }, [originalHref]);
2396
- const handleClick = useCallback6(
2935
+ const handleClick = useCallback8(
2397
2936
  (e) => {
2398
2937
  const selectModeEnabled = window.__builderSelectModeEnabled;
2399
2938
  if (selectModeEnabled) {
@@ -2425,7 +2964,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2425
2964
  },
2426
2965
  [href, navigate, onClick]
2427
2966
  );
2428
- const handleMouseEnter = useCallback6(() => {
2967
+ const handleMouseEnter = useCallback8(() => {
2429
2968
  if (hidePopoverTimeoutRef.current) {
2430
2969
  clearTimeout(hidePopoverTimeoutRef.current);
2431
2970
  hidePopoverTimeoutRef.current = null;
@@ -2434,19 +2973,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2434
2973
  setShowEditPopover(true);
2435
2974
  }
2436
2975
  }, [mode, editingMode]);
2437
- const handleMouseLeave = useCallback6(() => {
2976
+ const handleMouseLeave = useCallback8(() => {
2438
2977
  hidePopoverTimeoutRef.current = window.setTimeout(() => {
2439
2978
  if (!editingMode) {
2440
2979
  setShowEditPopover(false);
2441
2980
  }
2442
2981
  }, 150);
2443
2982
  }, [editingMode]);
2444
- const handleFocus = useCallback6(() => {
2983
+ const handleFocus = useCallback8(() => {
2445
2984
  if (mode === "inline-edit" && !editingMode) {
2446
2985
  setShowEditPopover(true);
2447
2986
  }
2448
2987
  }, [mode, editingMode]);
2449
- const startEditText = useCallback6(() => {
2988
+ const startEditText = useCallback8(() => {
2450
2989
  setShowEditPopover(false);
2451
2990
  setEditingMode("text");
2452
2991
  setOriginalText(text);
@@ -2454,14 +2993,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2454
2993
  editor?.chain().focus().selectAll().run();
2455
2994
  }, 20);
2456
2995
  }, [text, editor]);
2457
- const startEditLink = useCallback6(() => {
2996
+ const startEditLink = useCallback8(() => {
2458
2997
  setShowEditPopover(false);
2459
2998
  setEditingMode("link");
2460
2999
  setOriginalHref(href);
2461
3000
  setCurrentHref(href);
2462
3001
  setSections(discoverSectionsFromDOM());
2463
3002
  }, [href]);
2464
- const handleKeyDown = useCallback6(
3003
+ const handleKeyDown = useCallback8(
2465
3004
  (event) => {
2466
3005
  if (editingMode !== "text") return;
2467
3006
  if (event.key === "Enter" && !event.shiftKey) {
@@ -2482,7 +3021,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2482
3021
  },
2483
3022
  [editingMode, handleSaveText, handleCancelText]
2484
3023
  );
2485
- const handleFontSizeChange = useCallback6(
3024
+ const handleFontSizeChange = useCallback8(
2486
3025
  (e) => {
2487
3026
  if (!editor) return;
2488
3027
  const size = e.target.value;
@@ -2494,7 +3033,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2494
3033
  },
2495
3034
  [editor]
2496
3035
  );
2497
- const handleFontWeightChange = useCallback6(
3036
+ const handleFontWeightChange = useCallback8(
2498
3037
  (e) => {
2499
3038
  if (!editor) return;
2500
3039
  const weight = e.target.value;
@@ -2506,11 +3045,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2506
3045
  },
2507
3046
  [editor]
2508
3047
  );
2509
- const handlePageSelect = useCallback6((path) => {
3048
+ const handlePageSelect = useCallback8((path) => {
2510
3049
  setCurrentHref(path);
2511
3050
  setIsExternalUrl(false);
2512
3051
  }, []);
2513
- const handleExternalUrlApply = useCallback6(() => {
3052
+ const handleExternalUrlApply = useCallback8(() => {
2514
3053
  if (externalUrl) {
2515
3054
  setCurrentHref(externalUrl);
2516
3055
  }
@@ -2526,9 +3065,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2526
3065
  return attrs.fontWeight || "";
2527
3066
  };
2528
3067
  if (mode === "read-only") {
2529
- const content = isIconMode ? children : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode });
3068
+ const content = isIconMode ? children : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode });
2530
3069
  if (isInternalPath(href)) {
2531
- return /* @__PURE__ */ jsx7(
3070
+ return /* @__PURE__ */ jsx8(
2532
3071
  WouterLink,
2533
3072
  {
2534
3073
  href,
@@ -2539,7 +3078,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2539
3078
  }
2540
3079
  );
2541
3080
  }
2542
- return /* @__PURE__ */ jsx7(
3081
+ return /* @__PURE__ */ jsx8(
2543
3082
  Component,
2544
3083
  {
2545
3084
  ref: containerRef,
@@ -2552,7 +3091,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2552
3091
  );
2553
3092
  }
2554
3093
  return /* @__PURE__ */ jsxs4("span", { className: "ya-link-wrapper", children: [
2555
- /* @__PURE__ */ jsx7(
3094
+ /* @__PURE__ */ jsx8(
2556
3095
  Component,
2557
3096
  {
2558
3097
  ref: containerRef,
@@ -2578,27 +3117,27 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2578
3117
  options: { offset: 6, placement: "top" },
2579
3118
  className: "ya-bubble-menu",
2580
3119
  children: [
2581
- /* @__PURE__ */ jsx7(
3120
+ /* @__PURE__ */ jsx8(
2582
3121
  "button",
2583
3122
  {
2584
3123
  type: "button",
2585
3124
  onClick: () => editor.chain().focus().toggleBold().run(),
2586
3125
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
2587
3126
  title: "Bold",
2588
- children: /* @__PURE__ */ jsx7("strong", { children: "B" })
3127
+ children: /* @__PURE__ */ jsx8("strong", { children: "B" })
2589
3128
  }
2590
3129
  ),
2591
- /* @__PURE__ */ jsx7(
3130
+ /* @__PURE__ */ jsx8(
2592
3131
  "button",
2593
3132
  {
2594
3133
  type: "button",
2595
3134
  onClick: () => editor.chain().focus().toggleItalic().run(),
2596
3135
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
2597
3136
  title: "Italic",
2598
- children: /* @__PURE__ */ jsx7("em", { children: "I" })
3137
+ children: /* @__PURE__ */ jsx8("em", { children: "I" })
2599
3138
  }
2600
3139
  ),
2601
- /* @__PURE__ */ jsx7("span", { className: "ya-bubble-divider" }),
3140
+ /* @__PURE__ */ jsx8("span", { className: "ya-bubble-divider" }),
2602
3141
  /* @__PURE__ */ jsxs4(
2603
3142
  "select",
2604
3143
  {
@@ -2607,8 +3146,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2607
3146
  className: "ya-bubble-select",
2608
3147
  title: "Font Size",
2609
3148
  children: [
2610
- /* @__PURE__ */ jsx7("option", { value: "", children: "Size" }),
2611
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx7("option", { value: size, children: name }, name))
3149
+ /* @__PURE__ */ jsx8("option", { value: "", children: "Size" }),
3150
+ Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx8("option", { value: size, children: name }, name))
2612
3151
  ]
2613
3152
  }
2614
3153
  ),
@@ -2620,8 +3159,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2620
3159
  className: "ya-bubble-select",
2621
3160
  title: "Font Weight",
2622
3161
  children: [
2623
- /* @__PURE__ */ jsx7("option", { value: "", children: "Weight" }),
2624
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx7("option", { value: weight, children: name }, name))
3162
+ /* @__PURE__ */ jsx8("option", { value: "", children: "Weight" }),
3163
+ Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx8("option", { value: weight, children: name }, name))
2625
3164
  ]
2626
3165
  }
2627
3166
  )
@@ -2631,21 +3170,21 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2631
3170
  document.body
2632
3171
  ),
2633
3172
  editingMode === "text" ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
2634
- /* @__PURE__ */ jsx7(EditorContent2, { editor }),
3173
+ /* @__PURE__ */ jsx8(EditorContent2, { editor }),
2635
3174
  /* @__PURE__ */ jsxs4("div", { className: "ya-link-actions", children: [
2636
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
2637
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
3175
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
3176
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
2638
3177
  ] })
2639
- ] }) : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode })
2640
- ] }) : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode })
3178
+ ] }) : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode })
3179
+ ] }) : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode })
2641
3180
  }
2642
3181
  ),
2643
3182
  showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs4("div", { className: "ya-link-edit-popover", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [
2644
- !isIconMode && /* @__PURE__ */ jsx7("button", { type: "button", onClick: startEditText, children: "Edit text" }),
2645
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: startEditLink, children: "Edit link" })
3183
+ !isIconMode && /* @__PURE__ */ jsx8("button", { type: "button", onClick: startEditText, children: "Edit text" }),
3184
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: startEditLink, children: "Edit link" })
2646
3185
  ] }),
2647
3186
  editingMode === "link" && /* @__PURE__ */ jsxs4("div", { ref: hrefPopoverRef, className: "ya-href-popover", children: [
2648
- /* @__PURE__ */ jsx7("div", { className: "ya-href-popover-header", children: "Link destination" }),
3187
+ /* @__PURE__ */ jsx8("div", { className: "ya-href-popover-header", children: "Link destination" }),
2649
3188
  !isExternalUrl ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
2650
3189
  sections.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2651
3190
  /* @__PURE__ */ jsxs4(
@@ -2655,14 +3194,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2655
3194
  className: "ya-href-popover-label ya-href-collapsible-header",
2656
3195
  onClick: () => setSectionsExpanded(!sectionsExpanded),
2657
3196
  children: [
2658
- /* @__PURE__ */ jsx7("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3197
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
2659
3198
  "Scroll to section (",
2660
3199
  sections.length,
2661
3200
  ")"
2662
3201
  ]
2663
3202
  }
2664
3203
  ),
2665
- sectionsExpanded && /* @__PURE__ */ jsx7("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs4(
3204
+ sectionsExpanded && /* @__PURE__ */ jsx8("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs4(
2666
3205
  "button",
2667
3206
  {
2668
3207
  type: "button",
@@ -2670,15 +3209,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2670
3209
  onClick: () => handlePageSelect(section.path),
2671
3210
  children: [
2672
3211
  section.label,
2673
- /* @__PURE__ */ jsx7("span", { className: "ya-href-page-path", children: section.path })
3212
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-page-path", children: section.path })
2674
3213
  ]
2675
3214
  },
2676
3215
  section.path
2677
3216
  )) })
2678
3217
  ] }),
2679
3218
  pages.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2680
- /* @__PURE__ */ jsx7("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
2681
- /* @__PURE__ */ jsx7("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs4(
3219
+ /* @__PURE__ */ jsx8("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
3220
+ /* @__PURE__ */ jsx8("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs4(
2682
3221
  "button",
2683
3222
  {
2684
3223
  type: "button",
@@ -2686,13 +3225,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2686
3225
  onClick: () => handlePageSelect(page.path),
2687
3226
  children: [
2688
3227
  page.label,
2689
- /* @__PURE__ */ jsx7("span", { className: "ya-href-page-path", children: page.path })
3228
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-page-path", children: page.path })
2690
3229
  ]
2691
3230
  },
2692
3231
  page.path
2693
3232
  )) })
2694
3233
  ] }),
2695
- /* @__PURE__ */ jsx7(
3234
+ /* @__PURE__ */ jsx8(
2696
3235
  "button",
2697
3236
  {
2698
3237
  type: "button",
@@ -2706,8 +3245,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2706
3245
  )
2707
3246
  ] }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
2708
3247
  /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2709
- /* @__PURE__ */ jsx7("label", { className: "ya-href-popover-label", children: "External URL" }),
2710
- /* @__PURE__ */ jsx7(
3248
+ /* @__PURE__ */ jsx8("label", { className: "ya-href-popover-label", children: "External URL" }),
3249
+ /* @__PURE__ */ jsx8(
2711
3250
  "input",
2712
3251
  {
2713
3252
  type: "url",
@@ -2719,21 +3258,21 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2719
3258
  }
2720
3259
  )
2721
3260
  ] }),
2722
- /* @__PURE__ */ jsx7("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
3261
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
2723
3262
  ] }),
2724
3263
  /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-actions", children: [
2725
- /* @__PURE__ */ jsx7("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
2726
- isExternalUrl ? /* @__PURE__ */ jsx7("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx7("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
3264
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
3265
+ isExternalUrl ? /* @__PURE__ */ jsx8("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx8("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
2727
3266
  ] })
2728
3267
  ] })
2729
3268
  ] });
2730
3269
  }
2731
3270
 
2732
3271
  // src/components/StaticText.tsx
2733
- import { jsx as jsx8 } from "react/jsx-runtime";
3272
+ import { jsx as jsx9 } from "react/jsx-runtime";
2734
3273
  function MpText({ fieldId, className, as: Component = "span", children }) {
2735
3274
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
2736
- return /* @__PURE__ */ jsx8(
3275
+ return /* @__PURE__ */ jsx9(
2737
3276
  Component,
2738
3277
  {
2739
3278
  className,
@@ -2744,7 +3283,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
2744
3283
  }
2745
3284
 
2746
3285
  // src/components/StaticImage.tsx
2747
- import { jsx as jsx9 } from "react/jsx-runtime";
3286
+ import { jsx as jsx10 } from "react/jsx-runtime";
2748
3287
  function parseImageValue2(value) {
2749
3288
  if (!value) {
2750
3289
  return { src: "" };
@@ -2780,7 +3319,7 @@ function MpImage({
2780
3319
  const altText = imageData.alt || alt || fallbackAlt || "";
2781
3320
  const objectFit = imageData.objectFit || propObjectFit || "cover";
2782
3321
  const objectPosition = getObjectPosition2(imageData) || propObjectPosition || "50% 50%";
2783
- return /* @__PURE__ */ jsx9(
3322
+ return /* @__PURE__ */ jsx10(
2784
3323
  "img",
2785
3324
  {
2786
3325
  src: resolveAssetUrl(src),
@@ -2798,7 +3337,7 @@ function MpImage({
2798
3337
 
2799
3338
  // src/components/MarkdownText.tsx
2800
3339
  import { Fragment as Fragment4 } from "react";
2801
- import { jsx as jsx10 } from "react/jsx-runtime";
3340
+ import { jsx as jsx11 } from "react/jsx-runtime";
2802
3341
  function tokenize(text) {
2803
3342
  const tokens = [];
2804
3343
  let remaining = text;
@@ -2860,13 +3399,13 @@ function tokensToElements(tokens) {
2860
3399
  return tokens.map((token, index) => {
2861
3400
  switch (token.type) {
2862
3401
  case "text":
2863
- return /* @__PURE__ */ jsx10(Fragment4, { children: token.content }, index);
3402
+ return /* @__PURE__ */ jsx11(Fragment4, { children: token.content }, index);
2864
3403
  case "bold":
2865
- return /* @__PURE__ */ jsx10("strong", { children: token.content }, index);
3404
+ return /* @__PURE__ */ jsx11("strong", { children: token.content }, index);
2866
3405
  case "italic":
2867
- return /* @__PURE__ */ jsx10("em", { children: token.content }, index);
3406
+ return /* @__PURE__ */ jsx11("em", { children: token.content }, index);
2868
3407
  case "link":
2869
- return /* @__PURE__ */ jsx10(
3408
+ return /* @__PURE__ */ jsx11(
2870
3409
  "a",
2871
3410
  {
2872
3411
  href: token.url,
@@ -2878,7 +3417,7 @@ function tokensToElements(tokens) {
2878
3417
  index
2879
3418
  );
2880
3419
  case "newline":
2881
- return /* @__PURE__ */ jsx10("br", {}, index);
3420
+ return /* @__PURE__ */ jsx11("br", {}, index);
2882
3421
  default:
2883
3422
  return null;
2884
3423
  }
@@ -2890,15 +3429,15 @@ function parseMarkdownToElements(content) {
2890
3429
  }
2891
3430
  function MarkdownText({ content, className }) {
2892
3431
  const elements = parseMarkdownToElements(content);
2893
- return /* @__PURE__ */ jsx10("span", { className, children: elements });
3432
+ return /* @__PURE__ */ jsx11("span", { className, children: elements });
2894
3433
  }
2895
3434
 
2896
3435
  // src/router/Link.tsx
2897
3436
  import { Link as WouterLink2 } from "wouter";
2898
- import { jsx as jsx11 } from "react/jsx-runtime";
3437
+ import { jsx as jsx12 } from "react/jsx-runtime";
2899
3438
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
2900
3439
  const target = href ?? to ?? "/";
2901
- return /* @__PURE__ */ jsx11(WouterLink2, { href: target, className, onClick, replace, ...props, children });
3440
+ return /* @__PURE__ */ jsx12(WouterLink2, { href: target, className, onClick, replace, ...props, children });
2902
3441
  }
2903
3442
 
2904
3443
  // src/router/useNavigate.ts
@@ -2917,7 +3456,7 @@ function useNavigate() {
2917
3456
 
2918
3457
  // src/router/Router.tsx
2919
3458
  import { Router as WouterRouter } from "wouter";
2920
- import { jsx as jsx12 } from "react/jsx-runtime";
3459
+ import { jsx as jsx13 } from "react/jsx-runtime";
2921
3460
  function detectBasename() {
2922
3461
  if (typeof window === "undefined") return "";
2923
3462
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -2932,12 +3471,13 @@ function detectBasename() {
2932
3471
  }
2933
3472
  function Router({ children, base }) {
2934
3473
  const basename = base ?? detectBasename();
2935
- return /* @__PURE__ */ jsx12(WouterRouter, { base: basename, children });
3474
+ return /* @__PURE__ */ jsx13(WouterRouter, { base: basename, children });
2936
3475
  }
2937
3476
 
2938
3477
  // src/router/index.ts
2939
3478
  import { Route, Switch } from "wouter";
2940
3479
  export {
3480
+ AIEditProvider,
2941
3481
  ContentStoreProvider,
2942
3482
  ContentStoreProvider2 as ContentStoreProviderProd,
2943
3483
  Link2 as Link,
@@ -2951,15 +3491,28 @@ export {
2951
3491
  YaImage,
2952
3492
  YaLink,
2953
3493
  YaText,
3494
+ buildIntermediateText,
3495
+ calculateAnimationTiming,
3496
+ computeTextDiff,
3497
+ containsHtml,
2954
3498
  contentRegistry,
2955
3499
  getAllContent,
2956
3500
  getContent,
3501
+ getTextCursorPosition,
2957
3502
  hasContent,
3503
+ imageCrossfadeStrategy,
2958
3504
  initBuilderSelection,
3505
+ linkTransitionStrategy,
2959
3506
  registerContent,
2960
3507
  resolveAssetUrl,
2961
3508
  serializeImageValue,
2962
3509
  setAssetResolver,
3510
+ stripHtml,
3511
+ textTypingStrategy,
3512
+ useAIEditAnimation,
3513
+ useAIEditContext,
3514
+ useAIEditContextOptional,
3515
+ useAnimatedText,
2963
3516
  useContentStore,
2964
3517
  useContentStore2 as useContentStoreProd,
2965
3518
  useNavigate