@yoamigo.com/core 0.1.10 → 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.
package/dist/index.js CHANGED
@@ -198,6 +198,9 @@ var BuilderSelectionManager = class {
198
198
  case "CLEAR_SELECTIONS":
199
199
  this.clearAllSelections();
200
200
  break;
201
+ case "REQUEST_SCREENSHOT":
202
+ this.captureFullPageScreenshot();
203
+ break;
201
204
  case "REQUEST_REGION_SCREENSHOT":
202
205
  if (data.region) {
203
206
  this.captureRegionScreenshot(data.region);
@@ -572,6 +575,41 @@ var BuilderSelectionManager = class {
572
575
  container.style.height = `${rect.height}px`;
573
576
  });
574
577
  };
578
+ /**
579
+ * Capture a full-page screenshot for loading placeholder
580
+ * Uses html2canvas to render the page at reduced quality for smaller file size
581
+ */
582
+ async captureFullPageScreenshot() {
583
+ try {
584
+ console.log("[BuilderSelection] Capturing full-page screenshot");
585
+ const html2canvas = (await import("html2canvas-pro")).default;
586
+ const overlays = document.querySelectorAll(".builder-selection-container, #builder-hover-overlay");
587
+ overlays.forEach((el) => {
588
+ ;
589
+ el.style.display = "none";
590
+ });
591
+ const canvas = await html2canvas(document.body, {
592
+ scale: 0.5,
593
+ // Lower resolution for placeholder
594
+ logging: false,
595
+ useCORS: true,
596
+ allowTaint: true,
597
+ backgroundColor: null
598
+ });
599
+ overlays.forEach((el) => {
600
+ ;
601
+ el.style.display = "";
602
+ });
603
+ const dataUrl = canvas.toDataURL("image/jpeg", 0.6);
604
+ console.log("[BuilderSelection] Full-page screenshot captured, size:", dataUrl.length);
605
+ this.sendToParent({
606
+ type: "SCREENSHOT_READY",
607
+ dataUrl
608
+ });
609
+ } catch (error) {
610
+ console.error("[BuilderSelection] Full-page screenshot failed:", error);
611
+ }
612
+ }
575
613
  /**
576
614
  * Capture a region of the page as a screenshot
577
615
  * Uses html2canvas to render the page and then crops to the specified region
@@ -900,7 +938,7 @@ function ContentStoreProvider2({ children }) {
900
938
  }
901
939
 
902
940
  // src/components/YaText.tsx
903
- 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";
904
942
  import { createPortal as createPortal2 } from "react-dom";
905
943
  import { useEditor, EditorContent } from "@tiptap/react";
906
944
  import { BubbleMenu } from "@tiptap/react/menus";
@@ -1127,6 +1165,523 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1127
1165
  ] });
1128
1166
  }
1129
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
+
1130
1685
  // #style-inject:#style-inject
1131
1686
  function styleInject(css, { insertAt } = {}) {
1132
1687
  if (!css || typeof document === "undefined") return;
@@ -1377,8 +1932,11 @@ body.builder-selector-active .ya-text-editable:hover {
1377
1932
  }
1378
1933
  `);
1379
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
+
1380
1938
  // src/components/YaText.tsx
1381
- 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";
1382
1940
  var FontSize = Extension.create({
1383
1941
  name: "fontSize",
1384
1942
  addOptions() {
@@ -1473,10 +2031,17 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1473
2031
  const { getValue, setValue, mode, saveToWorker, activeFieldId, setActiveField } = useContentStore();
1474
2032
  const storeContent = getValue(fieldId);
1475
2033
  const content = storeContent || (typeof children === "string" ? children : "");
1476
- const [isEditing, setIsEditing] = useState3(false);
1477
- const [originalContent, setOriginalContent] = useState3(content);
1478
- const containerRef = useRef3(null);
1479
- 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);
1480
2045
  const editor = useEditor({
1481
2046
  extensions: [
1482
2047
  StarterKit.configure({
@@ -1510,19 +2075,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1510
2075
  },
1511
2076
  parseOptions: { preserveWhitespace: "full" }
1512
2077
  });
1513
- useEffect3(() => {
2078
+ useEffect4(() => {
1514
2079
  if (editor && !isEditing) {
1515
2080
  if (editor.getHTML() !== content) {
1516
2081
  editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
1517
2082
  }
1518
2083
  }
1519
2084
  }, [content, editor, isEditing]);
1520
- useEffect3(() => {
2085
+ useEffect4(() => {
1521
2086
  if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
1522
2087
  setIsEditing(false);
1523
2088
  }
1524
2089
  }, [activeFieldId, fieldId, isEditing]);
1525
- const handleSave = useCallback3(() => {
2090
+ const handleSave = useCallback5(() => {
1526
2091
  if (!editor) return;
1527
2092
  let html = editor.getHTML();
1528
2093
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -1530,13 +2095,13 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1530
2095
  saveToWorker?.(fieldId, html);
1531
2096
  setIsEditing(false);
1532
2097
  }, [editor, fieldId, setValue, saveToWorker]);
1533
- const handleCancel = useCallback3(() => {
2098
+ const handleCancel = useCallback5(() => {
1534
2099
  if (editor) {
1535
2100
  editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
1536
2101
  }
1537
2102
  setIsEditing(false);
1538
2103
  }, [editor, originalContent]);
1539
- const handleClose = useCallback3(() => {
2104
+ const handleClose = useCallback5(() => {
1540
2105
  if (!editor) {
1541
2106
  setIsEditing(false);
1542
2107
  return;
@@ -1549,7 +2114,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1549
2114
  }
1550
2115
  setIsEditing(false);
1551
2116
  }, [editor, fieldId, setValue, saveToWorker]);
1552
- const handleClick = useCallback3((e) => {
2117
+ const handleClick = useCallback5((e) => {
1553
2118
  if (isEditing) {
1554
2119
  e.preventDefault();
1555
2120
  e.stopPropagation();
@@ -1575,7 +2140,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1575
2140
  }, 20);
1576
2141
  }
1577
2142
  }, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
1578
- const handleKeyDown = useCallback3(
2143
+ const handleKeyDown = useCallback5(
1579
2144
  (event) => {
1580
2145
  if (!isEditing) return;
1581
2146
  if (event.key === "Enter" && !event.shiftKey) {
@@ -1596,7 +2161,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1596
2161
  },
1597
2162
  [isEditing, handleSave, handleCancel]
1598
2163
  );
1599
- const handleLink = useCallback3(() => {
2164
+ const handleLink = useCallback5(() => {
1600
2165
  if (!editor) return;
1601
2166
  const previousUrl = editor.getAttributes("link").href;
1602
2167
  const url = window.prompt("Enter URL:", previousUrl || "https://");
@@ -1607,7 +2172,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1607
2172
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
1608
2173
  }
1609
2174
  }, [editor]);
1610
- const handleFontSizeChange = useCallback3(
2175
+ const handleFontSizeChange = useCallback5(
1611
2176
  (e) => {
1612
2177
  if (!editor) return;
1613
2178
  const size = e.target.value;
@@ -1619,7 +2184,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1619
2184
  },
1620
2185
  [editor]
1621
2186
  );
1622
- const handleFontWeightChange = useCallback3(
2187
+ const handleFontWeightChange = useCallback5(
1623
2188
  (e) => {
1624
2189
  if (!editor) return;
1625
2190
  const weight = e.target.value;
@@ -1642,24 +2207,30 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1642
2207
  return attrs.fontWeight || "";
1643
2208
  };
1644
2209
  if (mode === "read-only") {
1645
- return /* @__PURE__ */ jsx4(
2210
+ return /* @__PURE__ */ jsx5(
1646
2211
  Component,
1647
2212
  {
1648
2213
  ref: containerRef,
1649
2214
  className,
1650
2215
  "data-ya-restricted": "true",
1651
2216
  "data-field-id": fieldId,
1652
- children: /* @__PURE__ */ jsx4(SafeHtml, { content, mode })
2217
+ children: /* @__PURE__ */ jsx5(SafeHtml, { content, mode })
1653
2218
  }
1654
2219
  );
1655
2220
  }
