@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.d.ts +390 -1
- package/dist/index.js +737 -146
- package/dist/lib.js +38 -0
- package/package.json +1 -1
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
|
|
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
|
|
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] =
|
|
1477
|
-
const
|
|
1478
|
-
|
|
1479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2085
|
+
useEffect4(() => {
|
|
1521
2086
|
if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
|
|
1522
2087
|
setIsEditing(false);
|
|
1523
2088
|
}
|
|
1524
2089
|
}, [activeFieldId, fieldId, isEditing]);
|
|
1525
|
-
const handleSave =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
2217
|
+
children: /* @__PURE__ */ jsx5(SafeHtml, { content, mode })
|
|
1653
2218
|
}
|
|
1654
2219
|
);
|
|
1655
2220
|
}
|
|
1656
|
-
|
|
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:
|
|
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__ */
|
|
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__ */
|
|
2253
|
+
children: /* @__PURE__ */ jsx5("strong", { children: "B" })
|
|
1683
2254
|
}
|
|
1684
2255
|
),
|
|
1685
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2263
|
+
children: /* @__PURE__ */ jsx5("em", { children: "I" })
|
|
1693
2264
|
}
|
|
1694
2265
|
),
|
|
1695
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2273
|
+
children: /* @__PURE__ */ jsx5("span", { children: "\u{1F517}" })
|
|
1703
2274
|
}
|
|
1704
2275
|
),
|
|
1705
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1715
|
-
Object.entries(SIZE_PRESETS).map(([name, size]) => /* @__PURE__ */
|
|
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__ */
|
|
1728
|
-
Object.entries(WEIGHT_PRESETS).map(([name, weight]) => /* @__PURE__ */
|
|
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__ */
|
|
2309
|
+
/* @__PURE__ */ jsx5(EditorContent, { editor }),
|
|
1739
2310
|
/* @__PURE__ */ jsxs2("div", { className: "ya-text-actions", children: [
|
|
1740
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1760
|
-
|
|
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
|
|
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
|
|
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
|
|
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] =
|
|
1797
|
-
const [coords, setCoords] =
|
|
1798
|
-
const [isPositioned, setIsPositioned] =
|
|
1799
|
-
const tooltipRef =
|
|
1800
|
-
const calculatePosition =
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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
|
|
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 =
|
|
1954
|
-
const imgRef =
|
|
1955
|
-
const [isSelected, setIsSelected] =
|
|
1956
|
-
const [isHovered, setIsHovered] =
|
|
1957
|
-
const [isSmallImage, setIsSmallImage] =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
2093
|
-
/* @__PURE__ */
|
|
2094
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2140
|
-
/* @__PURE__ */
|
|
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
|
|
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
|
|
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] =
|
|
2258
|
-
const [sectionsExpanded, setSectionsExpanded] =
|
|
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] =
|
|
2267
|
-
const [showEditPopover, setShowEditPopover] =
|
|
2268
|
-
const [originalText, setOriginalText] =
|
|
2269
|
-
const [originalHref, setOriginalHref] =
|
|
2270
|
-
const [currentHref, setCurrentHref] =
|
|
2271
|
-
const [isExternalUrl, setIsExternalUrl] =
|
|
2272
|
-
const [externalUrl, setExternalUrl] =
|
|
2273
|
-
const containerRef =
|
|
2274
|
-
const hrefPopoverRef =
|
|
2275
|
-
const hidePopoverTimeoutRef =
|
|
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
|
-
|
|
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
|
-
|
|
2882
|
+
useEffect7(() => {
|
|
2306
2883
|
if (editingMode !== "link") {
|
|
2307
2884
|
setCurrentHref(href);
|
|
2308
2885
|
}
|
|
2309
2886
|
}, [href, editingMode]);
|
|
2310
|
-
|
|
2887
|
+
useEffect7(() => {
|
|
2311
2888
|
return () => {
|
|
2312
2889
|
if (hidePopoverTimeoutRef.current) {
|
|
2313
2890
|
clearTimeout(hidePopoverTimeoutRef.current);
|
|
2314
2891
|
}
|
|
2315
2892
|
};
|
|
2316
2893
|
}, []);
|
|
2317
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2983
|
+
const handleFocus = useCallback8(() => {
|
|
2407
2984
|
if (mode === "inline-edit" && !editingMode) {
|
|
2408
2985
|
setShowEditPopover(true);
|
|
2409
2986
|
}
|
|
2410
2987
|
}, [mode, editingMode]);
|
|
2411
|
-
const startEditText =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3048
|
+
const handlePageSelect = useCallback8((path) => {
|
|
2472
3049
|
setCurrentHref(path);
|
|
2473
3050
|
setIsExternalUrl(false);
|
|
2474
3051
|
}, []);
|
|
2475
|
-
const handleExternalUrlApply =
|
|
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__ */
|
|
3068
|
+
const content = isIconMode ? children : /* @__PURE__ */ jsx8(SafeHtml, { content: text, mode });
|
|
2492
3069
|
if (isInternalPath(href)) {
|
|
2493
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
3127
|
+
children: /* @__PURE__ */ jsx8("strong", { children: "B" })
|
|
2551
3128
|
}
|
|
2552
3129
|
),
|
|
2553
|
-
/* @__PURE__ */
|
|
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__ */
|
|
3137
|
+
children: /* @__PURE__ */ jsx8("em", { children: "I" })
|
|
2561
3138
|
}
|
|
2562
3139
|
),
|
|
2563
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2573
|
-
Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */
|
|
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__ */
|
|
2586
|
-
Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */
|
|
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__ */
|
|
3173
|
+
/* @__PURE__ */ jsx8(EditorContent2, { editor }),
|
|
2597
3174
|
/* @__PURE__ */ jsxs4("div", { className: "ya-link-actions", children: [
|
|
2598
|
-
/* @__PURE__ */
|
|
2599
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2602
|
-
] }) : /* @__PURE__ */
|
|
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__ */
|
|
2607
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2643
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2672
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
2688
|
-
isExternalUrl ? /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
3402
|
+
return /* @__PURE__ */ jsx11(Fragment4, { children: token.content }, index);
|
|
2826
3403
|
case "bold":
|
|
2827
|
-
return /* @__PURE__ */
|
|
3404
|
+
return /* @__PURE__ */ jsx11("strong", { children: token.content }, index);
|
|
2828
3405
|
case "italic":
|
|
2829
|
-
return /* @__PURE__ */
|
|
3406
|
+
return /* @__PURE__ */ jsx11("em", { children: token.content }, index);
|
|
2830
3407
|
case "link":
|
|
2831
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|