1656
- 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(
1657
2227
  Component,
1658
2228
  {
1659
2229
  ref: containerRef,
1660
- className: `${className || ""} ${isEditing ? "ya-text-editing" : "ya-text-editable"}`,
2230
+ className: combinedClassName,
1661
2231
  "data-ya-restricted": "true",
1662
2232
  "data-field-id": fieldId,
2233
+ "data-ai-editing": isAnimating || void 0,
1663
2234
  onClick: handleClick,
1664
2235
  onKeyDown: handleKeyDown,
1665
2236
  children: editor ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
@@ -1672,37 +2243,37 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1672
2243
  options: { offset: 6, placement: "top" },
1673
2244
  className: "ya-bubble-menu",
1674
2245
  children: [
1675
- /* @__PURE__ */ jsx4(
2246
+ /* @__PURE__ */ jsx5(
1676
2247
  "button",
1677
2248
  {
1678
2249
  type: "button",
1679
2250
  onClick: () => editor.chain().focus().toggleBold().run(),
1680
2251
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
1681
2252
  title: "Bold",
1682
- children: /* @__PURE__ */ jsx4("strong", { children: "B" })
2253
+ children: /* @__PURE__ */ jsx5("strong", { children: "B" })
1683
2254
  }
1684
2255
  ),
1685
- /* @__PURE__ */ jsx4(
2256
+ /* @__PURE__ */ jsx5(
1686
2257
  "button",
1687
2258
  {
1688
2259
  type: "button",
1689
2260
  onClick: () => editor.chain().focus().toggleItalic().run(),
1690
2261
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
1691
2262
  title: "Italic",
1692
- children: /* @__PURE__ */ jsx4("em", { children: "I" })
2263
+ children: /* @__PURE__ */ jsx5("em", { children: "I" })
1693
2264
  }
1694
2265
  ),
1695
- /* @__PURE__ */ jsx4(
2266
+ /* @__PURE__ */ jsx5(
1696
2267
  "button",
1697
2268
  {
1698
2269
  type: "button",
1699
2270
  onClick: handleLink,
1700
2271
  className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
1701
2272
  title: "Link",
1702
- children: /* @__PURE__ */ jsx4("span", { children: "\u{1F517}" })
2273
+ children: /* @__PURE__ */ jsx5("span", { children: "\u{1F517}" })
1703
2274
  }
1704
2275
  ),
1705
- /* @__PURE__ */ jsx4("span", { className: "ya-bubble-divider" }),
2276
+ /* @__PURE__ */ jsx5("span", { className: "ya-bubble-divider" }),
1706
2277
  /* @__PURE__ */ jsxs2(
1707
2278
  "select",
1708
2279
  {
@@ -1711,8 +2282,8 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1711
2282
  className: "ya-bubble-select",
1712
2283
  title: "Font Size",
1713
2284
  children: [
1714
- /* @__PURE__ */ jsx4("option", { value: "", children: "Size" }),
1715
- 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))
1716
2287
  ]
1717
2288
  }
1718
2289
  ),
@@ -1724,8 +2295,8 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1724
2295
  className: "ya-bubble-select",
1725
2296
  title: "Font Weight",
1726
2297
  children: [
1727
- /* @__PURE__ */ jsx4("option", { value: "", children: "Weight" }),
1728
- 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))
1729
2300
  ]
1730
2301
  }
1731
2302
  )
@@ -1735,9 +2306,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1735
2306
  document.body
1736
2307
  ),
1737
2308
  isEditing ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1738
- /* @__PURE__ */ jsx4(EditorContent, { editor }),
2309
+ /* @__PURE__ */ jsx5(EditorContent, { editor }),
1739
2310
  /* @__PURE__ */ jsxs2("div", { className: "ya-text-actions", children: [
1740
- /* @__PURE__ */ jsx4(
2311
+ /* @__PURE__ */ jsx5(
1741
2312
  "button",
1742
2313
  {
1743
2314
  type: "button",
@@ -1746,7 +2317,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1746
2317
  children: "Cancel"
1747
2318
  }
1748
2319
  ),
1749
- /* @__PURE__ */ jsx4(
2320
+ /* @__PURE__ */ jsx5(
1750
2321
  "button",
1751
2322
  {
1752
2323
  type: "button",
@@ -1756,14 +2327,20 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
1756
2327
  }
1757
2328
  )
1758
2329
  ] })
1759
- ] }) : /* @__PURE__ */ jsx4(SafeHtml, { content, mode })
1760
- ] }) : /* @__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
+ ] })
1761
2338
  }
1762
2339
  );
1763
2340
  }
1764
2341
 
1765
2342
  // src/components/YaImage.tsx
1766
- 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";
1767
2344
 
1768
2345
  // src/lib/asset-resolver.ts
1769
2346
  var assetResolver = (path) => path;
@@ -1779,25 +2356,25 @@ function resolveAssetUrl(path) {
1779
2356
  }
1780
2357
 
1781
2358
  // src/components/YaTooltip.tsx
1782
- 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";
1783
2360
  import { createPortal as createPortal3 } from "react-dom";
1784
2361
 
1785
2362
  // src/components/ya-tooltip.css
1786
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');
1787
2364
 
1788
2365
  // src/components/YaTooltip.tsx
1789
- import { jsx as jsx5 } from "react/jsx-runtime";
2366
+ import { jsx as jsx6 } from "react/jsx-runtime";
1790
2367
  function YaTooltip({
1791
2368
  anchorRef,
1792
2369
  children,
1793
2370
  show,
1794
2371
  preferredPosition = "bottom"
1795
2372
  }) {
1796
- const [position, setPosition] = useState4(preferredPosition);
1797
- const [coords, setCoords] = useState4({ top: 0, left: 0 });
1798
- const [isPositioned, setIsPositioned] = useState4(false);
1799
- const tooltipRef = useRef4(null);
1800
- 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(() => {
1801
2378
  if (!anchorRef.current) return;
1802
2379
  const anchor = anchorRef.current.getBoundingClientRect();
1803
2380
  const tooltip = tooltipRef.current?.getBoundingClientRect();
@@ -1872,7 +2449,7 @@ function YaTooltip({
1872
2449
  setCoords({ top, left });
1873
2450
  setIsPositioned(true);
1874
2451
  }, [anchorRef, preferredPosition]);
1875
- useEffect4(() => {
2452
+ useEffect5(() => {
1876
2453
  if (!show) {
1877
2454
  setIsPositioned(false);
1878
2455
  return;
@@ -1885,14 +2462,14 @@ function YaTooltip({
1885
2462
  window.removeEventListener("resize", calculatePosition);
1886
2463
  };
1887
2464
  }, [show, calculatePosition]);
1888
- useEffect4(() => {
2465
+ useEffect5(() => {
1889
2466
  if (show && tooltipRef.current) {
1890
2467
  calculatePosition();
1891
2468
  }
1892
2469
  }, [show, children, calculatePosition]);
1893
2470
  if (!show) return null;
1894
2471
  return createPortal3(
1895
- /* @__PURE__ */ jsx5(
2472
+ /* @__PURE__ */ jsx6(
1896
2473
  "div",
1897
2474
  {
1898
2475
  ref: tooltipRef,
@@ -1915,7 +2492,7 @@ function YaTooltip({
1915
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');
1916
2493
 
1917
2494
  // src/components/YaImage.tsx
1918
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2495
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1919
2496
  function parseImageValue(value) {
1920
2497
  if (!value) {
1921
2498
  return { src: "" };
@@ -1950,18 +2527,18 @@ function YaImage({
1950
2527
  fallbackAlt
1951
2528
  }) {
1952
2529
  const { getValue, mode } = useContentStore();
1953
- const containerRef = useRef5(null);
1954
- const imgRef = useRef5(null);
1955
- const [isSelected, setIsSelected] = useState5(false);
1956
- const [isHovered, setIsHovered] = useState5(false);
1957
- 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);
1958
2535
  const rawValue = getValue(fieldId);
1959
2536
  const imageData = parseImageValue(rawValue);
1960
2537
  const src = imageData.src || fallbackSrc || "";
1961
2538
  const altText = imageData.alt || alt || fallbackAlt || "";
1962
2539
  const objectFit = imageData.objectFit || propObjectFit || "cover";
1963
2540
  const objectPosition = getObjectPosition(imageData) || propObjectPosition || "50% 50%";
1964
- const handleClick = useCallback5(() => {
2541
+ const handleClick = useCallback7(() => {
1965
2542
  if (mode !== "inline-edit") return;
1966
2543
  if (document.body.classList.contains("builder-selector-active")) return;
1967
2544
  setIsSelected(true);
@@ -1989,7 +2566,7 @@ function YaImage({
1989
2566
  "*"
1990
2567
  );
1991
2568
  }, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
1992
- useEffect5(() => {
2569
+ useEffect6(() => {
1993
2570
  if (mode !== "inline-edit") return;
1994
2571
  const handleMessage2 = (event) => {
1995
2572
  if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -2004,7 +2581,7 @@ function YaImage({
2004
2581
  window.addEventListener("message", handleMessage2);
2005
2582
  return () => window.removeEventListener("message", handleMessage2);
2006
2583
  }, [mode, fieldId]);
2007
- useEffect5(() => {
2584
+ useEffect6(() => {
2008
2585
  if (mode !== "inline-edit") return;
2009
2586
  const checkSize = () => {
2010
2587
  if (imgRef.current) {
@@ -2026,7 +2603,7 @@ function YaImage({
2026
2603
  window.removeEventListener("resize", checkSize);
2027
2604
  };
2028
2605
  }, [mode]);
2029
- useEffect5(() => {
2606
+ useEffect6(() => {
2030
2607
  if (!isSelected || mode !== "inline-edit") return;
2031
2608
  let lastRectKey = "";
2032
2609
  let lastTime = 0;
@@ -2061,7 +2638,7 @@ function YaImage({
2061
2638
  return () => cancelAnimationFrame(rafId);
2062
2639
  }, [isSelected, fieldId, mode]);
2063
2640
  if (mode === "read-only") {
2064
- return /* @__PURE__ */ jsx6(
2641
+ return /* @__PURE__ */ jsx7(
2065
2642
  "img",
2066
2643
  {
2067
2644
  src: resolveAssetUrl(src),
@@ -2089,9 +2666,9 @@ function YaImage({
2089
2666
  strokeLinecap: "round",
2090
2667
  strokeLinejoin: "round",
2091
2668
  children: [
2092
- /* @__PURE__ */ jsx6("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
2093
- /* @__PURE__ */ jsx6("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2094
- /* @__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" })
2095
2672
  ]
2096
2673
  }
2097
2674
  );
@@ -2116,7 +2693,7 @@ function YaImage({
2116
2693
  }
2117
2694
  },
2118
2695
  children: [
2119
- /* @__PURE__ */ jsx6(
2696
+ /* @__PURE__ */ jsx7(
2120
2697
  "img",
2121
2698
  {
2122
2699
  ref: imgRef,
@@ -2132,12 +2709,12 @@ function YaImage({
2132
2709
  ),
2133
2710
  isSmallImage ? /* @__PURE__ */ jsxs3(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
2134
2711
  editIcon,
2135
- /* @__PURE__ */ jsx6("span", { children: "Click to edit" })
2712
+ /* @__PURE__ */ jsx7("span", { children: "Click to edit" })
2136
2713
  ] }) : (
2137
2714
  /* For large images: show overlay inside the image */
2138
2715
  /* @__PURE__ */ jsxs3("div", { className: "ya-image-overlay", children: [
2139
- /* @__PURE__ */ jsx6("div", { className: "ya-image-edit-icon", children: editIcon }),
2140
- /* @__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" })
2141
2718
  ] })
2142
2719
  )
2143
2720
  ]
@@ -2146,7 +2723,7 @@ function YaImage({
2146
2723
  }
2147
2724
 
2148
2725
  // src/components/YaLink.tsx
2149
- 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";
2150
2727
  import { createPortal as createPortal4 } from "react-dom";
2151
2728
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
2152
2729
  import { BubbleMenu as BubbleMenu2 } from "@tiptap/react/menus";
@@ -2159,7 +2736,7 @@ import { Link as WouterLink, useLocation } from "wouter";
2159
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');
2160
2737
 
2161
2738
  // src/components/YaLink.tsx
2162
- 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";
2163
2740
  function isInternalPath(path) {
2164
2741
  if (!path) return false;
2165
2742
  if (path.startsWith("#")) return false;
@@ -2254,8 +2831,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2254
2831
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
2255
2832
  const [, navigate] = useLocation();
2256
2833
  const pages = availablePages ?? getPages();
2257
- const [sections, setSections] = useState6([]);
2258
- const [sectionsExpanded, setSectionsExpanded] = useState6(false);
2834
+ const [sections, setSections] = useState7([]);
2835
+ const [sectionsExpanded, setSectionsExpanded] = useState7(false);
2259
2836
  const textFieldId = `${fieldId}.text`;
2260
2837
  const hrefFieldId = `${fieldId}.href`;
2261
2838
  const storeText = getValue(textFieldId);
@@ -2263,16 +2840,16 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2263
2840
  const isIconMode = children != null && typeof children !== "string";
2264
2841
  const text = storeText || (typeof children === "string" ? children : "");
2265
2842
  const href = storeHref || defaultHref;
2266
- const [editingMode, setEditingMode] = useState6(null);
2267
- const [showEditPopover, setShowEditPopover] = useState6(false);
2268
- const [originalText, setOriginalText] = useState6(text);
2269
- const [originalHref, setOriginalHref] = useState6(href);
2270
- const [currentHref, setCurrentHref] = useState6(href);
2271
- const [isExternalUrl, setIsExternalUrl] = useState6(false);
2272
- const [externalUrl, setExternalUrl] = useState6("");
2273
- const containerRef = useRef6(null);
2274
- const hrefPopoverRef = useRef6(null);
2275
- 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);
2276
2853
  const editor = useEditor2({
2277
2854
  extensions: [
2278
2855
  StarterKit2.configure({
@@ -2295,26 +2872,26 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2295
2872
  }
2296
2873
  }
2297
2874
  });
2298
- useEffect6(() => {
2875
+ useEffect7(() => {
2299
2876
  if (editor && editingMode !== "text") {
2300
2877
  if (editor.getHTML() !== text) {
2301
2878
  editor.commands.setContent(text);
2302
2879
  }
2303
2880
  }
2304
2881
  }, [text, editor, editingMode]);
2305
- useEffect6(() => {
2882
+ useEffect7(() => {
2306
2883
  if (editingMode !== "link") {
2307
2884
  setCurrentHref(href);
2308
2885
  }
2309
2886
  }, [href, editingMode]);
2310
- useEffect6(() => {
2887
+ useEffect7(() => {
2311
2888
  return () => {
2312
2889
  if (hidePopoverTimeoutRef.current) {
2313
2890
  clearTimeout(hidePopoverTimeoutRef.current);
2314
2891
  }
2315
2892
  };
2316
2893
  }, []);
2317
- useEffect6(() => {
2894
+ useEffect7(() => {
2318
2895
  if (editingMode !== "link") return;
2319
2896
  const handleClickOutside = (event) => {
2320
2897
  const target = event.target;
@@ -2328,7 +2905,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2328
2905
  document.addEventListener("mousedown", handleClickOutside);
2329
2906
  return () => document.removeEventListener("mousedown", handleClickOutside);
2330
2907
  }, [editingMode, originalHref]);
2331
- const handleSaveText = useCallback6(() => {
2908
+ const handleSaveText = useCallback8(() => {
2332
2909
  if (!editor) return;
2333
2910
  let html = editor.getHTML();
2334
2911
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -2336,26 +2913,26 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2336
2913
  saveToWorker?.(textFieldId, html);
2337
2914
  setEditingMode(null);
2338
2915
  }, [editor, textFieldId, setValue, saveToWorker]);
2339
- const handleSaveLink = useCallback6(() => {
2916
+ const handleSaveLink = useCallback8(() => {
2340
2917
  setValue(hrefFieldId, currentHref);
2341
2918
  saveToWorker?.(hrefFieldId, currentHref);
2342
2919
  setEditingMode(null);
2343
2920
  setIsExternalUrl(false);
2344
2921
  setExternalUrl("");
2345
2922
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
2346
- const handleCancelText = useCallback6(() => {
2923
+ const handleCancelText = useCallback8(() => {
2347
2924
  if (editor) {
2348
2925
  editor.commands.setContent(originalText);
2349
2926
  }
2350
2927
  setEditingMode(null);
2351
2928
  }, [editor, originalText]);
2352
- const handleCancelLink = useCallback6(() => {
2929
+ const handleCancelLink = useCallback8(() => {
2353
2930
  setCurrentHref(originalHref);
2354
2931
  setEditingMode(null);
2355
2932
  setIsExternalUrl(false);
2356
2933
  setExternalUrl("");
2357
2934
  }, [originalHref]);
2358
- const handleClick = useCallback6(
2935
+ const handleClick = useCallback8(
2359
2936
  (e) => {
2360
2937
  const selectModeEnabled = window.__builderSelectModeEnabled;
2361
2938
  if (selectModeEnabled) {
@@ -2387,7 +2964,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2387
2964
  },
2388
2965
  [href, navigate, onClick]
2389
2966
  );
2390
- const handleMouseEnter = useCallback6(() => {
2967
+ const handleMouseEnter = useCallback8(() => {
2391
2968
  if (hidePopoverTimeoutRef.current) {
2392
2969
  clearTimeout(hidePopoverTimeoutRef.current);
2393
2970
  hidePopoverTimeoutRef.current = null;
@@ -2396,19 +2973,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2396
2973
  setShowEditPopover(true);
2397
2974
  }
2398
2975
  }, [mode, editingMode]);
2399
- const handleMouseLeave = useCallback6(() => {
2976
+ const handleMouseLeave = useCallback8(() => {
2400
2977
  hidePopoverTimeoutRef.current = window.setTimeout(() => {
2401
2978
  if (!editingMode) {
2402
2979
  setShowEditPopover(false);
2403
2980
  }
2404
2981
  }, 150);
2405
2982
  }, [editingMode]);
2406
- const handleFocus = useCallback6(() => {
2983
+ const handleFocus = useCallback8(() => {
2407
2984
  if (mode === "inline-edit" && !editingMode) {
2408
2985
  setShowEditPopover(true);
2409
2986
  }
2410
2987
  }, [mode, editingMode]);
2411
- const startEditText = useCallback6(() => {
2988
+ const startEditText = useCallback8(() => {
2412
2989
  setShowEditPopover(false);
2413
2990
  setEditingMode("text");
2414
2991
  setOriginalText(text);
@@ -2416,14 +2993,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2416
2993
  editor?.chain().focus().selectAll().run();
2417
2994
  }, 20);
2418
2995
  }, [text, editor]);
2419
- const startEditLink = useCallback6(() => {
2996
+ const startEditLink = useCallback8(() => {
2420
2997
  setShowEditPopover(false);
2421
2998
  setEditingMode("link");
2422
2999
  setOriginalHref(href);
2423
3000
  setCurrentHref(href);
2424
3001
  setSections(discoverSectionsFromDOM());
2425
3002
  }, [href]);
2426
- const handleKeyDown = useCallback6(
3003
+ const handleKeyDown = useCallback8(
2427
3004
  (event) => {
2428
3005
  if (editingMode !== "text") return;
2429
3006
  if (event.key === "Enter" && !event.shiftKey) {
@@ -2444,7 +3021,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2444
3021
  },
2445
3022
  [editingMode, handleSaveText, handleCancelText]
2446
3023
  );
2447
- const handleFontSizeChange = useCallback6(
3024
+ const handleFontSizeChange = useCallback8(
2448
3025
  (e) => {
2449
3026
  if (!editor) return;
2450
3027
  const size = e.target.value;
@@ -2456,7 +3033,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2456
3033
  },
2457
3034
  [editor]
2458
3035
  );
2459
- const handleFontWeightChange = useCallback6(
3036
+ const handleFontWeightChange = useCallback8(
2460
3037
  (e) => {
2461
3038
  if (!editor) return;
2462
3039
  const weight = e.target.value;
@@ -2468,11 +3045,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2468
3045
  },
2469
3046
  [editor]
2470
3047
  );
2471
- const handlePageSelect = useCallback6((path) => {
3048
+ const handlePageSelect = useCallback8((path) => {
2472
3049
  setCurrentHref(path);
2473
3050
  setIsExternalUrl(false);
2474
3051
  }, []);
2475
- const handleExternalUrlApply = useCallback6(() => {
3052
+ const handleExternalUrlApply = useCallback8(() => {
2476
3053
  if (externalUrl) {
2477
3054
  setCurrentHref(externalUrl);
2478
3055
  }
@@ -2488,9 +3065,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2488
3065
  return attrs.fontWeight || "";
2489
3066
  };
2490
3067
  if (mode === "read-only") {
2491
- const content = isIconMode ? children : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode });
3068
+ const content = isIconMode ? children : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode });
2492
3069
  if (isInternalPath(href)) {
2493
- return /* @__PURE__ */ jsx7(
3070
+ return /* @__PURE__ */ jsx8(
2494
3071
  WouterLink,
2495
3072
  {
2496
3073
  href,
@@ -2501,7 +3078,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2501
3078
  }
2502
3079
  );
2503
3080
  }
2504
- return /* @__PURE__ */ jsx7(
3081
+ return /* @__PURE__ */ jsx8(
2505
3082
  Component,
2506
3083
  {
2507
3084
  ref: containerRef,
@@ -2514,7 +3091,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2514
3091
  );
2515
3092
  }
2516
3093
  return /* @__PURE__ */ jsxs4("span", { className: "ya-link-wrapper", children: [
2517
- /* @__PURE__ */ jsx7(
3094
+ /* @__PURE__ */ jsx8(
2518
3095
  Component,
2519
3096
  {
2520
3097
  ref: containerRef,
@@ -2540,27 +3117,27 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2540
3117
  options: { offset: 6, placement: "top" },
2541
3118
  className: "ya-bubble-menu",
2542
3119
  children: [
2543
- /* @__PURE__ */ jsx7(
3120
+ /* @__PURE__ */ jsx8(
2544
3121
  "button",
2545
3122
  {
2546
3123
  type: "button",
2547
3124
  onClick: () => editor.chain().focus().toggleBold().run(),
2548
3125
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
2549
3126
  title: "Bold",
2550
- children: /* @__PURE__ */ jsx7("strong", { children: "B" })
3127
+ children: /* @__PURE__ */ jsx8("strong", { children: "B" })
2551
3128
  }
2552
3129
  ),
2553
- /* @__PURE__ */ jsx7(
3130
+ /* @__PURE__ */ jsx8(
2554
3131
  "button",
2555
3132
  {
2556
3133
  type: "button",
2557
3134
  onClick: () => editor.chain().focus().toggleItalic().run(),
2558
3135
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
2559
3136
  title: "Italic",
2560
- children: /* @__PURE__ */ jsx7("em", { children: "I" })
3137
+ children: /* @__PURE__ */ jsx8("em", { children: "I" })
2561
3138
  }
2562
3139
  ),
2563
- /* @__PURE__ */ jsx7("span", { className: "ya-bubble-divider" }),
3140
+ /* @__PURE__ */ jsx8("span", { className: "ya-bubble-divider" }),
2564
3141
  /* @__PURE__ */ jsxs4(
2565
3142
  "select",
2566
3143
  {
@@ -2569,8 +3146,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2569
3146
  className: "ya-bubble-select",
2570
3147
  title: "Font Size",
2571
3148
  children: [
2572
- /* @__PURE__ */ jsx7("option", { value: "", children: "Size" }),
2573
- 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))
2574
3151
  ]
2575
3152
  }
2576
3153
  ),
@@ -2582,8 +3159,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2582
3159
  className: "ya-bubble-select",
2583
3160
  title: "Font Weight",
2584
3161
  children: [
2585
- /* @__PURE__ */ jsx7("option", { value: "", children: "Weight" }),
2586
- 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))
2587
3164
  ]
2588
3165
  }
2589
3166
  )
@@ -2593,21 +3170,21 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2593
3170
  document.body
2594
3171
  ),
2595
3172
  editingMode === "text" ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
2596
- /* @__PURE__ */ jsx7(EditorContent2, { editor }),
3173
+ /* @__PURE__ */ jsx8(EditorContent2, { editor }),
2597
3174
  /* @__PURE__ */ jsxs4("div", { className: "ya-link-actions", children: [
2598
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
2599
- /* @__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" })
2600
3177
  ] })
2601
- ] }) : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode })
2602
- ] }) : /* @__PURE__ */ jsx7(SafeHtml, { content: text, mode })
3178
+ ] }) : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode })
3179
+ ] }) : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode })
2603
3180
  }
2604
3181
  ),
2605
3182
  showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs4("div", { className: "ya-link-edit-popover", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [
2606
- !isIconMode && /* @__PURE__ */ jsx7("button", { type: "button", onClick: startEditText, children: "Edit text" }),
2607
- /* @__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" })
2608
3185
  ] }),
2609
3186
  editingMode === "link" && /* @__PURE__ */ jsxs4("div", { ref: hrefPopoverRef, className: "ya-href-popover", children: [
2610
- /* @__PURE__ */ jsx7("div", { className: "ya-href-popover-header", children: "Link destination" }),
3187
+ /* @__PURE__ */ jsx8("div", { className: "ya-href-popover-header", children: "Link destination" }),
2611
3188
  !isExternalUrl ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
2612
3189
  sections.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2613
3190
  /* @__PURE__ */ jsxs4(
@@ -2617,14 +3194,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2617
3194
  className: "ya-href-popover-label ya-href-collapsible-header",
2618
3195
  onClick: () => setSectionsExpanded(!sectionsExpanded),
2619
3196
  children: [
2620
- /* @__PURE__ */ jsx7("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3197
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
2621
3198
  "Scroll to section (",
2622
3199
  sections.length,
2623
3200
  ")"
2624
3201
  ]
2625
3202
  }
2626
3203
  ),
2627
- 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(
2628
3205
  "button",
2629
3206
  {
2630
3207
  type: "button",
@@ -2632,15 +3209,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2632
3209
  onClick: () => handlePageSelect(section.path),
2633
3210
  children: [
2634
3211
  section.label,
2635
- /* @__PURE__ */ jsx7("span", { className: "ya-href-page-path", children: section.path })
3212
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-page-path", children: section.path })
2636
3213
  ]
2637
3214
  },
2638
3215
  section.path
2639
3216
  )) })
2640
3217
  ] }),
2641
3218
  pages.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2642
- /* @__PURE__ */ jsx7("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
2643
- /* @__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(
2644
3221
  "button",
2645
3222
  {
2646
3223
  type: "button",
@@ -2648,13 +3225,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2648
3225
  onClick: () => handlePageSelect(page.path),
2649
3226
  children: [
2650
3227
  page.label,
2651
- /* @__PURE__ */ jsx7("span", { className: "ya-href-page-path", children: page.path })
3228
+ /* @__PURE__ */ jsx8("span", { className: "ya-href-page-path", children: page.path })
2652
3229
  ]
2653
3230
  },
2654
3231
  page.path
2655
3232
  )) })
2656
3233
  ] }),
2657
- /* @__PURE__ */ jsx7(
3234
+ /* @__PURE__ */ jsx8(
2658
3235
  "button",
2659
3236
  {
2660
3237
  type: "button",
@@ -2668,8 +3245,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2668
3245
  )
2669
3246
  ] }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
2670
3247
  /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-section", children: [
2671
- /* @__PURE__ */ jsx7("label", { className: "ya-href-popover-label", children: "External URL" }),
2672
- /* @__PURE__ */ jsx7(
3248
+ /* @__PURE__ */ jsx8("label", { className: "ya-href-popover-label", children: "External URL" }),
3249
+ /* @__PURE__ */ jsx8(
2673
3250
  "input",
2674
3251
  {
2675
3252
  type: "url",
@@ -2681,21 +3258,21 @@ function YaLink({ fieldId, href: defaultHref = "#", className, as: Component = "
2681
3258
  }
2682
3259
  )
2683
3260
  ] }),
2684
- /* @__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" })
2685
3262
  ] }),
2686
3263
  /* @__PURE__ */ jsxs4("div", { className: "ya-href-popover-actions", children: [
2687
- /* @__PURE__ */ jsx7("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
2688
- 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" })
2689
3266
  ] })
2690
3267
  ] })
2691
3268
  ] });
2692
3269
  }
2693
3270
 
2694
3271
  // src/components/StaticText.tsx
2695
- import { jsx as jsx8 } from "react/jsx-runtime";
3272
+ import { jsx as jsx9 } from "react/jsx-runtime";
2696
3273
  function MpText({ fieldId, className, as: Component = "span", children }) {
2697
3274
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
2698
- return /* @__PURE__ */ jsx8(
3275
+ return /* @__PURE__ */ jsx9(
2699
3276
  Component,
2700
3277
  {
2701
3278
  className,
@@ -2706,7 +3283,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
2706
3283
  }
2707
3284
 
2708
3285
  // src/components/StaticImage.tsx
2709
- import { jsx as jsx9 } from "react/jsx-runtime";
3286
+ import { jsx as jsx10 } from "react/jsx-runtime";
2710
3287
  function parseImageValue2(value) {
2711
3288
  if (!value) {
2712
3289
  return { src: "" };
@@ -2742,7 +3319,7 @@ function MpImage({
2742
3319
  const altText = imageData.alt || alt || fallbackAlt || "";
2743
3320
  const objectFit = imageData.objectFit || propObjectFit || "cover";
2744
3321
  const objectPosition = getObjectPosition2(imageData) || propObjectPosition || "50% 50%";
2745
- return /* @__PURE__ */ jsx9(
3322
+ return /* @__PURE__ */ jsx10(
2746
3323
  "img",
2747
3324
  {
2748
3325
  src: resolveAssetUrl(src),
@@ -2760,7 +3337,7 @@ function MpImage({
2760
3337
 
2761
3338
  // src/components/MarkdownText.tsx
2762
3339
  import { Fragment as Fragment4 } from "react";
2763
- import { jsx as jsx10 } from "react/jsx-runtime";
3340
+ import { jsx as jsx11 } from "react/jsx-runtime";
2764
3341
  function tokenize(text) {
2765
3342
  const tokens = [];
2766
3343
  let remaining = text;
@@ -2822,13 +3399,13 @@ function tokensToElements(tokens) {
2822
3399
  return tokens.map((token, index) => {
2823
3400
  switch (token.type) {
2824
3401
  case "text":
2825
- return /* @__PURE__ */ jsx10(Fragment4, { children: token.content }, index);
3402
+ return /* @__PURE__ */ jsx11(Fragment4, { children: token.content }, index);
2826
3403
  case "bold":
2827
- return /* @__PURE__ */ jsx10("strong", { children: token.content }, index);
3404
+ return /* @__PURE__ */ jsx11("strong", { children: token.content }, index);
2828
3405
  case "italic":
2829
- return /* @__PURE__ */ jsx10("em", { children: token.content }, index);
3406
+ return /* @__PURE__ */ jsx11("em", { children: token.content }, index);
2830
3407
  case "link":
2831
- return /* @__PURE__ */ jsx10(
3408
+ return /* @__PURE__ */ jsx11(
2832
3409
  "a",
2833
3410
  {
2834
3411
  href: token.url,
@@ -2840,7 +3417,7 @@ function tokensToElements(tokens) {
2840
3417
  index
2841
3418
  );
2842
3419
  case "newline":
2843
- return /* @__PURE__ */ jsx10("br", {}, index);
3420
+ return /* @__PURE__ */ jsx11("br", {}, index);
2844
3421
  default:
2845
3422
  return null;
2846
3423
  }
@@ -2852,15 +3429,15 @@ function parseMarkdownToElements(content) {
2852
3429
  }
2853
3430
  function MarkdownText({ content, className }) {
2854
3431
  const elements = parseMarkdownToElements(content);
2855
- return /* @__PURE__ */ jsx10("span", { className, children: elements });
3432
+ return /* @__PURE__ */ jsx11("span", { className, children: elements });
2856
3433
  }
2857
3434
 
2858
3435
  // src/router/Link.tsx
2859
3436
  import { Link as WouterLink2 } from "wouter";
2860
- import { jsx as jsx11 } from "react/jsx-runtime";
3437
+ import { jsx as jsx12 } from "react/jsx-runtime";
2861
3438
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
2862
3439
  const target = href ?? to ?? "/";
2863
- return /* @__PURE__ */ jsx11(WouterLink2, { href: target, className, onClick, replace, ...props, children });
3440
+ return /* @__PURE__ */ jsx12(WouterLink2, { href: target, className, onClick, replace, ...props, children });
2864
3441
  }
2865
3442
 
2866
3443
  // src/router/useNavigate.ts
@@ -2879,7 +3456,7 @@ function useNavigate() {
2879
3456
 
2880
3457
  // src/router/Router.tsx
2881
3458
  import { Router as WouterRouter } from "wouter";
2882
- import { jsx as jsx12 } from "react/jsx-runtime";
3459
+ import { jsx as jsx13 } from "react/jsx-runtime";
2883
3460
  function detectBasename() {
2884
3461
  if (typeof window === "undefined") return "";
2885
3462
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -2894,12 +3471,13 @@ function detectBasename() {
2894
3471
  }
2895
3472
  function Router({ children, base }) {
2896
3473
  const basename = base ?? detectBasename();
2897
- return /* @__PURE__ */ jsx12(WouterRouter, { base: basename, children });
3474
+ return /* @__PURE__ */ jsx13(WouterRouter, { base: basename, children });
2898
3475
  }
2899
3476
 
2900
3477
  // src/router/index.ts
2901
3478
  import { Route, Switch } from "wouter";
2902
3479
  export {
3480
+ AIEditProvider,
2903
3481
  ContentStoreProvider,
2904
3482
  ContentStoreProvider2 as ContentStoreProviderProd,
2905
3483
  Link2 as Link,
@@ -2913,15 +3491,28 @@ export {
2913
3491
  YaImage,
2914
3492
  YaLink,
2915
3493
  YaText,
3494
+ buildIntermediateText,
3495
+ calculateAnimationTiming,
3496
+ computeTextDiff,
3497
+ containsHtml,
2916
3498
  contentRegistry,
2917
3499
  getAllContent,
2918
3500
  getContent,
3501
+ getTextCursorPosition,
2919
3502
  hasContent,
3503
+ imageCrossfadeStrategy,
2920
3504
  initBuilderSelection,
3505
+ linkTransitionStrategy,
2921
3506
  registerContent,
2922
3507
  resolveAssetUrl,
2923
3508
  serializeImageValue,
2924
3509
  setAssetResolver,
3510
+ stripHtml,
3511
+ textTypingStrategy,
3512
+ useAIEditAnimation,
3513
+ useAIEditContext,
3514
+ useAIEditContextOptional,
3515
+ useAnimatedText,
2925
3516
  useContentStore,
2926
3517
  useContentStore2 as useContentStoreProd,
2927
3518
  useNavigate