@yoamigo.com/core 0.4.8 → 1.0.0
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/cart-storage-DFdGPcwm.d.ts +176 -0
- package/dist/index.d.ts +1198 -39
- package/dist/index.js +2372 -461
- package/dist/lib.d.ts +93 -2
- package/dist/lib.js +337 -4
- package/dist/prod.d.ts +2 -2
- package/dist/prod.js +74 -1
- package/dist/router.d.ts +80 -2
- package/dist/router.js +74 -1
- package/package.json +1 -1
- package/dist/builder-selection-CYP91nRu.d.ts +0 -6
package/dist/index.js
CHANGED
|
@@ -895,7 +895,7 @@ var BuilderSelectionManager = class {
|
|
|
895
895
|
const navLinks = document.querySelectorAll("nav a[href]");
|
|
896
896
|
navLinks.forEach((link) => {
|
|
897
897
|
const href = link.getAttribute("href");
|
|
898
|
-
if (href
|
|
898
|
+
if (href?.startsWith("/")) {
|
|
899
899
|
const path = href.split("?")[0].replace(/\/$/, "") || "/";
|
|
900
900
|
routes.add(path);
|
|
901
901
|
}
|
|
@@ -907,7 +907,7 @@ var BuilderSelectionManager = class {
|
|
|
907
907
|
* Non-blocking: uses requestIdleCallback between pages
|
|
908
908
|
* Transfers ArrayBuffer directly (zero-copy) for performance
|
|
909
909
|
*/
|
|
910
|
-
async captureAllPagesScreenshots(checkpointId,
|
|
910
|
+
async captureAllPagesScreenshots(checkpointId, _viewport) {
|
|
911
911
|
console.log("[BuilderSelection] Starting multi-page capture for checkpoint:", checkpointId);
|
|
912
912
|
const routes = this.getAllRoutes();
|
|
913
913
|
const originalPath = window.location.pathname;
|
|
@@ -923,7 +923,8 @@ var BuilderSelectionManager = class {
|
|
|
923
923
|
try {
|
|
924
924
|
await new Promise((resolve) => {
|
|
925
925
|
if ("requestIdleCallback" in window) {
|
|
926
|
-
|
|
926
|
+
;
|
|
927
|
+
window.requestIdleCallback(() => resolve(), { timeout: 1e3 });
|
|
927
928
|
} else {
|
|
928
929
|
setTimeout(resolve, 50);
|
|
929
930
|
}
|
|
@@ -1098,6 +1099,40 @@ function initBuilderSelection() {
|
|
|
1098
1099
|
}
|
|
1099
1100
|
}
|
|
1100
1101
|
|
|
1102
|
+
// src/lib/collection-context-registry.ts
|
|
1103
|
+
var registry = /* @__PURE__ */ new Map();
|
|
1104
|
+
function registerCollectionContext(prefix, context) {
|
|
1105
|
+
if (registry.has(prefix)) {
|
|
1106
|
+
console.warn(
|
|
1107
|
+
`[collection-registry] Overwriting existing context for prefix "${prefix}". This usually means multiple CollectionContentProviders with the same prefix are mounted.`
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
registry.set(prefix, context);
|
|
1111
|
+
}
|
|
1112
|
+
function unregisterCollectionContext(prefix) {
|
|
1113
|
+
registry.delete(prefix);
|
|
1114
|
+
}
|
|
1115
|
+
function getCollectionContextForField(fieldId) {
|
|
1116
|
+
for (const [prefix, context] of registry) {
|
|
1117
|
+
if (fieldId === prefix || fieldId.startsWith(prefix + ".")) {
|
|
1118
|
+
return context;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
function getAllCollectionFields() {
|
|
1124
|
+
const result = [];
|
|
1125
|
+
for (const [prefix, context] of registry) {
|
|
1126
|
+
result.push({
|
|
1127
|
+
prefix,
|
|
1128
|
+
recordId: context.recordId,
|
|
1129
|
+
collectionSlug: context.collectionSlug,
|
|
1130
|
+
appId: context.appId
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
return result;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1101
1136
|
// src/components/ContentStoreProvider.tsx
|
|
1102
1137
|
import { jsx } from "react/jsx-runtime";
|
|
1103
1138
|
var ContentStoreContext = createContext(null);
|
|
@@ -1292,16 +1327,68 @@ function ContentStoreProvider({
|
|
|
1292
1327
|
useEffect(() => {
|
|
1293
1328
|
modeRef.current = mode;
|
|
1294
1329
|
}, [mode]);
|
|
1330
|
+
const contentRef = useRef(content);
|
|
1331
|
+
useEffect(() => {
|
|
1332
|
+
contentRef.current = content;
|
|
1333
|
+
}, [content]);
|
|
1295
1334
|
useEffect(() => {
|
|
1296
1335
|
;
|
|
1297
1336
|
window.yaContentStore = {
|
|
1298
|
-
getValue:
|
|
1299
|
-
|
|
1300
|
-
|
|
1337
|
+
// getValue: Check collection context first, then static content
|
|
1338
|
+
getValue: (fieldId) => {
|
|
1339
|
+
const collectionCtx = getCollectionContextForField(fieldId);
|
|
1340
|
+
if (collectionCtx) {
|
|
1341
|
+
return collectionCtx.getValue(fieldId);
|
|
1342
|
+
}
|
|
1343
|
+
return getValueRef.current(fieldId);
|
|
1344
|
+
},
|
|
1345
|
+
// setValue: Route to collection context if field belongs to one
|
|
1346
|
+
setValue: (fieldId, value2, source) => {
|
|
1347
|
+
const collectionCtx = getCollectionContextForField(fieldId);
|
|
1348
|
+
if (collectionCtx?.setValue) {
|
|
1349
|
+
collectionCtx.setValue(fieldId, value2, source);
|
|
1350
|
+
collectionCtx.saveToBackend?.(fieldId, value2);
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
setValueRef.current(fieldId, value2, source);
|
|
1354
|
+
},
|
|
1355
|
+
// getChangeSource: Check collection context first
|
|
1356
|
+
getChangeSource: (fieldId) => {
|
|
1357
|
+
return getChangeSourceRef.current(fieldId);
|
|
1358
|
+
},
|
|
1301
1359
|
getMode: () => modeRef.current,
|
|
1302
1360
|
setMode: (mode2) => setModeRef.current(mode2),
|
|
1303
1361
|
subscribe: (listener) => subscribeRef.current(listener),
|
|
1304
|
-
saveToWorker: saveToWorkerRef.current ? (fieldId, value2) => saveToWorkerRef.current?.(fieldId, value2) : void 0
|
|
1362
|
+
saveToWorker: saveToWorkerRef.current ? (fieldId, value2) => saveToWorkerRef.current?.(fieldId, value2) : void 0,
|
|
1363
|
+
// NEW: Get info about a field (is it static or collection?)
|
|
1364
|
+
getFieldInfo: (fieldId) => {
|
|
1365
|
+
const collectionCtx = getCollectionContextForField(fieldId);
|
|
1366
|
+
if (collectionCtx) {
|
|
1367
|
+
return {
|
|
1368
|
+
isCollectionField: true,
|
|
1369
|
+
collectionSlug: collectionCtx.collectionSlug,
|
|
1370
|
+
recordId: collectionCtx.recordId,
|
|
1371
|
+
prefix: collectionCtx.prefix,
|
|
1372
|
+
appId: collectionCtx.appId
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
return {
|
|
1376
|
+
isCollectionField: false,
|
|
1377
|
+
collectionSlug: void 0,
|
|
1378
|
+
recordId: void 0,
|
|
1379
|
+
prefix: void 0,
|
|
1380
|
+
appId: void 0
|
|
1381
|
+
};
|
|
1382
|
+
},
|
|
1383
|
+
// NEW: List all editable fields (for AI discovery)
|
|
1384
|
+
listEditableFields: () => {
|
|
1385
|
+
const staticFields = Array.from(contentRef.current.keys());
|
|
1386
|
+
const collectionFields = getAllCollectionFields();
|
|
1387
|
+
return {
|
|
1388
|
+
static: staticFields,
|
|
1389
|
+
collection: collectionFields
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1305
1392
|
};
|
|
1306
1393
|
return () => {
|
|
1307
1394
|
delete window.yaContentStore;
|
|
@@ -1389,7 +1476,7 @@ function ContentStoreProvider2({ children, initialContent }) {
|
|
|
1389
1476
|
}
|
|
1390
1477
|
|
|
1391
1478
|
// src/components/YaText.tsx
|
|
1392
|
-
import { useEffect as
|
|
1479
|
+
import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback10 } from "react";
|
|
1393
1480
|
import { createPortal as createPortal4 } from "react-dom";
|
|
1394
1481
|
import { useEditor, EditorContent } from "@tiptap/react";
|
|
1395
1482
|
|
|
@@ -1499,11 +1586,322 @@ import Link from "@tiptap/extension-link";
|
|
|
1499
1586
|
import { TextStyle } from "@tiptap/extension-text-style";
|
|
1500
1587
|
import { Extension } from "@tiptap/core";
|
|
1501
1588
|
|
|
1589
|
+
// src/hooks/useContent.ts
|
|
1590
|
+
import { useMemo as useMemo3 } from "react";
|
|
1591
|
+
|
|
1592
|
+
// src/components/CollectionContentProvider.tsx
|
|
1593
|
+
import {
|
|
1594
|
+
createContext as createContext3,
|
|
1595
|
+
useCallback as useCallback3,
|
|
1596
|
+
useContext as useContext3,
|
|
1597
|
+
useEffect as useEffect3,
|
|
1598
|
+
useMemo as useMemo2,
|
|
1599
|
+
useRef as useRef3,
|
|
1600
|
+
useState as useState3
|
|
1601
|
+
} from "react";
|
|
1602
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1603
|
+
var CollectionContentContext = createContext3(null);
|
|
1604
|
+
function useCollectionContent() {
|
|
1605
|
+
return useContext3(CollectionContentContext);
|
|
1606
|
+
}
|
|
1607
|
+
function extractSessionId2() {
|
|
1608
|
+
if (typeof window === "undefined") return null;
|
|
1609
|
+
const match = window.location.pathname.match(/\/session\/([^/]+)/);
|
|
1610
|
+
return match ? match[1] : null;
|
|
1611
|
+
}
|
|
1612
|
+
function isBuilderPreview2() {
|
|
1613
|
+
return typeof window !== "undefined" && (window.__YOAMIGO_EDIT_MODE__ === true || typeof import.meta !== "undefined" && import.meta.env?.YA_EDIT_MODE === "true");
|
|
1614
|
+
}
|
|
1615
|
+
function flattenObject(obj, prefix) {
|
|
1616
|
+
const result = {};
|
|
1617
|
+
function flatten(current, currentPath) {
|
|
1618
|
+
if (current === null || current === void 0) {
|
|
1619
|
+
result[currentPath] = "";
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
if (typeof current === "string") {
|
|
1623
|
+
result[currentPath] = current;
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
if (typeof current === "number" || typeof current === "boolean") {
|
|
1627
|
+
result[currentPath] = String(current);
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (Array.isArray(current)) {
|
|
1631
|
+
result[currentPath] = JSON.stringify(current);
|
|
1632
|
+
current.forEach((item, index) => {
|
|
1633
|
+
flatten(item, `${currentPath}.${index}`);
|
|
1634
|
+
});
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
if (typeof current === "object") {
|
|
1638
|
+
const record = current;
|
|
1639
|
+
if (record.src && typeof record.src === "string") {
|
|
1640
|
+
result[currentPath] = JSON.stringify(current);
|
|
1641
|
+
}
|
|
1642
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1643
|
+
flatten(value, `${currentPath}.${key}`);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1648
|
+
flatten(value, `${prefix}.${key}`);
|
|
1649
|
+
}
|
|
1650
|
+
return result;
|
|
1651
|
+
}
|
|
1652
|
+
function CollectionContentProvider({
|
|
1653
|
+
record,
|
|
1654
|
+
prefix,
|
|
1655
|
+
children,
|
|
1656
|
+
recordId,
|
|
1657
|
+
collectionSlug,
|
|
1658
|
+
appId,
|
|
1659
|
+
// changeType is auto-determined from recordId presence
|
|
1660
|
+
changeType: _changeType = "UPDATE"
|
|
1661
|
+
}) {
|
|
1662
|
+
const isEditable = Boolean(
|
|
1663
|
+
collectionSlug && appId && isBuilderPreview2()
|
|
1664
|
+
);
|
|
1665
|
+
const baseContentMap = useMemo2(() => {
|
|
1666
|
+
return flattenObject(record, prefix);
|
|
1667
|
+
}, [record, prefix]);
|
|
1668
|
+
const [localOverrides, setLocalOverrides] = useState3({});
|
|
1669
|
+
const [changeSourceMap, setChangeSourceMap] = useState3({});
|
|
1670
|
+
const isMountedRef = useRef3(true);
|
|
1671
|
+
useEffect3(() => {
|
|
1672
|
+
isMountedRef.current = true;
|
|
1673
|
+
return () => {
|
|
1674
|
+
isMountedRef.current = false;
|
|
1675
|
+
};
|
|
1676
|
+
}, []);
|
|
1677
|
+
const getValue = useCallback3(
|
|
1678
|
+
(fieldId) => {
|
|
1679
|
+
if (fieldId in localOverrides) {
|
|
1680
|
+
return localOverrides[fieldId];
|
|
1681
|
+
}
|
|
1682
|
+
if (fieldId in baseContentMap) {
|
|
1683
|
+
return baseContentMap[fieldId];
|
|
1684
|
+
}
|
|
1685
|
+
const prefixedFieldId = fieldId.startsWith(prefix + ".") ? fieldId : `${prefix}.${fieldId}`;
|
|
1686
|
+
if (prefixedFieldId in localOverrides) {
|
|
1687
|
+
return localOverrides[prefixedFieldId];
|
|
1688
|
+
}
|
|
1689
|
+
if (prefixedFieldId in baseContentMap) {
|
|
1690
|
+
return baseContentMap[prefixedFieldId];
|
|
1691
|
+
}
|
|
1692
|
+
return "";
|
|
1693
|
+
},
|
|
1694
|
+
[baseContentMap, localOverrides, prefix]
|
|
1695
|
+
);
|
|
1696
|
+
const setValue = useCallback3(
|
|
1697
|
+
(fieldId, value, source = "ai") => {
|
|
1698
|
+
if (!isEditable) {
|
|
1699
|
+
console.warn("[CollectionContentProvider] setValue called but editing is not enabled");
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
setLocalOverrides((prev) => ({ ...prev, [fieldId]: value }));
|
|
1703
|
+
setChangeSourceMap((prev) => ({ ...prev, [fieldId]: source }));
|
|
1704
|
+
},
|
|
1705
|
+
[isEditable]
|
|
1706
|
+
);
|
|
1707
|
+
const getChangeSource = useCallback3(
|
|
1708
|
+
(fieldId) => changeSourceMap[fieldId] || "initial",
|
|
1709
|
+
[changeSourceMap]
|
|
1710
|
+
);
|
|
1711
|
+
const clearChangeSource = useCallback3(
|
|
1712
|
+
(fieldId) => {
|
|
1713
|
+
setChangeSourceMap((prev) => {
|
|
1714
|
+
const next = { ...prev };
|
|
1715
|
+
delete next[fieldId];
|
|
1716
|
+
return next;
|
|
1717
|
+
});
|
|
1718
|
+
},
|
|
1719
|
+
[]
|
|
1720
|
+
);
|
|
1721
|
+
const saveToBackend = useCallback3(
|
|
1722
|
+
async (fieldId, value) => {
|
|
1723
|
+
if (!isEditable) {
|
|
1724
|
+
console.warn("[CollectionContentProvider] saveToBackend called but editing is not enabled");
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const sessionId = extractSessionId2();
|
|
1728
|
+
if (!sessionId) {
|
|
1729
|
+
console.warn("[CollectionContentProvider] saveToBackend: Not in builder preview mode, skipping");
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
try {
|
|
1733
|
+
const response = await fetch(`/api/session/${sessionId}/collection-edit`, {
|
|
1734
|
+
method: "POST",
|
|
1735
|
+
headers: { "Content-Type": "application/json" },
|
|
1736
|
+
credentials: "include",
|
|
1737
|
+
body: JSON.stringify({
|
|
1738
|
+
fieldId,
|
|
1739
|
+
value,
|
|
1740
|
+
recordId,
|
|
1741
|
+
collectionSlug,
|
|
1742
|
+
appId,
|
|
1743
|
+
changeType: recordId ? "UPDATE" : "CREATE"
|
|
1744
|
+
})
|
|
1745
|
+
});
|
|
1746
|
+
if (!response.ok) {
|
|
1747
|
+
const error = await response.json();
|
|
1748
|
+
console.error("[CollectionContentProvider] saveToBackend failed:", error);
|
|
1749
|
+
throw new Error(error.error || "Failed to save collection edit");
|
|
1750
|
+
}
|
|
1751
|
+
console.log(`[CollectionContentProvider] Saved ${fieldId} to staging`);
|
|
1752
|
+
} catch (error) {
|
|
1753
|
+
console.error("[CollectionContentProvider] saveToBackend error:", error);
|
|
1754
|
+
throw error;
|
|
1755
|
+
}
|
|
1756
|
+
},
|
|
1757
|
+
[isEditable, recordId, collectionSlug, appId]
|
|
1758
|
+
);
|
|
1759
|
+
const contextValue = useMemo2(() => ({
|
|
1760
|
+
getValue,
|
|
1761
|
+
setValue: isEditable ? setValue : void 0,
|
|
1762
|
+
saveToBackend: isEditable ? saveToBackend : void 0,
|
|
1763
|
+
getChangeSource: isEditable ? getChangeSource : void 0,
|
|
1764
|
+
clearChangeSource: isEditable ? clearChangeSource : void 0,
|
|
1765
|
+
isCollectionContent: true,
|
|
1766
|
+
prefix,
|
|
1767
|
+
recordId,
|
|
1768
|
+
collectionSlug,
|
|
1769
|
+
appId,
|
|
1770
|
+
isEditable
|
|
1771
|
+
}), [
|
|
1772
|
+
getValue,
|
|
1773
|
+
setValue,
|
|
1774
|
+
saveToBackend,
|
|
1775
|
+
getChangeSource,
|
|
1776
|
+
clearChangeSource,
|
|
1777
|
+
isEditable,
|
|
1778
|
+
prefix,
|
|
1779
|
+
recordId,
|
|
1780
|
+
collectionSlug,
|
|
1781
|
+
appId
|
|
1782
|
+
]);
|
|
1783
|
+
const contextValueRef = useRef3(contextValue);
|
|
1784
|
+
useEffect3(() => {
|
|
1785
|
+
contextValueRef.current = contextValue;
|
|
1786
|
+
}, [contextValue]);
|
|
1787
|
+
useEffect3(() => {
|
|
1788
|
+
if (!isEditable) return;
|
|
1789
|
+
const registryContext = {
|
|
1790
|
+
getValue: (fid) => contextValueRef.current.getValue(fid),
|
|
1791
|
+
setValue: (fid, val, src) => {
|
|
1792
|
+
contextValueRef.current.setValue?.(fid, val, src);
|
|
1793
|
+
},
|
|
1794
|
+
saveToBackend: (fid, val) => {
|
|
1795
|
+
return contextValueRef.current.saveToBackend?.(fid, val) ?? Promise.resolve();
|
|
1796
|
+
},
|
|
1797
|
+
prefix,
|
|
1798
|
+
recordId,
|
|
1799
|
+
collectionSlug,
|
|
1800
|
+
appId
|
|
1801
|
+
};
|
|
1802
|
+
registerCollectionContext(prefix, registryContext);
|
|
1803
|
+
return () => {
|
|
1804
|
+
unregisterCollectionContext(prefix);
|
|
1805
|
+
};
|
|
1806
|
+
}, [isEditable, prefix, recordId, collectionSlug, appId]);
|
|
1807
|
+
return /* @__PURE__ */ jsx4(CollectionContentContext.Provider, { value: contextValue, children });
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
// src/types/fields.ts
|
|
1811
|
+
function parseFieldValue(raw) {
|
|
1812
|
+
if (!raw) {
|
|
1813
|
+
return {};
|
|
1814
|
+
}
|
|
1815
|
+
if (typeof raw === "string") {
|
|
1816
|
+
if (raw.startsWith("{") || raw.startsWith("[")) {
|
|
1817
|
+
try {
|
|
1818
|
+
return JSON.parse(raw);
|
|
1819
|
+
} catch {
|
|
1820
|
+
return raw;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return raw;
|
|
1824
|
+
}
|
|
1825
|
+
return raw;
|
|
1826
|
+
}
|
|
1827
|
+
function stringifyFieldValue(value) {
|
|
1828
|
+
if (typeof value === "string") {
|
|
1829
|
+
return value;
|
|
1830
|
+
}
|
|
1831
|
+
return JSON.stringify(value);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// src/hooks/useContent.ts
|
|
1835
|
+
function useContent(fieldId) {
|
|
1836
|
+
const contentStore = useContentStore();
|
|
1837
|
+
const collectionContext = useCollectionContent();
|
|
1838
|
+
const isInCollection = Boolean(
|
|
1839
|
+
collectionContext?.isEditable && fieldId.startsWith(collectionContext.prefix + ".")
|
|
1840
|
+
);
|
|
1841
|
+
return useMemo3(() => {
|
|
1842
|
+
const getValueFn = () => {
|
|
1843
|
+
return isInCollection ? collectionContext.getValue(fieldId) : contentStore.getValue(fieldId);
|
|
1844
|
+
};
|
|
1845
|
+
const setValueFn = (value, source) => {
|
|
1846
|
+
if (isInCollection && collectionContext.setValue) {
|
|
1847
|
+
collectionContext.setValue(fieldId, value, source);
|
|
1848
|
+
} else {
|
|
1849
|
+
contentStore.setValue(fieldId, value, source);
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
const saveFn = async () => {
|
|
1853
|
+
const value = getValueFn();
|
|
1854
|
+
if (isInCollection && collectionContext.saveToBackend) {
|
|
1855
|
+
await collectionContext.saveToBackend(fieldId, value);
|
|
1856
|
+
} else if (contentStore.saveToWorker) {
|
|
1857
|
+
await contentStore.saveToWorker(fieldId, value);
|
|
1858
|
+
}
|
|
1859
|
+
};
|
|
1860
|
+
const getChangeSourceFn = () => {
|
|
1861
|
+
if (isInCollection) {
|
|
1862
|
+
return collectionContext.getChangeSource?.(fieldId);
|
|
1863
|
+
}
|
|
1864
|
+
return contentStore.getChangeSource?.(fieldId);
|
|
1865
|
+
};
|
|
1866
|
+
const clearChangeSourceFn = () => {
|
|
1867
|
+
if (isInCollection) {
|
|
1868
|
+
collectionContext.clearChangeSource?.(fieldId);
|
|
1869
|
+
} else {
|
|
1870
|
+
contentStore.clearChangeSource?.(fieldId);
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
return {
|
|
1874
|
+
get value() {
|
|
1875
|
+
const raw = getValueFn();
|
|
1876
|
+
return parseFieldValue(raw);
|
|
1877
|
+
},
|
|
1878
|
+
get() {
|
|
1879
|
+
return getValueFn();
|
|
1880
|
+
},
|
|
1881
|
+
set(value, source) {
|
|
1882
|
+
const stringValue = typeof value === "string" ? value : stringifyFieldValue(value);
|
|
1883
|
+
setValueFn(stringValue, source);
|
|
1884
|
+
},
|
|
1885
|
+
async save() {
|
|
1886
|
+
await saveFn();
|
|
1887
|
+
},
|
|
1888
|
+
get changeSource() {
|
|
1889
|
+
return getChangeSourceFn();
|
|
1890
|
+
},
|
|
1891
|
+
clearChangeSource() {
|
|
1892
|
+
clearChangeSourceFn();
|
|
1893
|
+
},
|
|
1894
|
+
mode: contentStore.mode,
|
|
1895
|
+
isCollectionField: isInCollection
|
|
1896
|
+
};
|
|
1897
|
+
}, [fieldId, isInCollection, collectionContext, contentStore]);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1502
1900
|
// src/components/SafeHtml.tsx
|
|
1503
|
-
import { useEffect as
|
|
1901
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState4, useCallback as useCallback4 } from "react";
|
|
1504
1902
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1505
1903
|
import DOMPurify from "dompurify";
|
|
1506
|
-
import { Fragment, jsx as
|
|
1904
|
+
import { Fragment, jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
1507
1905
|
var ALLOWED_TAGS = ["strong", "em", "a", "span", "br", "b", "i", "u"];
|
|
1508
1906
|
var ALLOWED_ATTR = ["href", "style", "class", "target", "rel"];
|
|
1509
1907
|
if (typeof window !== "undefined") {
|
|
@@ -1561,8 +1959,8 @@ function LinkIcon() {
|
|
|
1561
1959
|
strokeLinecap: "round",
|
|
1562
1960
|
strokeLinejoin: "round",
|
|
1563
1961
|
children: [
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1962
|
+
/* @__PURE__ */ jsx5("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
1963
|
+
/* @__PURE__ */ jsx5("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
1566
1964
|
]
|
|
1567
1965
|
}
|
|
1568
1966
|
);
|
|
@@ -1594,20 +1992,20 @@ function LinkPopover({
|
|
|
1594
1992
|
}
|
|
1595
1993
|
},
|
|
1596
1994
|
children: [
|
|
1597
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsx5(LinkIcon, {}),
|
|
1598
1996
|
/* @__PURE__ */ jsxs("span", { className: "ya-link-popover-text", children: [
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1997
|
+
/* @__PURE__ */ jsx5("span", { className: "ya-link-popover-prefix", children: "Go to " }),
|
|
1998
|
+
/* @__PURE__ */ jsx5("span", { className: "ya-link-popover-name", children: displayText })
|
|
1601
1999
|
] })
|
|
1602
2000
|
]
|
|
1603
2001
|
}
|
|
1604
2002
|
);
|
|
1605
2003
|
}
|
|
1606
2004
|
function SafeHtml({ content, className, mode = "read-only" }) {
|
|
1607
|
-
const containerRef =
|
|
1608
|
-
const showTimerRef =
|
|
1609
|
-
const hideTimerRef =
|
|
1610
|
-
const [popoverState, setPopoverState] =
|
|
2005
|
+
const containerRef = useRef4(null);
|
|
2006
|
+
const showTimerRef = useRef4(void 0);
|
|
2007
|
+
const hideTimerRef = useRef4(void 0);
|
|
2008
|
+
const [popoverState, setPopoverState] = useState4({
|
|
1611
2009
|
isVisible: false,
|
|
1612
2010
|
href: "",
|
|
1613
2011
|
displayText: "",
|
|
@@ -1618,20 +2016,20 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1618
2016
|
ALLOWED_TAGS,
|
|
1619
2017
|
ALLOWED_ATTR
|
|
1620
2018
|
});
|
|
1621
|
-
const hidePopover =
|
|
2019
|
+
const hidePopover = useCallback4(() => {
|
|
1622
2020
|
clearTimeout(showTimerRef.current);
|
|
1623
2021
|
setPopoverState((prev) => ({ ...prev, isVisible: false }));
|
|
1624
2022
|
}, []);
|
|
1625
|
-
const scheduleHide =
|
|
2023
|
+
const scheduleHide = useCallback4(() => {
|
|
1626
2024
|
clearTimeout(showTimerRef.current);
|
|
1627
2025
|
hideTimerRef.current = window.setTimeout(() => {
|
|
1628
2026
|
hidePopover();
|
|
1629
2027
|
}, 100);
|
|
1630
2028
|
}, [hidePopover]);
|
|
1631
|
-
const cancelHide =
|
|
2029
|
+
const cancelHide = useCallback4(() => {
|
|
1632
2030
|
clearTimeout(hideTimerRef.current);
|
|
1633
2031
|
}, []);
|
|
1634
|
-
const handlePopoverClick =
|
|
2032
|
+
const handlePopoverClick = useCallback4(() => {
|
|
1635
2033
|
if (popoverState.isExternal) {
|
|
1636
2034
|
window.open(popoverState.href, "_blank", "noopener,noreferrer");
|
|
1637
2035
|
} else {
|
|
@@ -1639,7 +2037,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1639
2037
|
}
|
|
1640
2038
|
hidePopover();
|
|
1641
2039
|
}, [popoverState.href, popoverState.isExternal, hidePopover]);
|
|
1642
|
-
|
|
2040
|
+
useEffect4(() => {
|
|
1643
2041
|
if (mode !== "inline-edit" || !containerRef.current) return;
|
|
1644
2042
|
const container = containerRef.current;
|
|
1645
2043
|
const handleMouseOver = (e) => {
|
|
@@ -1697,7 +2095,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1697
2095
|
};
|
|
1698
2096
|
}, [mode, scheduleHide]);
|
|
1699
2097
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1700
|
-
/* @__PURE__ */
|
|
2098
|
+
/* @__PURE__ */ jsx5(
|
|
1701
2099
|
"span",
|
|
1702
2100
|
{
|
|
1703
2101
|
ref: containerRef,
|
|
@@ -1706,7 +2104,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1706
2104
|
}
|
|
1707
2105
|
),
|
|
1708
2106
|
mode === "inline-edit" && popoverState.isVisible && createPortal2(
|
|
1709
|
-
/* @__PURE__ */
|
|
2107
|
+
/* @__PURE__ */ jsx5(
|
|
1710
2108
|
LinkPopover,
|
|
1711
2109
|
{
|
|
1712
2110
|
displayText: popoverState.displayText,
|
|
@@ -1722,37 +2120,37 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1722
2120
|
}
|
|
1723
2121
|
|
|
1724
2122
|
// src/hooks/useAnimatedText.ts
|
|
1725
|
-
import { useMemo as
|
|
2123
|
+
import { useMemo as useMemo6 } from "react";
|
|
1726
2124
|
|
|
1727
2125
|
// src/hooks/useAIEditAnimation.ts
|
|
1728
|
-
import { useState as
|
|
2126
|
+
import { useState as useState5, useEffect as useEffect5, useRef as useRef6, useCallback as useCallback6, useMemo as useMemo5 } from "react";
|
|
1729
2127
|
|
|
1730
2128
|
// src/contexts/AIEditContext.tsx
|
|
1731
|
-
import { createContext as
|
|
1732
|
-
import { jsx as
|
|
1733
|
-
var AIEditContext =
|
|
2129
|
+
import { createContext as createContext4, useContext as useContext4, useCallback as useCallback5, useRef as useRef5, useMemo as useMemo4 } from "react";
|
|
2130
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2131
|
+
var AIEditContext = createContext4(null);
|
|
1734
2132
|
function useAIEditContext() {
|
|
1735
|
-
const context =
|
|
2133
|
+
const context = useContext4(AIEditContext);
|
|
1736
2134
|
if (!context) {
|
|
1737
2135
|
throw new Error("useAIEditContext must be used within an AIEditProvider");
|
|
1738
2136
|
}
|
|
1739
2137
|
return context;
|
|
1740
2138
|
}
|
|
1741
2139
|
function useAIEditContextOptional() {
|
|
1742
|
-
return
|
|
2140
|
+
return useContext4(AIEditContext);
|
|
1743
2141
|
}
|
|
1744
2142
|
function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
1745
|
-
const animationsRef =
|
|
1746
|
-
const listenersRef =
|
|
1747
|
-
const queueRef =
|
|
1748
|
-
const processingRef =
|
|
1749
|
-
const notifyListeners =
|
|
2143
|
+
const animationsRef = useRef5(/* @__PURE__ */ new Map());
|
|
2144
|
+
const listenersRef = useRef5(/* @__PURE__ */ new Map());
|
|
2145
|
+
const queueRef = useRef5([]);
|
|
2146
|
+
const processingRef = useRef5(false);
|
|
2147
|
+
const notifyListeners = useCallback5((fieldId) => {
|
|
1750
2148
|
const listeners = listenersRef.current.get(fieldId);
|
|
1751
2149
|
if (listeners) {
|
|
1752
2150
|
listeners.forEach((listener) => listener());
|
|
1753
2151
|
}
|
|
1754
2152
|
}, []);
|
|
1755
|
-
const processQueue =
|
|
2153
|
+
const processQueue = useCallback5(() => {
|
|
1756
2154
|
if (processingRef.current || queueRef.current.length === 0) return;
|
|
1757
2155
|
processingRef.current = true;
|
|
1758
2156
|
const fieldId = queueRef.current.shift();
|
|
@@ -1767,7 +2165,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1767
2165
|
processQueue();
|
|
1768
2166
|
}, staggerDelay);
|
|
1769
2167
|
}, [staggerDelay, notifyListeners]);
|
|
1770
|
-
const queueAnimation =
|
|
2168
|
+
const queueAnimation = useCallback5(
|
|
1771
2169
|
(fieldId, config) => {
|
|
1772
2170
|
const existing = animationsRef.current.get(fieldId);
|
|
1773
2171
|
if (existing?.status === "animating") {
|
|
@@ -1790,7 +2188,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1790
2188
|
},
|
|
1791
2189
|
[notifyListeners, processQueue]
|
|
1792
2190
|
);
|
|
1793
|
-
const cancelAnimation =
|
|
2191
|
+
const cancelAnimation = useCallback5(
|
|
1794
2192
|
(fieldId) => {
|
|
1795
2193
|
const state = animationsRef.current.get(fieldId);
|
|
1796
2194
|
if (state) {
|
|
@@ -1804,14 +2202,14 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1804
2202
|
},
|
|
1805
2203
|
[notifyListeners]
|
|
1806
2204
|
);
|
|
1807
|
-
const isAnimating =
|
|
2205
|
+
const isAnimating = useCallback5((fieldId) => {
|
|
1808
2206
|
const state = animationsRef.current.get(fieldId);
|
|
1809
2207
|
return state?.status === "animating" || state?.status === "pending";
|
|
1810
2208
|
}, []);
|
|
1811
|
-
const getAnimationState =
|
|
2209
|
+
const getAnimationState = useCallback5((fieldId) => {
|
|
1812
2210
|
return animationsRef.current.get(fieldId);
|
|
1813
2211
|
}, []);
|
|
1814
|
-
const subscribe =
|
|
2212
|
+
const subscribe = useCallback5((fieldId, listener) => {
|
|
1815
2213
|
let listeners = listenersRef.current.get(fieldId);
|
|
1816
2214
|
if (!listeners) {
|
|
1817
2215
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -1825,7 +2223,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1825
2223
|
}
|
|
1826
2224
|
};
|
|
1827
2225
|
}, []);
|
|
1828
|
-
const completeAnimation =
|
|
2226
|
+
const completeAnimation = useCallback5(
|
|
1829
2227
|
(fieldId) => {
|
|
1830
2228
|
const state = animationsRef.current.get(fieldId);
|
|
1831
2229
|
if (state) {
|
|
@@ -1840,7 +2238,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1840
2238
|
},
|
|
1841
2239
|
[notifyListeners]
|
|
1842
2240
|
);
|
|
1843
|
-
const value =
|
|
2241
|
+
const value = useMemo4(
|
|
1844
2242
|
() => ({
|
|
1845
2243
|
queueAnimation,
|
|
1846
2244
|
cancelAnimation,
|
|
@@ -1851,7 +2249,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1851
2249
|
}),
|
|
1852
2250
|
[queueAnimation, cancelAnimation, isAnimating, getAnimationState, subscribe, completeAnimation]
|
|
1853
2251
|
);
|
|
1854
|
-
return /* @__PURE__ */
|
|
2252
|
+
return /* @__PURE__ */ jsx6(AIEditContext.Provider, { value, children });
|
|
1855
2253
|
}
|
|
1856
2254
|
|
|
1857
2255
|
// src/hooks/useAIEditAnimation.ts
|
|
@@ -1859,15 +2257,15 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1859
2257
|
const { enabled = true, strategy, maxDuration = 2e3, onStart, onComplete } = options;
|
|
1860
2258
|
const context = useAIEditContextOptional();
|
|
1861
2259
|
const { getChangeSource, clearChangeSource } = useContentStore();
|
|
1862
|
-
const previousValueRef =
|
|
1863
|
-
const isFirstRender =
|
|
1864
|
-
const [phase, setPhase] =
|
|
1865
|
-
const [progress, setProgress] =
|
|
1866
|
-
const [displayValue, setDisplayValue] =
|
|
1867
|
-
const metadataRef =
|
|
1868
|
-
const animationFrameRef =
|
|
1869
|
-
const startTimeRef =
|
|
1870
|
-
const cancel =
|
|
2260
|
+
const previousValueRef = useRef6(value);
|
|
2261
|
+
const isFirstRender = useRef6(true);
|
|
2262
|
+
const [phase, setPhase] = useState5("idle");
|
|
2263
|
+
const [progress, setProgress] = useState5(0);
|
|
2264
|
+
const [displayValue, setDisplayValue] = useState5(value);
|
|
2265
|
+
const metadataRef = useRef6(null);
|
|
2266
|
+
const animationFrameRef = useRef6(null);
|
|
2267
|
+
const startTimeRef = useRef6(0);
|
|
2268
|
+
const cancel = useCallback6(() => {
|
|
1871
2269
|
if (animationFrameRef.current !== null) {
|
|
1872
2270
|
cancelAnimationFrame(animationFrameRef.current);
|
|
1873
2271
|
animationFrameRef.current = null;
|
|
@@ -1878,7 +2276,7 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1878
2276
|
metadataRef.current = null;
|
|
1879
2277
|
context?.cancelAnimation(fieldId);
|
|
1880
2278
|
}, [value, context, fieldId]);
|
|
1881
|
-
const runAnimation =
|
|
2279
|
+
const runAnimation = useCallback6(() => {
|
|
1882
2280
|
if (!metadataRef.current) return;
|
|
1883
2281
|
const metadata = metadataRef.current;
|
|
1884
2282
|
const elapsed = performance.now() - startTimeRef.current;
|
|
@@ -1903,7 +2301,7 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1903
2301
|
setDisplayValue(interpolatedValue);
|
|
1904
2302
|
animationFrameRef.current = requestAnimationFrame(runAnimation);
|
|
1905
2303
|
}, [strategy, maxDuration, context, fieldId, onComplete, clearChangeSource]);
|
|
1906
|
-
|
|
2304
|
+
useEffect5(() => {
|
|
1907
2305
|
if (isFirstRender.current) {
|
|
1908
2306
|
isFirstRender.current = false;
|
|
1909
2307
|
previousValueRef.current = value;
|
|
@@ -1957,14 +2355,14 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1957
2355
|
}
|
|
1958
2356
|
};
|
|
1959
2357
|
}, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation, getChangeSource, clearChangeSource]);
|
|
1960
|
-
|
|
2358
|
+
useEffect5(() => {
|
|
1961
2359
|
return () => {
|
|
1962
2360
|
if (animationFrameRef.current !== null) {
|
|
1963
2361
|
cancelAnimationFrame(animationFrameRef.current);
|
|
1964
2362
|
}
|
|
1965
2363
|
};
|
|
1966
2364
|
}, []);
|
|
1967
|
-
const wrapperProps =
|
|
2365
|
+
const wrapperProps = useMemo5(
|
|
1968
2366
|
() => ({
|
|
1969
2367
|
className: phase === "animating" ? "ya-ai-editing" : phase === "complete" ? "ya-ai-complete" : "",
|
|
1970
2368
|
"data-ai-editing": phase === "animating"
|
|
@@ -2186,7 +2584,7 @@ function useAnimatedText(fieldId, content, options = {}) {
|
|
|
2186
2584
|
onStart,
|
|
2187
2585
|
onComplete
|
|
2188
2586
|
} = options;
|
|
2189
|
-
const customStrategy =
|
|
2587
|
+
const customStrategy = useMemo6(() => {
|
|
2190
2588
|
if (charDelay === 50) {
|
|
2191
2589
|
return textTypingStrategy;
|
|
2192
2590
|
}
|
|
@@ -2225,7 +2623,7 @@ function useAnimatedText(fieldId, content, options = {}) {
|
|
|
2225
2623
|
onStart,
|
|
2226
2624
|
onComplete
|
|
2227
2625
|
});
|
|
2228
|
-
const cursorPosition =
|
|
2626
|
+
const cursorPosition = useMemo6(() => {
|
|
2229
2627
|
if (!isAnimating) return null;
|
|
2230
2628
|
const diff = computeTextDiff(content, displayValue);
|
|
2231
2629
|
const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
|
|
@@ -2256,7 +2654,7 @@ function useAnimatedText(fieldId, content, options = {}) {
|
|
|
2256
2654
|
}
|
|
2257
2655
|
|
|
2258
2656
|
// src/components/BubbleIcons.tsx
|
|
2259
|
-
import { jsx as
|
|
2657
|
+
import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2260
2658
|
function BoldIcon({ size = 16, className }) {
|
|
2261
2659
|
return /* @__PURE__ */ jsxs2(
|
|
2262
2660
|
"svg",
|
|
@@ -2271,8 +2669,8 @@ function BoldIcon({ size = 16, className }) {
|
|
|
2271
2669
|
strokeLinejoin: "round",
|
|
2272
2670
|
className,
|
|
2273
2671
|
children: [
|
|
2274
|
-
/* @__PURE__ */
|
|
2275
|
-
/* @__PURE__ */
|
|
2672
|
+
/* @__PURE__ */ jsx7("path", { d: "M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" }),
|
|
2673
|
+
/* @__PURE__ */ jsx7("path", { d: "M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" })
|
|
2276
2674
|
]
|
|
2277
2675
|
}
|
|
2278
2676
|
);
|
|
@@ -2291,9 +2689,9 @@ function ItalicIcon({ size = 16, className }) {
|
|
|
2291
2689
|
strokeLinejoin: "round",
|
|
2292
2690
|
className,
|
|
2293
2691
|
children: [
|
|
2294
|
-
/* @__PURE__ */
|
|
2295
|
-
/* @__PURE__ */
|
|
2296
|
-
/* @__PURE__ */
|
|
2692
|
+
/* @__PURE__ */ jsx7("line", { x1: "19", y1: "4", x2: "10", y2: "4" }),
|
|
2693
|
+
/* @__PURE__ */ jsx7("line", { x1: "14", y1: "20", x2: "5", y2: "20" }),
|
|
2694
|
+
/* @__PURE__ */ jsx7("line", { x1: "15", y1: "4", x2: "9", y2: "20" })
|
|
2297
2695
|
]
|
|
2298
2696
|
}
|
|
2299
2697
|
);
|
|
@@ -2312,14 +2710,14 @@ function LinkIcon2({ size = 16, className }) {
|
|
|
2312
2710
|
strokeLinejoin: "round",
|
|
2313
2711
|
className,
|
|
2314
2712
|
children: [
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
/* @__PURE__ */
|
|
2713
|
+
/* @__PURE__ */ jsx7("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
2714
|
+
/* @__PURE__ */ jsx7("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
2317
2715
|
]
|
|
2318
2716
|
}
|
|
2319
2717
|
);
|
|
2320
2718
|
}
|
|
2321
2719
|
function ChevronDownIcon({ size = 12, className }) {
|
|
2322
|
-
return /* @__PURE__ */
|
|
2720
|
+
return /* @__PURE__ */ jsx7(
|
|
2323
2721
|
"svg",
|
|
2324
2722
|
{
|
|
2325
2723
|
width: size,
|
|
@@ -2331,15 +2729,15 @@ function ChevronDownIcon({ size = 12, className }) {
|
|
|
2331
2729
|
strokeLinecap: "round",
|
|
2332
2730
|
strokeLinejoin: "round",
|
|
2333
2731
|
className,
|
|
2334
|
-
children: /* @__PURE__ */
|
|
2732
|
+
children: /* @__PURE__ */ jsx7("polyline", { points: "6 9 12 15 18 9" })
|
|
2335
2733
|
}
|
|
2336
2734
|
);
|
|
2337
2735
|
}
|
|
2338
2736
|
|
|
2339
2737
|
// src/components/BubbleDropdown.tsx
|
|
2340
|
-
import { useEffect as
|
|
2738
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useState as useState6, useRef as useRef7, useCallback as useCallback7 } from "react";
|
|
2341
2739
|
import { createPortal as createPortal3 } from "react-dom";
|
|
2342
|
-
import { Fragment as Fragment2, jsx as
|
|
2740
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2343
2741
|
function BubbleDropdown({
|
|
2344
2742
|
label,
|
|
2345
2743
|
open,
|
|
@@ -2348,14 +2746,14 @@ function BubbleDropdown({
|
|
|
2348
2746
|
triggerClassName = "",
|
|
2349
2747
|
panelClassName = ""
|
|
2350
2748
|
}) {
|
|
2351
|
-
const triggerRef =
|
|
2352
|
-
const panelRef =
|
|
2353
|
-
const [position, setPosition] =
|
|
2354
|
-
const [isMounted, setIsMounted] =
|
|
2355
|
-
|
|
2749
|
+
const triggerRef = useRef7(null);
|
|
2750
|
+
const panelRef = useRef7(null);
|
|
2751
|
+
const [position, setPosition] = useState6(null);
|
|
2752
|
+
const [isMounted, setIsMounted] = useState6(false);
|
|
2753
|
+
useEffect6(() => {
|
|
2356
2754
|
setIsMounted(true);
|
|
2357
2755
|
}, []);
|
|
2358
|
-
const calculatePosition =
|
|
2756
|
+
const calculatePosition = useCallback7(() => {
|
|
2359
2757
|
if (!triggerRef.current) return null;
|
|
2360
2758
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
2361
2759
|
const gap = 4;
|
|
@@ -2371,7 +2769,7 @@ function BubbleDropdown({
|
|
|
2371
2769
|
}
|
|
2372
2770
|
return { top, left, adjusted: false };
|
|
2373
2771
|
}, []);
|
|
2374
|
-
|
|
2772
|
+
useEffect6(() => {
|
|
2375
2773
|
if (open) {
|
|
2376
2774
|
const pos = calculatePosition();
|
|
2377
2775
|
setPosition(pos);
|
|
@@ -2400,7 +2798,7 @@ function BubbleDropdown({
|
|
|
2400
2798
|
setPosition((prev) => prev ? { ...prev, adjusted: true } : null);
|
|
2401
2799
|
}
|
|
2402
2800
|
}, [open, position]);
|
|
2403
|
-
|
|
2801
|
+
useEffect6(() => {
|
|
2404
2802
|
if (!open) return;
|
|
2405
2803
|
const handleClickOutside = (e) => {
|
|
2406
2804
|
if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) {
|
|
@@ -2453,13 +2851,13 @@ function BubbleDropdown({
|
|
|
2453
2851
|
onClick: handleTriggerClick,
|
|
2454
2852
|
onMouseDown: handleTriggerMouseDown,
|
|
2455
2853
|
children: [
|
|
2456
|
-
/* @__PURE__ */
|
|
2457
|
-
/* @__PURE__ */
|
|
2854
|
+
/* @__PURE__ */ jsx8("span", { className: "ya-bubble-dropdown-label", children: label }),
|
|
2855
|
+
/* @__PURE__ */ jsx8(ChevronDownIcon, { size: 10, className: `ya-bubble-dropdown-arrow ${open ? "is-open" : ""}` })
|
|
2458
2856
|
]
|
|
2459
2857
|
}
|
|
2460
2858
|
),
|
|
2461
2859
|
isMounted && open && position && createPortal3(
|
|
2462
|
-
/* @__PURE__ */
|
|
2860
|
+
/* @__PURE__ */ jsx8(
|
|
2463
2861
|
"div",
|
|
2464
2862
|
{
|
|
2465
2863
|
ref: panelRef,
|
|
@@ -2475,8 +2873,8 @@ function BubbleDropdown({
|
|
|
2475
2873
|
}
|
|
2476
2874
|
|
|
2477
2875
|
// src/components/FontSizePicker.tsx
|
|
2478
|
-
import { useState as
|
|
2479
|
-
import { jsx as
|
|
2876
|
+
import { useState as useState7, useEffect as useEffect7, useCallback as useCallback8, useRef as useRef8 } from "react";
|
|
2877
|
+
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2480
2878
|
var SIZE_PRESETS = [
|
|
2481
2879
|
{ name: "S", value: "0.875rem" },
|
|
2482
2880
|
{ name: "M", value: "1rem" },
|
|
@@ -2533,28 +2931,28 @@ function normalizeValue(input) {
|
|
|
2533
2931
|
return `${num}${unit}`;
|
|
2534
2932
|
}
|
|
2535
2933
|
function FontSizePicker({ value, onChange, onClose }) {
|
|
2536
|
-
const [inputValue, setInputValue] =
|
|
2537
|
-
const inputRef =
|
|
2538
|
-
|
|
2934
|
+
const [inputValue, setInputValue] = useState7(value || "");
|
|
2935
|
+
const inputRef = useRef8(null);
|
|
2936
|
+
useEffect7(() => {
|
|
2539
2937
|
inputRef.current?.focus();
|
|
2540
2938
|
inputRef.current?.select();
|
|
2541
2939
|
}, []);
|
|
2542
|
-
|
|
2940
|
+
useEffect7(() => {
|
|
2543
2941
|
setInputValue(value || "");
|
|
2544
2942
|
}, [value]);
|
|
2545
|
-
const handlePresetClick =
|
|
2943
|
+
const handlePresetClick = useCallback8((e, presetValue) => {
|
|
2546
2944
|
e.stopPropagation();
|
|
2547
2945
|
onChange(presetValue);
|
|
2548
2946
|
onClose();
|
|
2549
2947
|
}, [onChange, onClose]);
|
|
2550
|
-
const handlePresetMouseDown =
|
|
2948
|
+
const handlePresetMouseDown = useCallback8((e) => {
|
|
2551
2949
|
e.preventDefault();
|
|
2552
2950
|
e.stopPropagation();
|
|
2553
2951
|
}, []);
|
|
2554
|
-
const handleInputChange =
|
|
2952
|
+
const handleInputChange = useCallback8((e) => {
|
|
2555
2953
|
setInputValue(e.target.value);
|
|
2556
2954
|
}, []);
|
|
2557
|
-
const handleInputKeyDown =
|
|
2955
|
+
const handleInputKeyDown = useCallback8((e) => {
|
|
2558
2956
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
2559
2957
|
e.preventDefault();
|
|
2560
2958
|
e.stopPropagation();
|
|
@@ -2596,7 +2994,7 @@ function FontSizePicker({ value, onChange, onClose }) {
|
|
|
2596
2994
|
}, [inputValue, value, onChange, onClose]);
|
|
2597
2995
|
const activePreset = getPresetName(value);
|
|
2598
2996
|
return /* @__PURE__ */ jsxs4("div", { className: "ya-font-size-picker", children: [
|
|
2599
|
-
/* @__PURE__ */
|
|
2997
|
+
/* @__PURE__ */ jsx9("div", { className: "ya-size-presets", children: SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs4(
|
|
2600
2998
|
"button",
|
|
2601
2999
|
{
|
|
2602
3000
|
type: "button",
|
|
@@ -2604,13 +3002,13 @@ function FontSizePicker({ value, onChange, onClose }) {
|
|
|
2604
3002
|
onClick: (e) => handlePresetClick(e, preset.value),
|
|
2605
3003
|
onMouseDown: handlePresetMouseDown,
|
|
2606
3004
|
children: [
|
|
2607
|
-
/* @__PURE__ */
|
|
2608
|
-
/* @__PURE__ */
|
|
3005
|
+
/* @__PURE__ */ jsx9("span", { className: "ya-size-preset-name", children: preset.name }),
|
|
3006
|
+
/* @__PURE__ */ jsx9("span", { className: "ya-size-preset-value", children: preset.value })
|
|
2609
3007
|
]
|
|
2610
3008
|
},
|
|
2611
3009
|
preset.name
|
|
2612
3010
|
)) }),
|
|
2613
|
-
/* @__PURE__ */
|
|
3011
|
+
/* @__PURE__ */ jsx9("div", { className: "ya-size-combobox", children: /* @__PURE__ */ jsx9(
|
|
2614
3012
|
"input",
|
|
2615
3013
|
{
|
|
2616
3014
|
ref: inputRef,
|
|
@@ -2630,8 +3028,8 @@ function FontSizePicker({ value, onChange, onClose }) {
|
|
|
2630
3028
|
}
|
|
2631
3029
|
|
|
2632
3030
|
// src/components/FontWeightPicker.tsx
|
|
2633
|
-
import { useCallback as
|
|
2634
|
-
import { jsx as
|
|
3031
|
+
import { useCallback as useCallback9 } from "react";
|
|
3032
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2635
3033
|
var WEIGHT_PRESETS = [
|
|
2636
3034
|
{ name: "Regular", value: "400" },
|
|
2637
3035
|
{ name: "Semi-bold", value: "600" },
|
|
@@ -2645,16 +3043,16 @@ function getFontWeightLabel(value) {
|
|
|
2645
3043
|
return value;
|
|
2646
3044
|
}
|
|
2647
3045
|
function FontWeightPicker({ value, onChange, onClose }) {
|
|
2648
|
-
const handleClick =
|
|
3046
|
+
const handleClick = useCallback9((e, weightValue) => {
|
|
2649
3047
|
e.stopPropagation();
|
|
2650
3048
|
onChange(weightValue);
|
|
2651
3049
|
onClose();
|
|
2652
3050
|
}, [onChange, onClose]);
|
|
2653
|
-
const handleMouseDown =
|
|
3051
|
+
const handleMouseDown = useCallback9((e) => {
|
|
2654
3052
|
e.preventDefault();
|
|
2655
3053
|
e.stopPropagation();
|
|
2656
3054
|
}, []);
|
|
2657
|
-
return /* @__PURE__ */
|
|
3055
|
+
return /* @__PURE__ */ jsx10("div", { className: "ya-font-weight-picker", children: WEIGHT_PRESETS.map((preset) => /* @__PURE__ */ jsx10(
|
|
2658
3056
|
"button",
|
|
2659
3057
|
{
|
|
2660
3058
|
type: "button",
|
|
@@ -3017,7 +3415,7 @@ body.builder-selector-active .ya-text-editable:not(.ya-text-editing) *::-moz-sel
|
|
|
3017
3415
|
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');
|
|
3018
3416
|
|
|
3019
3417
|
// src/components/YaText.tsx
|
|
3020
|
-
import { Fragment as Fragment3, jsx as
|
|
3418
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3021
3419
|
var FontSize = Extension.create({
|
|
3022
3420
|
name: "fontSize",
|
|
3023
3421
|
addOptions() {
|
|
@@ -3097,13 +3495,15 @@ var FontWeight = Extension.create({
|
|
|
3097
3495
|
}
|
|
3098
3496
|
});
|
|
3099
3497
|
function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
3100
|
-
const
|
|
3101
|
-
const
|
|
3498
|
+
const contentHandle = useContent(fieldId);
|
|
3499
|
+
const { mode } = contentHandle;
|
|
3500
|
+
const { activeFieldId, setActiveField } = useContentStore();
|
|
3501
|
+
const storeContent = contentHandle.get();
|
|
3102
3502
|
const content = storeContent || (typeof children === "string" ? children : "");
|
|
3103
|
-
const [isEditing, setIsEditing] =
|
|
3104
|
-
const [showBubbleMenu, setShowBubbleMenu] =
|
|
3105
|
-
const [fontSizeOpen, setFontSizeOpen] =
|
|
3106
|
-
const [fontWeightOpen, setFontWeightOpen] =
|
|
3503
|
+
const [isEditing, setIsEditing] = useState8(false);
|
|
3504
|
+
const [showBubbleMenu, setShowBubbleMenu] = useState8(false);
|
|
3505
|
+
const [fontSizeOpen, setFontSizeOpen] = useState8(false);
|
|
3506
|
+
const [fontWeightOpen, setFontWeightOpen] = useState8(false);
|
|
3107
3507
|
const {
|
|
3108
3508
|
displayContent,
|
|
3109
3509
|
isAnimating,
|
|
@@ -3111,16 +3511,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3111
3511
|
} = useAnimatedText(fieldId, content, {
|
|
3112
3512
|
enabled: mode === "inline-edit" && !isEditing
|
|
3113
3513
|
});
|
|
3114
|
-
const [originalContent, setOriginalContent] =
|
|
3115
|
-
const containerRef =
|
|
3116
|
-
const originalContentRef =
|
|
3117
|
-
const originalHadLineBreaksRef =
|
|
3118
|
-
const [actionButtonsPos, setActionButtonsPos] =
|
|
3119
|
-
const handleSaveRef =
|
|
3514
|
+
const [originalContent, setOriginalContent] = useState8(content);
|
|
3515
|
+
const containerRef = useRef9(null);
|
|
3516
|
+
const originalContentRef = useRef9(content);
|
|
3517
|
+
const originalHadLineBreaksRef = useRef9(false);
|
|
3518
|
+
const [actionButtonsPos, setActionButtonsPos] = useState8(null);
|
|
3519
|
+
const handleSaveRef = useRef9(() => {
|
|
3120
3520
|
});
|
|
3121
|
-
const handleCancelRef =
|
|
3521
|
+
const handleCancelRef = useRef9(() => {
|
|
3122
3522
|
});
|
|
3123
|
-
const handleCloseRef =
|
|
3523
|
+
const handleCloseRef = useRef9(() => {
|
|
3124
3524
|
});
|
|
3125
3525
|
const editor = useEditor({
|
|
3126
3526
|
extensions: [
|
|
@@ -3176,19 +3576,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3176
3576
|
},
|
|
3177
3577
|
parseOptions: { preserveWhitespace: "full" }
|
|
3178
3578
|
});
|
|
3179
|
-
|
|
3579
|
+
useEffect8(() => {
|
|
3180
3580
|
if (editor && !isEditing) {
|
|
3181
3581
|
if (editor.getHTML() !== content) {
|
|
3182
3582
|
editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
|
|
3183
3583
|
}
|
|
3184
3584
|
}
|
|
3185
3585
|
}, [content, editor, isEditing]);
|
|
3186
|
-
|
|
3586
|
+
useEffect8(() => {
|
|
3187
3587
|
if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
|
|
3188
3588
|
setIsEditing(false);
|
|
3189
3589
|
}
|
|
3190
3590
|
}, [activeFieldId, fieldId, isEditing]);
|
|
3191
|
-
|
|
3591
|
+
useEffect8(() => {
|
|
3192
3592
|
if (!isEditing || !containerRef.current || !editor) {
|
|
3193
3593
|
setActionButtonsPos(null);
|
|
3194
3594
|
return;
|
|
@@ -3213,31 +3613,31 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3213
3613
|
window.removeEventListener("resize", updatePosition);
|
|
3214
3614
|
};
|
|
3215
3615
|
}, [isEditing, editor]);
|
|
3216
|
-
const handleSave =
|
|
3616
|
+
const handleSave = useCallback10(() => {
|
|
3217
3617
|
if (!editor) return;
|
|
3218
3618
|
let html = editor.getHTML();
|
|
3219
3619
|
const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
|
|
3220
3620
|
html = html.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
|
|
3221
3621
|
if (html !== originalContentRef.current) {
|
|
3222
|
-
|
|
3223
|
-
|
|
3622
|
+
contentHandle.set(html, "user");
|
|
3623
|
+
contentHandle.save();
|
|
3224
3624
|
originalContentRef.current = html;
|
|
3225
3625
|
}
|
|
3226
3626
|
setShowBubbleMenu(false);
|
|
3227
3627
|
setIsEditing(false);
|
|
3228
|
-
}, [editor,
|
|
3229
|
-
const handleCancel =
|
|
3628
|
+
}, [editor, contentHandle]);
|
|
3629
|
+
const handleCancel = useCallback10(() => {
|
|
3230
3630
|
if (editor) {
|
|
3231
3631
|
editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
|
|
3232
3632
|
}
|
|
3233
3633
|
setShowBubbleMenu(false);
|
|
3234
3634
|
setIsEditing(false);
|
|
3235
3635
|
}, [editor, originalContent]);
|
|
3236
|
-
|
|
3636
|
+
useEffect8(() => {
|
|
3237
3637
|
handleSaveRef.current = handleSave;
|
|
3238
3638
|
handleCancelRef.current = handleCancel;
|
|
3239
3639
|
}, [handleSave, handleCancel]);
|
|
3240
|
-
|
|
3640
|
+
useEffect8(() => {
|
|
3241
3641
|
if (mode !== "inline-edit") return;
|
|
3242
3642
|
const handleEditRequest = (event) => {
|
|
3243
3643
|
const customEvent = event;
|
|
@@ -3260,7 +3660,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3260
3660
|
window.addEventListener("yatext:edit-mode", handleEditRequest);
|
|
3261
3661
|
return () => window.removeEventListener("yatext:edit-mode", handleEditRequest);
|
|
3262
3662
|
}, [mode, fieldId, content, editor, setActiveField]);
|
|
3263
|
-
const handleClose =
|
|
3663
|
+
const handleClose = useCallback10(() => {
|
|
3264
3664
|
if (!editor) {
|
|
3265
3665
|
setShowBubbleMenu(false);
|
|
3266
3666
|
setIsEditing(false);
|
|
@@ -3270,16 +3670,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3270
3670
|
const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
|
|
3271
3671
|
currentHtml = currentHtml.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
|
|
3272
3672
|
if (currentHtml !== originalContentRef.current) {
|
|
3273
|
-
|
|
3274
|
-
|
|
3673
|
+
contentHandle.set(currentHtml, "user");
|
|
3674
|
+
contentHandle.save();
|
|
3275
3675
|
}
|
|
3276
3676
|
setShowBubbleMenu(false);
|
|
3277
3677
|
setIsEditing(false);
|
|
3278
|
-
}, [editor,
|
|
3279
|
-
|
|
3678
|
+
}, [editor, contentHandle]);
|
|
3679
|
+
useEffect8(() => {
|
|
3280
3680
|
handleCloseRef.current = handleClose;
|
|
3281
3681
|
}, [handleClose]);
|
|
3282
|
-
const handleClick =
|
|
3682
|
+
const handleClick = useCallback10((e) => {
|
|
3283
3683
|
if (isEditing) {
|
|
3284
3684
|
e.preventDefault();
|
|
3285
3685
|
e.stopPropagation();
|
|
@@ -3310,7 +3710,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3310
3710
|
}, 20);
|
|
3311
3711
|
}
|
|
3312
3712
|
}, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
|
|
3313
|
-
const handleKeyDown =
|
|
3713
|
+
const handleKeyDown = useCallback10(
|
|
3314
3714
|
(event) => {
|
|
3315
3715
|
if (!isEditing) return;
|
|
3316
3716
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
@@ -3331,7 +3731,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3331
3731
|
},
|
|
3332
3732
|
[isEditing, handleSave, handleCancel]
|
|
3333
3733
|
);
|
|
3334
|
-
const handleLink =
|
|
3734
|
+
const handleLink = useCallback10(() => {
|
|
3335
3735
|
if (!editor) return;
|
|
3336
3736
|
const previousUrl = editor.getAttributes("link").href;
|
|
3337
3737
|
const url = window.prompt("Enter URL:", previousUrl || "https://");
|
|
@@ -3342,7 +3742,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3342
3742
|
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
3343
3743
|
}
|
|
3344
3744
|
}, [editor]);
|
|
3345
|
-
const handleFontSizeChange =
|
|
3745
|
+
const handleFontSizeChange = useCallback10(
|
|
3346
3746
|
(size) => {
|
|
3347
3747
|
if (!editor) return;
|
|
3348
3748
|
if (size === "") {
|
|
@@ -3353,7 +3753,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3353
3753
|
},
|
|
3354
3754
|
[editor]
|
|
3355
3755
|
);
|
|
3356
|
-
const handleFontWeightChange =
|
|
3756
|
+
const handleFontWeightChange = useCallback10(
|
|
3357
3757
|
(weight) => {
|
|
3358
3758
|
if (!editor) return;
|
|
3359
3759
|
if (weight === "") {
|
|
@@ -3398,14 +3798,14 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3398
3798
|
return "";
|
|
3399
3799
|
};
|
|
3400
3800
|
if (mode === "read-only") {
|
|
3401
|
-
return /* @__PURE__ */
|
|
3801
|
+
return /* @__PURE__ */ jsx11(
|
|
3402
3802
|
Component,
|
|
3403
3803
|
{
|
|
3404
3804
|
ref: containerRef,
|
|
3405
3805
|
className,
|
|
3406
3806
|
"data-ya-restricted": "true",
|
|
3407
3807
|
"data-field-id": fieldId,
|
|
3408
|
-
children: /* @__PURE__ */
|
|
3808
|
+
children: /* @__PURE__ */ jsx11(SafeHtml, { content, mode })
|
|
3409
3809
|
}
|
|
3410
3810
|
);
|
|
3411
3811
|
}
|
|
@@ -3418,7 +3818,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3418
3818
|
wrapperClassName
|
|
3419
3819
|
].filter(Boolean).join(" ");
|
|
3420
3820
|
const EditSafeComponent = isEditing && Component === "p" ? "div" : Component;
|
|
3421
|
-
return /* @__PURE__ */
|
|
3821
|
+
return /* @__PURE__ */ jsx11(
|
|
3422
3822
|
EditSafeComponent,
|
|
3423
3823
|
{
|
|
3424
3824
|
ref: containerRef,
|
|
@@ -3436,7 +3836,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3436
3836
|
open: showBubbleMenu,
|
|
3437
3837
|
className: "ya-bubble-menu",
|
|
3438
3838
|
children: [
|
|
3439
|
-
/* @__PURE__ */
|
|
3839
|
+
/* @__PURE__ */ jsx11(
|
|
3440
3840
|
"button",
|
|
3441
3841
|
{
|
|
3442
3842
|
type: "button",
|
|
@@ -3444,10 +3844,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3444
3844
|
onMouseDown: (e) => e.preventDefault(),
|
|
3445
3845
|
className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
|
|
3446
3846
|
title: "Bold",
|
|
3447
|
-
children: /* @__PURE__ */
|
|
3847
|
+
children: /* @__PURE__ */ jsx11(BoldIcon, { size: 16 })
|
|
3448
3848
|
}
|
|
3449
3849
|
),
|
|
3450
|
-
/* @__PURE__ */
|
|
3850
|
+
/* @__PURE__ */ jsx11(
|
|
3451
3851
|
"button",
|
|
3452
3852
|
{
|
|
3453
3853
|
type: "button",
|
|
@@ -3455,10 +3855,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3455
3855
|
onMouseDown: (e) => e.preventDefault(),
|
|
3456
3856
|
className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
|
|
3457
3857
|
title: "Italic",
|
|
3458
|
-
children: /* @__PURE__ */
|
|
3858
|
+
children: /* @__PURE__ */ jsx11(ItalicIcon, { size: 16 })
|
|
3459
3859
|
}
|
|
3460
3860
|
),
|
|
3461
|
-
/* @__PURE__ */
|
|
3861
|
+
/* @__PURE__ */ jsx11(
|
|
3462
3862
|
"button",
|
|
3463
3863
|
{
|
|
3464
3864
|
type: "button",
|
|
@@ -3466,17 +3866,17 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3466
3866
|
onMouseDown: (e) => e.preventDefault(),
|
|
3467
3867
|
className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
|
|
3468
3868
|
title: "Link",
|
|
3469
|
-
children: /* @__PURE__ */
|
|
3869
|
+
children: /* @__PURE__ */ jsx11(LinkIcon2, { size: 16 })
|
|
3470
3870
|
}
|
|
3471
3871
|
),
|
|
3472
|
-
/* @__PURE__ */
|
|
3473
|
-
/* @__PURE__ */
|
|
3872
|
+
/* @__PURE__ */ jsx11("span", { className: "ya-bubble-divider" }),
|
|
3873
|
+
/* @__PURE__ */ jsx11(
|
|
3474
3874
|
BubbleDropdown,
|
|
3475
3875
|
{
|
|
3476
3876
|
label: getFontSizeLabel(getCurrentFontSize()),
|
|
3477
3877
|
open: fontSizeOpen,
|
|
3478
3878
|
onOpenChange: setFontSizeOpen,
|
|
3479
|
-
children: /* @__PURE__ */
|
|
3879
|
+
children: /* @__PURE__ */ jsx11(
|
|
3480
3880
|
FontSizePicker,
|
|
3481
3881
|
{
|
|
3482
3882
|
value: getCurrentFontSize(),
|
|
@@ -3486,13 +3886,13 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3486
3886
|
)
|
|
3487
3887
|
}
|
|
3488
3888
|
),
|
|
3489
|
-
/* @__PURE__ */
|
|
3889
|
+
/* @__PURE__ */ jsx11(
|
|
3490
3890
|
BubbleDropdown,
|
|
3491
3891
|
{
|
|
3492
3892
|
label: getFontWeightLabel(getCurrentFontWeight()),
|
|
3493
3893
|
open: fontWeightOpen,
|
|
3494
3894
|
onOpenChange: setFontWeightOpen,
|
|
3495
|
-
children: /* @__PURE__ */
|
|
3895
|
+
children: /* @__PURE__ */ jsx11(
|
|
3496
3896
|
FontWeightPicker,
|
|
3497
3897
|
{
|
|
3498
3898
|
value: getCurrentFontWeight(),
|
|
@@ -3506,7 +3906,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3506
3906
|
}
|
|
3507
3907
|
),
|
|
3508
3908
|
isEditing ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3509
|
-
/* @__PURE__ */
|
|
3909
|
+
/* @__PURE__ */ jsx11(EditorContent, { editor }),
|
|
3510
3910
|
actionButtonsPos && createPortal4(
|
|
3511
3911
|
/* @__PURE__ */ jsxs5(
|
|
3512
3912
|
"div",
|
|
@@ -3520,7 +3920,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3520
3920
|
// Right edge aligns with text end
|
|
3521
3921
|
},
|
|
3522
3922
|
children: [
|
|
3523
|
-
/* @__PURE__ */
|
|
3923
|
+
/* @__PURE__ */ jsx11(
|
|
3524
3924
|
"button",
|
|
3525
3925
|
{
|
|
3526
3926
|
type: "button",
|
|
@@ -3529,7 +3929,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3529
3929
|
children: "Cancel"
|
|
3530
3930
|
}
|
|
3531
3931
|
),
|
|
3532
|
-
/* @__PURE__ */
|
|
3932
|
+
/* @__PURE__ */ jsx11(
|
|
3533
3933
|
"button",
|
|
3534
3934
|
{
|
|
3535
3935
|
type: "button",
|
|
@@ -3544,19 +3944,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
|
|
|
3544
3944
|
document.body
|
|
3545
3945
|
)
|
|
3546
3946
|
] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3547
|
-
/* @__PURE__ */
|
|
3548
|
-
isAnimating && /* @__PURE__ */
|
|
3947
|
+
/* @__PURE__ */ jsx11(SafeHtml, { content: displayContent, mode }),
|
|
3948
|
+
isAnimating && /* @__PURE__ */ jsx11("span", { className: "ya-typing-cursor" })
|
|
3549
3949
|
] })
|
|
3550
3950
|
] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3551
|
-
/* @__PURE__ */
|
|
3552
|
-
isAnimating && /* @__PURE__ */
|
|
3951
|
+
/* @__PURE__ */ jsx11(SafeHtml, { content: displayContent, mode }),
|
|
3952
|
+
isAnimating && /* @__PURE__ */ jsx11("span", { className: "ya-typing-cursor" })
|
|
3553
3953
|
] })
|
|
3554
3954
|
}
|
|
3555
3955
|
);
|
|
3556
3956
|
}
|
|
3557
3957
|
|
|
3558
3958
|
// src/components/YaImage.tsx
|
|
3559
|
-
import { useCallback as
|
|
3959
|
+
import { useCallback as useCallback13, useEffect as useEffect11, useRef as useRef12, useState as useState11 } from "react";
|
|
3560
3960
|
|
|
3561
3961
|
// src/lib/asset-resolver.ts
|
|
3562
3962
|
var assetResolver = (path) => path;
|
|
@@ -3572,25 +3972,25 @@ function resolveAssetUrl(path) {
|
|
|
3572
3972
|
}
|
|
3573
3973
|
|
|
3574
3974
|
// src/components/YaTooltip.tsx
|
|
3575
|
-
import { useEffect as
|
|
3975
|
+
import { useEffect as useEffect9, useRef as useRef10, useState as useState9, useCallback as useCallback11 } from "react";
|
|
3576
3976
|
import { createPortal as createPortal5 } from "react-dom";
|
|
3577
3977
|
|
|
3578
3978
|
// src/components/ya-tooltip.css
|
|
3579
3979
|
styleInject('.ya-tooltip {\n position: fixed;\n z-index: 9999;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n animation: ya-tooltip-fade-in 0.15s ease;\n pointer-events: none;\n}\n@keyframes ya-tooltip-fade-in {\n from {\n transform: scale(0.95);\n }\n to {\n transform: scale(1);\n }\n}\n.ya-tooltip svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n.ya-tooltip-bottom {\n transform: translateX(-50%);\n}\n.ya-tooltip-bottom::before {\n content: "";\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-bottom-color: #1a1a1a;\n}\n.ya-tooltip-top {\n transform: translateX(-50%);\n}\n.ya-tooltip-top::before {\n content: "";\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-top-color: #1a1a1a;\n}\n.ya-tooltip-right {\n transform: translateY(-50%);\n}\n.ya-tooltip-right::before {\n content: "";\n position: absolute;\n right: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-right-color: #1a1a1a;\n}\n.ya-tooltip-left {\n transform: translateY(-50%);\n}\n.ya-tooltip-left::before {\n content: "";\n position: absolute;\n left: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: #1a1a1a;\n}\n');
|
|
3580
3980
|
|
|
3581
3981
|
// src/components/YaTooltip.tsx
|
|
3582
|
-
import { jsx as
|
|
3982
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
3583
3983
|
function YaTooltip({
|
|
3584
3984
|
anchorRef,
|
|
3585
3985
|
children,
|
|
3586
3986
|
show,
|
|
3587
3987
|
preferredPosition = "bottom"
|
|
3588
3988
|
}) {
|
|
3589
|
-
const [position, setPosition] =
|
|
3590
|
-
const [coords, setCoords] =
|
|
3591
|
-
const [isPositioned, setIsPositioned] =
|
|
3592
|
-
const tooltipRef =
|
|
3593
|
-
const calculatePosition =
|
|
3989
|
+
const [position, setPosition] = useState9(preferredPosition);
|
|
3990
|
+
const [coords, setCoords] = useState9({ top: 0, left: 0 });
|
|
3991
|
+
const [isPositioned, setIsPositioned] = useState9(false);
|
|
3992
|
+
const tooltipRef = useRef10(null);
|
|
3993
|
+
const calculatePosition = useCallback11(() => {
|
|
3594
3994
|
if (!anchorRef.current) return;
|
|
3595
3995
|
const anchor = anchorRef.current.getBoundingClientRect();
|
|
3596
3996
|
const tooltip = tooltipRef.current?.getBoundingClientRect();
|
|
@@ -3665,7 +4065,7 @@ function YaTooltip({
|
|
|
3665
4065
|
setCoords({ top, left });
|
|
3666
4066
|
setIsPositioned(true);
|
|
3667
4067
|
}, [anchorRef, preferredPosition]);
|
|
3668
|
-
|
|
4068
|
+
useEffect9(() => {
|
|
3669
4069
|
if (!show) {
|
|
3670
4070
|
setIsPositioned(false);
|
|
3671
4071
|
return;
|
|
@@ -3678,14 +4078,14 @@ function YaTooltip({
|
|
|
3678
4078
|
window.removeEventListener("resize", calculatePosition);
|
|
3679
4079
|
};
|
|
3680
4080
|
}, [show, calculatePosition]);
|
|
3681
|
-
|
|
4081
|
+
useEffect9(() => {
|
|
3682
4082
|
if (show && tooltipRef.current) {
|
|
3683
4083
|
calculatePosition();
|
|
3684
4084
|
}
|
|
3685
4085
|
}, [show, children, calculatePosition]);
|
|
3686
4086
|
if (!show) return null;
|
|
3687
4087
|
return createPortal5(
|
|
3688
|
-
/* @__PURE__ */
|
|
4088
|
+
/* @__PURE__ */ jsx12(
|
|
3689
4089
|
"div",
|
|
3690
4090
|
{
|
|
3691
4091
|
ref: tooltipRef,
|
|
@@ -3704,7 +4104,7 @@ function YaTooltip({
|
|
|
3704
4104
|
}
|
|
3705
4105
|
|
|
3706
4106
|
// src/hooks/useImageShaderTransition.ts
|
|
3707
|
-
import { useCallback as
|
|
4107
|
+
import { useCallback as useCallback12, useEffect as useEffect10, useRef as useRef11, useState as useState10 } from "react";
|
|
3708
4108
|
|
|
3709
4109
|
// src/lib/image-shader-transition.ts
|
|
3710
4110
|
var VERTEX_SHADER = `
|
|
@@ -3964,14 +4364,14 @@ function preloadImage(src) {
|
|
|
3964
4364
|
var TRANSITION_DURATION = 500;
|
|
3965
4365
|
function useImageShaderTransition(options = {}) {
|
|
3966
4366
|
const { duration = TRANSITION_DURATION, onComplete } = options;
|
|
3967
|
-
const canvasRef =
|
|
3968
|
-
const rendererRef =
|
|
3969
|
-
const rafRef =
|
|
3970
|
-
const startTimeRef =
|
|
3971
|
-
const newSrcRef =
|
|
3972
|
-
const [isTransitioning, setIsTransitioning] =
|
|
3973
|
-
const [webglAvailable] =
|
|
3974
|
-
|
|
4367
|
+
const canvasRef = useRef11(null);
|
|
4368
|
+
const rendererRef = useRef11(null);
|
|
4369
|
+
const rafRef = useRef11(null);
|
|
4370
|
+
const startTimeRef = useRef11(0);
|
|
4371
|
+
const newSrcRef = useRef11("");
|
|
4372
|
+
const [isTransitioning, setIsTransitioning] = useState10(false);
|
|
4373
|
+
const [webglAvailable] = useState10(() => isWebGLAvailable());
|
|
4374
|
+
useEffect10(() => {
|
|
3975
4375
|
return () => {
|
|
3976
4376
|
if (rafRef.current) {
|
|
3977
4377
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -3979,7 +4379,7 @@ function useImageShaderTransition(options = {}) {
|
|
|
3979
4379
|
rendererRef.current?.destroy();
|
|
3980
4380
|
};
|
|
3981
4381
|
}, []);
|
|
3982
|
-
const animate =
|
|
4382
|
+
const animate = useCallback12(() => {
|
|
3983
4383
|
const renderer = rendererRef.current;
|
|
3984
4384
|
if (!renderer) return;
|
|
3985
4385
|
const elapsed = performance.now() - startTimeRef.current;
|
|
@@ -3994,7 +4394,7 @@ function useImageShaderTransition(options = {}) {
|
|
|
3994
4394
|
});
|
|
3995
4395
|
}
|
|
3996
4396
|
}, [duration, onComplete]);
|
|
3997
|
-
const startTransition =
|
|
4397
|
+
const startTransition = useCallback12(
|
|
3998
4398
|
(oldSrc, newSrc) => {
|
|
3999
4399
|
if (!webglAvailable) {
|
|
4000
4400
|
return;
|
|
@@ -4026,7 +4426,7 @@ function useImageShaderTransition(options = {}) {
|
|
|
4026
4426
|
},
|
|
4027
4427
|
[webglAvailable, animate]
|
|
4028
4428
|
);
|
|
4029
|
-
const cancelTransition =
|
|
4429
|
+
const cancelTransition = useCallback12(() => {
|
|
4030
4430
|
if (rafRef.current) {
|
|
4031
4431
|
cancelAnimationFrame(rafRef.current);
|
|
4032
4432
|
rafRef.current = null;
|
|
@@ -4046,7 +4446,7 @@ function useImageShaderTransition(options = {}) {
|
|
|
4046
4446
|
styleInject('.ya-image-container {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 45px;\n min-height: 45px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-image-container img {\n display: block;\n}\n.ya-image-editable {\n cursor: pointer;\n}\n.ya-image-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-image-editable:hover .ya-image-overlay {\n opacity: 1;\n}\n.ya-image-selected .ya-image-overlay {\n opacity: 0;\n}\n.ya-image-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-image-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-image-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n@keyframes ya-image-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #D4A574);\n outline-width: 2px;\n }\n}\n.ya-image-success {\n animation: ya-image-success 0.4s ease;\n}\n.ya-image-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-image-shimmer 1.5s infinite;\n}\n@keyframes ya-image-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-image-container:focus {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-image-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-small .ya-image-overlay {\n display: none;\n}\n.ya-image-drop-target {\n outline: 2px dashed var(--ya-drop-color, #3b82f6) !important;\n outline-offset: 4px;\n}\n.ya-image-drop-target .ya-image-overlay {\n display: none !important;\n}\n.ya-image-drop-hover {\n outline: 3px solid var(--ya-drop-color, #3b82f6) !important;\n outline-offset: 4px;\n background-color: rgba(59, 130, 246, 0.1);\n}\n.ya-image-drop-hover::before {\n content: "";\n position: absolute;\n inset: -4px;\n border: 2px solid var(--ya-drop-color, #3b82f6);\n border-radius: inherit;\n animation: ya-drop-pulse 1s ease-in-out infinite;\n pointer-events: none;\n}\n@keyframes ya-drop-pulse {\n 0%, 100% {\n opacity: 0.4;\n transform: scale(1);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.02);\n }\n}\n');
|
|
4047
4447
|
|
|
4048
4448
|
// src/components/YaImage.tsx
|
|
4049
|
-
import { jsx as
|
|
4449
|
+
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4050
4450
|
function parseImageValue(value) {
|
|
4051
4451
|
if (!value) {
|
|
4052
4452
|
return { src: "" };
|
|
@@ -4090,17 +4490,18 @@ function YaImage({
|
|
|
4090
4490
|
fallbackSrc,
|
|
4091
4491
|
fallbackAlt
|
|
4092
4492
|
}) {
|
|
4093
|
-
const
|
|
4094
|
-
const
|
|
4095
|
-
const
|
|
4096
|
-
const
|
|
4097
|
-
const [
|
|
4098
|
-
const [
|
|
4099
|
-
const [
|
|
4100
|
-
const [
|
|
4101
|
-
const [
|
|
4102
|
-
const
|
|
4103
|
-
const
|
|
4493
|
+
const content = useContent(fieldId);
|
|
4494
|
+
const { mode } = content;
|
|
4495
|
+
const containerRef = useRef12(null);
|
|
4496
|
+
const imgRef = useRef12(null);
|
|
4497
|
+
const [isSelected, setIsSelected] = useState11(false);
|
|
4498
|
+
const [isHovered, setIsHovered] = useState11(false);
|
|
4499
|
+
const [isSmallImage, setIsSmallImage] = useState11(false);
|
|
4500
|
+
const [isDropMode, setIsDropMode] = useState11(false);
|
|
4501
|
+
const [isDropHover, setIsDropHover] = useState11(false);
|
|
4502
|
+
const [previewOverride, setPreviewOverride] = useState11(null);
|
|
4503
|
+
const prevSrcRef = useRef12(null);
|
|
4504
|
+
const rawValue = content.get();
|
|
4104
4505
|
const imageData = parseImageValue(rawValue);
|
|
4105
4506
|
const displayData = previewOverride || imageData;
|
|
4106
4507
|
const src = displayData.src || fallbackSrc || PLACEHOLDER_SVG;
|
|
@@ -4116,36 +4517,34 @@ function YaImage({
|
|
|
4116
4517
|
} = useImageShaderTransition({
|
|
4117
4518
|
duration: 500,
|
|
4118
4519
|
onComplete: () => {
|
|
4119
|
-
clearChangeSource(
|
|
4520
|
+
content.clearChangeSource();
|
|
4120
4521
|
}
|
|
4121
4522
|
});
|
|
4122
|
-
|
|
4123
|
-
const changeSource =
|
|
4523
|
+
useEffect11(() => {
|
|
4524
|
+
const changeSource = content.changeSource;
|
|
4124
4525
|
const resolvedSrc = resolveAssetUrl(src);
|
|
4125
4526
|
const prevResolvedSrc = prevSrcRef.current;
|
|
4126
4527
|
if (changeSource === "ai") {
|
|
4127
4528
|
if (prevResolvedSrc !== null && prevResolvedSrc !== resolvedSrc && webglAvailable) {
|
|
4128
4529
|
startTransition(prevResolvedSrc, resolvedSrc);
|
|
4129
4530
|
} else {
|
|
4130
|
-
clearChangeSource(
|
|
4531
|
+
content.clearChangeSource();
|
|
4131
4532
|
}
|
|
4132
4533
|
}
|
|
4133
4534
|
prevSrcRef.current = resolvedSrc;
|
|
4134
4535
|
}, [
|
|
4135
4536
|
rawValue,
|
|
4136
4537
|
src,
|
|
4137
|
-
|
|
4138
|
-
getChangeSource,
|
|
4139
|
-
clearChangeSource,
|
|
4538
|
+
content,
|
|
4140
4539
|
startTransition,
|
|
4141
4540
|
webglAvailable
|
|
4142
4541
|
]);
|
|
4143
|
-
|
|
4542
|
+
useEffect11(() => {
|
|
4144
4543
|
return () => {
|
|
4145
4544
|
cancelTransition();
|
|
4146
4545
|
};
|
|
4147
4546
|
}, [cancelTransition]);
|
|
4148
|
-
const handleClick =
|
|
4547
|
+
const handleClick = useCallback13(() => {
|
|
4149
4548
|
if (mode !== "inline-edit") return;
|
|
4150
4549
|
if (document.body.classList.contains("builder-selector-active")) return;
|
|
4151
4550
|
setIsSelected(true);
|
|
@@ -4173,12 +4572,14 @@ function YaImage({
|
|
|
4173
4572
|
"*"
|
|
4174
4573
|
);
|
|
4175
4574
|
}, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
|
|
4176
|
-
|
|
4575
|
+
useEffect11(() => {
|
|
4177
4576
|
if (mode !== "inline-edit") return;
|
|
4178
4577
|
const handleMessage2 = (event) => {
|
|
4179
4578
|
if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
|
|
4180
4579
|
const value = event.data.value;
|
|
4181
|
-
|
|
4580
|
+
const serializedValue = serializeImageValue(value);
|
|
4581
|
+
content.set(serializedValue, "user");
|
|
4582
|
+
content.save();
|
|
4182
4583
|
setPreviewOverride(null);
|
|
4183
4584
|
setIsSelected(false);
|
|
4184
4585
|
}
|
|
@@ -4193,8 +4594,8 @@ function YaImage({
|
|
|
4193
4594
|
};
|
|
4194
4595
|
window.addEventListener("message", handleMessage2);
|
|
4195
4596
|
return () => window.removeEventListener("message", handleMessage2);
|
|
4196
|
-
}, [mode, fieldId,
|
|
4197
|
-
|
|
4597
|
+
}, [mode, fieldId, content]);
|
|
4598
|
+
useEffect11(() => {
|
|
4198
4599
|
if (mode !== "inline-edit") return;
|
|
4199
4600
|
const handleDropModeMessage = (event) => {
|
|
4200
4601
|
if (event.data?.type === "DROP_MODE_START") {
|
|
@@ -4208,7 +4609,7 @@ function YaImage({
|
|
|
4208
4609
|
window.addEventListener("message", handleDropModeMessage);
|
|
4209
4610
|
return () => window.removeEventListener("message", handleDropModeMessage);
|
|
4210
4611
|
}, [mode]);
|
|
4211
|
-
const handleDragEnter =
|
|
4612
|
+
const handleDragEnter = useCallback13(
|
|
4212
4613
|
(e) => {
|
|
4213
4614
|
if (!isDropMode) return;
|
|
4214
4615
|
e.preventDefault();
|
|
@@ -4232,7 +4633,7 @@ function YaImage({
|
|
|
4232
4633
|
},
|
|
4233
4634
|
[isDropMode, fieldId]
|
|
4234
4635
|
);
|
|
4235
|
-
const handleDragOver =
|
|
4636
|
+
const handleDragOver = useCallback13(
|
|
4236
4637
|
(e) => {
|
|
4237
4638
|
if (!isDropMode) return;
|
|
4238
4639
|
e.preventDefault();
|
|
@@ -4240,7 +4641,7 @@ function YaImage({
|
|
|
4240
4641
|
},
|
|
4241
4642
|
[isDropMode]
|
|
4242
4643
|
);
|
|
4243
|
-
const handleDragLeave =
|
|
4644
|
+
const handleDragLeave = useCallback13(
|
|
4244
4645
|
(e) => {
|
|
4245
4646
|
if (!isDropMode) return;
|
|
4246
4647
|
e.preventDefault();
|
|
@@ -4254,7 +4655,7 @@ function YaImage({
|
|
|
4254
4655
|
},
|
|
4255
4656
|
[isDropMode]
|
|
4256
4657
|
);
|
|
4257
|
-
const handleDrop =
|
|
4658
|
+
const handleDrop = useCallback13(
|
|
4258
4659
|
(e) => {
|
|
4259
4660
|
if (!isDropMode) return;
|
|
4260
4661
|
e.preventDefault();
|
|
@@ -4272,7 +4673,7 @@ function YaImage({
|
|
|
4272
4673
|
},
|
|
4273
4674
|
[isDropMode, fieldId]
|
|
4274
4675
|
);
|
|
4275
|
-
|
|
4676
|
+
useEffect11(() => {
|
|
4276
4677
|
if (mode !== "inline-edit") return;
|
|
4277
4678
|
const checkSize = () => {
|
|
4278
4679
|
if (imgRef.current) {
|
|
@@ -4294,7 +4695,7 @@ function YaImage({
|
|
|
4294
4695
|
window.removeEventListener("resize", checkSize);
|
|
4295
4696
|
};
|
|
4296
4697
|
}, [mode]);
|
|
4297
|
-
|
|
4698
|
+
useEffect11(() => {
|
|
4298
4699
|
if (!isSelected || mode !== "inline-edit") return;
|
|
4299
4700
|
let lastRectKey = "";
|
|
4300
4701
|
let lastTime = 0;
|
|
@@ -4336,7 +4737,7 @@ function YaImage({
|
|
|
4336
4737
|
"data-ya-restricted": "true",
|
|
4337
4738
|
"data-field-id": fieldId,
|
|
4338
4739
|
children: [
|
|
4339
|
-
/* @__PURE__ */
|
|
4740
|
+
/* @__PURE__ */ jsx13(
|
|
4340
4741
|
"img",
|
|
4341
4742
|
{
|
|
4342
4743
|
src: resolveAssetUrl(src),
|
|
@@ -4352,7 +4753,7 @@ function YaImage({
|
|
|
4352
4753
|
loading
|
|
4353
4754
|
}
|
|
4354
4755
|
),
|
|
4355
|
-
/* @__PURE__ */
|
|
4756
|
+
/* @__PURE__ */ jsx13(
|
|
4356
4757
|
"canvas",
|
|
4357
4758
|
{
|
|
4358
4759
|
ref: canvasRef,
|
|
@@ -4386,9 +4787,9 @@ function YaImage({
|
|
|
4386
4787
|
strokeLinecap: "round",
|
|
4387
4788
|
strokeLinejoin: "round",
|
|
4388
4789
|
children: [
|
|
4389
|
-
/* @__PURE__ */
|
|
4390
|
-
/* @__PURE__ */
|
|
4391
|
-
/* @__PURE__ */
|
|
4790
|
+
/* @__PURE__ */ jsx13("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
4791
|
+
/* @__PURE__ */ jsx13("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
4792
|
+
/* @__PURE__ */ jsx13("polyline", { points: "21 15 16 10 5 21" })
|
|
4392
4793
|
]
|
|
4393
4794
|
}
|
|
4394
4795
|
);
|
|
@@ -4424,7 +4825,7 @@ function YaImage({
|
|
|
4424
4825
|
}
|
|
4425
4826
|
},
|
|
4426
4827
|
children: [
|
|
4427
|
-
/* @__PURE__ */
|
|
4828
|
+
/* @__PURE__ */ jsx13(
|
|
4428
4829
|
"img",
|
|
4429
4830
|
{
|
|
4430
4831
|
ref: imgRef,
|
|
@@ -4441,7 +4842,7 @@ function YaImage({
|
|
|
4441
4842
|
loading
|
|
4442
4843
|
}
|
|
4443
4844
|
),
|
|
4444
|
-
/* @__PURE__ */
|
|
4845
|
+
/* @__PURE__ */ jsx13(
|
|
4445
4846
|
"canvas",
|
|
4446
4847
|
{
|
|
4447
4848
|
ref: canvasRef,
|
|
@@ -4461,12 +4862,12 @@ function YaImage({
|
|
|
4461
4862
|
),
|
|
4462
4863
|
isSmallImage ? /* @__PURE__ */ jsxs6(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
|
|
4463
4864
|
editIcon,
|
|
4464
|
-
/* @__PURE__ */
|
|
4865
|
+
/* @__PURE__ */ jsx13("span", { children: "Click to edit" })
|
|
4465
4866
|
] }) : (
|
|
4466
4867
|
/* For large images: show overlay inside the image */
|
|
4467
4868
|
/* @__PURE__ */ jsxs6("div", { className: "ya-image-overlay", children: [
|
|
4468
|
-
/* @__PURE__ */
|
|
4469
|
-
/* @__PURE__ */
|
|
4869
|
+
/* @__PURE__ */ jsx13("div", { className: "ya-image-edit-icon", children: editIcon }),
|
|
4870
|
+
/* @__PURE__ */ jsx13("span", { className: "ya-image-edit-label", children: "Click to edit" })
|
|
4470
4871
|
] })
|
|
4471
4872
|
)
|
|
4472
4873
|
]
|
|
@@ -4475,13 +4876,13 @@ function YaImage({
|
|
|
4475
4876
|
}
|
|
4476
4877
|
|
|
4477
4878
|
// src/components/YaVideo.tsx
|
|
4478
|
-
import { useCallback as
|
|
4879
|
+
import { useCallback as useCallback14, useEffect as useEffect12, useRef as useRef13, useState as useState12 } from "react";
|
|
4479
4880
|
|
|
4480
4881
|
// src/components/ya-video.css
|
|
4481
4882
|
styleInject('.ya-video-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-video-wrapper video,\n.ya-video-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-video-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 45px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-video-container video,\n.ya-video-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-video-editable {\n cursor: pointer;\n}\n.ya-video-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-video-editable:hover .ya-video-overlay {\n opacity: 1;\n}\n.ya-video-selected .ya-video-overlay {\n opacity: 0;\n}\n.ya-video-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-video-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-video-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-video-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-video-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-video-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #D4A574);\n outline-width: 2px;\n }\n}\n.ya-video-success {\n animation: ya-video-success 0.4s ease;\n}\n.ya-video-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-video-shimmer 1.5s infinite;\n}\n@keyframes ya-video-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-video-container:focus {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-video-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-video-small .ya-video-overlay {\n display: none;\n}\n.ya-video-background {\n position: absolute;\n inset: 0;\n z-index: -1;\n}\n.ya-video-background video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n');
|
|
4482
4883
|
|
|
4483
4884
|
// src/components/YaVideo.tsx
|
|
4484
|
-
import { jsx as
|
|
4885
|
+
import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4485
4886
|
function parseVideoValue(value) {
|
|
4486
4887
|
if (!value) {
|
|
4487
4888
|
return { type: "upload", src: "" };
|
|
@@ -4553,14 +4954,15 @@ function YaVideo({
|
|
|
4553
4954
|
fallbackSrc,
|
|
4554
4955
|
fallbackPoster
|
|
4555
4956
|
}) {
|
|
4556
|
-
const
|
|
4557
|
-
const
|
|
4558
|
-
const
|
|
4559
|
-
const
|
|
4560
|
-
const [
|
|
4561
|
-
const [
|
|
4562
|
-
const [
|
|
4563
|
-
const
|
|
4957
|
+
const content = useContent(fieldId);
|
|
4958
|
+
const { mode } = content;
|
|
4959
|
+
const containerRef = useRef13(null);
|
|
4960
|
+
const videoRef = useRef13(null);
|
|
4961
|
+
const [isSelected, setIsSelected] = useState12(false);
|
|
4962
|
+
const [isHovered, setIsHovered] = useState12(false);
|
|
4963
|
+
const [isSmallVideo, setIsSmallVideo] = useState12(false);
|
|
4964
|
+
const [isInView, setIsInView] = useState12(loading === "eager");
|
|
4965
|
+
const rawValue = content.get();
|
|
4564
4966
|
const parsedValue = parseVideoValue(rawValue);
|
|
4565
4967
|
const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
|
|
4566
4968
|
const src = videoData.src || fallbackSrc || "";
|
|
@@ -4573,8 +4975,8 @@ function YaVideo({
|
|
|
4573
4975
|
const controls = videoData.controls ?? true;
|
|
4574
4976
|
const playsinline = videoData.playsinline ?? true;
|
|
4575
4977
|
const preload = videoData.preload ?? "metadata";
|
|
4576
|
-
const [prefersReducedMotion, setPrefersReducedMotion] =
|
|
4577
|
-
|
|
4978
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = useState12(false);
|
|
4979
|
+
useEffect12(() => {
|
|
4578
4980
|
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
4579
4981
|
setPrefersReducedMotion(mediaQuery.matches);
|
|
4580
4982
|
const handleChange = (e) => {
|
|
@@ -4584,7 +4986,7 @@ function YaVideo({
|
|
|
4584
4986
|
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
4585
4987
|
}, []);
|
|
4586
4988
|
const effectiveAutoplay = autoplay && !prefersReducedMotion;
|
|
4587
|
-
|
|
4989
|
+
useEffect12(() => {
|
|
4588
4990
|
if (loading === "eager" || isInView) return;
|
|
4589
4991
|
const observer = new IntersectionObserver(
|
|
4590
4992
|
(entries) => {
|
|
@@ -4601,7 +5003,7 @@ function YaVideo({
|
|
|
4601
5003
|
}
|
|
4602
5004
|
return () => observer.disconnect();
|
|
4603
5005
|
}, [loading, isInView]);
|
|
4604
|
-
const handleKeyDown =
|
|
5006
|
+
const handleKeyDown = useCallback14(
|
|
4605
5007
|
(e) => {
|
|
4606
5008
|
if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
|
|
4607
5009
|
e.preventDefault();
|
|
@@ -4617,7 +5019,7 @@ function YaVideo({
|
|
|
4617
5019
|
},
|
|
4618
5020
|
[videoData.type, controls]
|
|
4619
5021
|
);
|
|
4620
|
-
const handleClick =
|
|
5022
|
+
const handleClick = useCallback14(() => {
|
|
4621
5023
|
if (mode !== "inline-edit") return;
|
|
4622
5024
|
if (document.body.classList.contains("builder-selector-active")) return;
|
|
4623
5025
|
setIsSelected(true);
|
|
@@ -4637,7 +5039,7 @@ function YaVideo({
|
|
|
4637
5039
|
"*"
|
|
4638
5040
|
);
|
|
4639
5041
|
}, [mode, fieldId, videoData]);
|
|
4640
|
-
|
|
5042
|
+
useEffect12(() => {
|
|
4641
5043
|
if (mode !== "inline-edit") return;
|
|
4642
5044
|
const handleMessage2 = (event) => {
|
|
4643
5045
|
if (event.data?.type === "YA_VIDEO_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
|
|
@@ -4650,7 +5052,7 @@ function YaVideo({
|
|
|
4650
5052
|
window.addEventListener("message", handleMessage2);
|
|
4651
5053
|
return () => window.removeEventListener("message", handleMessage2);
|
|
4652
5054
|
}, [mode, fieldId]);
|
|
4653
|
-
|
|
5055
|
+
useEffect12(() => {
|
|
4654
5056
|
if (mode !== "inline-edit") return;
|
|
4655
5057
|
const checkSize = () => {
|
|
4656
5058
|
if (containerRef.current) {
|
|
@@ -4662,7 +5064,7 @@ function YaVideo({
|
|
|
4662
5064
|
window.addEventListener("resize", checkSize);
|
|
4663
5065
|
return () => window.removeEventListener("resize", checkSize);
|
|
4664
5066
|
}, [mode]);
|
|
4665
|
-
|
|
5067
|
+
useEffect12(() => {
|
|
4666
5068
|
if (!isSelected || mode !== "inline-edit") return;
|
|
4667
5069
|
let lastRectKey = "";
|
|
4668
5070
|
let lastTime = 0;
|
|
@@ -4699,23 +5101,23 @@ function YaVideo({
|
|
|
4699
5101
|
const renderVideo = (isReadOnly) => {
|
|
4700
5102
|
if (!src && !isReadOnly) {
|
|
4701
5103
|
return /* @__PURE__ */ jsxs7("div", { className: "ya-video-placeholder", children: [
|
|
4702
|
-
/* @__PURE__ */
|
|
4703
|
-
/* @__PURE__ */
|
|
5104
|
+
/* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG2, alt: "" }),
|
|
5105
|
+
/* @__PURE__ */ jsx14("span", { children: "No video selected" })
|
|
4704
5106
|
] });
|
|
4705
5107
|
}
|
|
4706
5108
|
if (!isInView && loading === "lazy" && !isReadOnly) {
|
|
4707
|
-
return /* @__PURE__ */
|
|
5109
|
+
return /* @__PURE__ */ jsx14(
|
|
4708
5110
|
"div",
|
|
4709
5111
|
{
|
|
4710
5112
|
className: "ya-video-placeholder",
|
|
4711
5113
|
style: { aspectRatio },
|
|
4712
|
-
children: /* @__PURE__ */
|
|
5114
|
+
children: /* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG2, alt: "" })
|
|
4713
5115
|
}
|
|
4714
5116
|
);
|
|
4715
5117
|
}
|
|
4716
5118
|
if (videoData.type === "youtube" && src) {
|
|
4717
5119
|
const embedUrl = buildYouTubeEmbedUrl(src, videoData);
|
|
4718
|
-
return /* @__PURE__ */
|
|
5120
|
+
return /* @__PURE__ */ jsx14(
|
|
4719
5121
|
"iframe",
|
|
4720
5122
|
{
|
|
4721
5123
|
src: embedUrl,
|
|
@@ -4735,7 +5137,7 @@ function YaVideo({
|
|
|
4735
5137
|
}
|
|
4736
5138
|
if (videoData.type === "vimeo" && src) {
|
|
4737
5139
|
const embedUrl = buildVimeoEmbedUrl(src, videoData);
|
|
4738
|
-
return /* @__PURE__ */
|
|
5140
|
+
return /* @__PURE__ */ jsx14(
|
|
4739
5141
|
"iframe",
|
|
4740
5142
|
{
|
|
4741
5143
|
src: embedUrl,
|
|
@@ -4755,7 +5157,7 @@ function YaVideo({
|
|
|
4755
5157
|
}
|
|
4756
5158
|
const resolvedSrc = resolveAssetUrl(src);
|
|
4757
5159
|
const resolvedPoster = poster ? resolveAssetUrl(poster) : void 0;
|
|
4758
|
-
return /* @__PURE__ */
|
|
5160
|
+
return /* @__PURE__ */ jsx14(
|
|
4759
5161
|
"video",
|
|
4760
5162
|
{
|
|
4761
5163
|
ref: videoRef,
|
|
@@ -4790,7 +5192,7 @@ function YaVideo({
|
|
|
4790
5192
|
);
|
|
4791
5193
|
};
|
|
4792
5194
|
if (mode === "read-only") {
|
|
4793
|
-
return /* @__PURE__ */
|
|
5195
|
+
return /* @__PURE__ */ jsx14(
|
|
4794
5196
|
"div",
|
|
4795
5197
|
{
|
|
4796
5198
|
ref: containerRef,
|
|
@@ -4818,8 +5220,8 @@ function YaVideo({
|
|
|
4818
5220
|
strokeLinecap: "round",
|
|
4819
5221
|
strokeLinejoin: "round",
|
|
4820
5222
|
children: [
|
|
4821
|
-
/* @__PURE__ */
|
|
4822
|
-
/* @__PURE__ */
|
|
5223
|
+
/* @__PURE__ */ jsx14("rect", { x: "2", y: "4", width: "15", height: "13", rx: "2", ry: "2" }),
|
|
5224
|
+
/* @__PURE__ */ jsx14("polygon", { points: "22 7 15 12 22 17 22 7", fill: "currentColor" })
|
|
4823
5225
|
]
|
|
4824
5226
|
}
|
|
4825
5227
|
);
|
|
@@ -4848,12 +5250,12 @@ function YaVideo({
|
|
|
4848
5250
|
renderVideo(false),
|
|
4849
5251
|
isSmallVideo ? /* @__PURE__ */ jsxs7(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
|
|
4850
5252
|
videoIcon,
|
|
4851
|
-
/* @__PURE__ */
|
|
5253
|
+
/* @__PURE__ */ jsx14("span", { children: "Click to edit" })
|
|
4852
5254
|
] }) : (
|
|
4853
5255
|
/* For large videos: show overlay inside the container */
|
|
4854
5256
|
/* @__PURE__ */ jsxs7("div", { className: "ya-video-overlay", children: [
|
|
4855
|
-
/* @__PURE__ */
|
|
4856
|
-
/* @__PURE__ */
|
|
5257
|
+
/* @__PURE__ */ jsx14("div", { className: "ya-video-edit-icon", children: videoIcon }),
|
|
5258
|
+
/* @__PURE__ */ jsx14("span", { className: "ya-video-edit-label", children: "Click to edit" })
|
|
4857
5259
|
] })
|
|
4858
5260
|
)
|
|
4859
5261
|
]
|
|
@@ -4862,13 +5264,13 @@ function YaVideo({
|
|
|
4862
5264
|
}
|
|
4863
5265
|
|
|
4864
5266
|
// src/components/YaEmbed.tsx
|
|
4865
|
-
import { useCallback as
|
|
5267
|
+
import { useCallback as useCallback15, useEffect as useEffect13, useRef as useRef14, useState as useState13 } from "react";
|
|
4866
5268
|
|
|
4867
5269
|
// src/components/ya-embed.css
|
|
4868
5270
|
styleInject('.ya-embed-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-embed-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-embed-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 80px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-embed-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-embed-editable {\n cursor: pointer;\n}\n.ya-embed-editable:hover {\n outline: 2px dashed var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-selected {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-embed-editable:hover .ya-embed-overlay {\n opacity: 1;\n}\n.ya-embed-selected .ya-embed-overlay {\n opacity: 0;\n}\n.ya-embed-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-embed-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-embed-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-embed-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-embed-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-embed-success {\n 0% {\n outline-color: var(--color-primary, #d4a574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #d4a574);\n outline-width: 2px;\n }\n}\n.ya-embed-success {\n animation: ya-embed-success 0.4s ease;\n}\n.ya-embed-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-embed-shimmer 1.5s infinite;\n}\n@keyframes ya-embed-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-embed-container:focus {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-embed-container:focus-visible {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-small .ya-embed-overlay {\n display: none;\n}\n.ya-embed-twitter {\n min-height: 200px;\n}\n.ya-embed-twitter .twitter-tweet {\n margin: 0 auto !important;\n}\n.ya-embed-wrapper[data-embed-type=spotify],\n.ya-embed-container[data-embed-type=spotify] {\n min-height: 80px;\n}\n.ya-embed-wrapper[data-embed-type=soundcloud],\n.ya-embed-container[data-embed-type=soundcloud] {\n min-height: 166px;\n}\n.ya-embed-wrapper[data-embed-type=instagram] iframe,\n.ya-embed-container[data-embed-type=instagram] iframe {\n min-height: 400px;\n}\n');
|
|
4869
5271
|
|
|
4870
5272
|
// src/components/YaEmbed.tsx
|
|
4871
|
-
import { jsx as
|
|
5273
|
+
import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4872
5274
|
function parseEmbedUrl(url) {
|
|
4873
5275
|
if (!url) return null;
|
|
4874
5276
|
const trimmedUrl = url.trim();
|
|
@@ -4981,20 +5383,21 @@ function YaEmbed({
|
|
|
4981
5383
|
loading = "lazy",
|
|
4982
5384
|
defaultValue
|
|
4983
5385
|
}) {
|
|
4984
|
-
const
|
|
4985
|
-
const
|
|
4986
|
-
const
|
|
4987
|
-
const [
|
|
4988
|
-
const [
|
|
4989
|
-
const [
|
|
4990
|
-
const
|
|
5386
|
+
const content = useContent(fieldId);
|
|
5387
|
+
const { mode } = content;
|
|
5388
|
+
const containerRef = useRef14(null);
|
|
5389
|
+
const [isSelected, setIsSelected] = useState13(false);
|
|
5390
|
+
const [isHovered, setIsHovered] = useState13(false);
|
|
5391
|
+
const [isSmallEmbed, setIsSmallEmbed] = useState13(false);
|
|
5392
|
+
const [isInView, setIsInView] = useState13(loading === "eager");
|
|
5393
|
+
const rawValue = content.get();
|
|
4991
5394
|
const parsedValue = parseEmbedValue(rawValue);
|
|
4992
5395
|
const embedData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
|
|
4993
5396
|
const src = embedData.src || "";
|
|
4994
5397
|
const embedType = embedData.type || "custom";
|
|
4995
5398
|
const height = embedData.height;
|
|
4996
5399
|
const aspectRatio = embedData.aspectRatio || propAspectRatio || "16/9";
|
|
4997
|
-
|
|
5400
|
+
useEffect13(() => {
|
|
4998
5401
|
if (loading === "eager" || isInView) return;
|
|
4999
5402
|
const observer = new IntersectionObserver(
|
|
5000
5403
|
(entries) => {
|
|
@@ -5011,7 +5414,7 @@ function YaEmbed({
|
|
|
5011
5414
|
}
|
|
5012
5415
|
return () => observer.disconnect();
|
|
5013
5416
|
}, [loading, isInView]);
|
|
5014
|
-
const handleClick =
|
|
5417
|
+
const handleClick = useCallback15(() => {
|
|
5015
5418
|
if (mode !== "inline-edit") return;
|
|
5016
5419
|
if (document.body.classList.contains("builder-selector-active")) return;
|
|
5017
5420
|
setIsSelected(true);
|
|
@@ -5031,7 +5434,7 @@ function YaEmbed({
|
|
|
5031
5434
|
"*"
|
|
5032
5435
|
);
|
|
5033
5436
|
}, [mode, fieldId, embedData]);
|
|
5034
|
-
|
|
5437
|
+
useEffect13(() => {
|
|
5035
5438
|
if (mode !== "inline-edit") return;
|
|
5036
5439
|
const handleMessage2 = (event) => {
|
|
5037
5440
|
if (event.data?.type === "YA_EMBED_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
|
|
@@ -5044,7 +5447,7 @@ function YaEmbed({
|
|
|
5044
5447
|
window.addEventListener("message", handleMessage2);
|
|
5045
5448
|
return () => window.removeEventListener("message", handleMessage2);
|
|
5046
5449
|
}, [mode, fieldId]);
|
|
5047
|
-
|
|
5450
|
+
useEffect13(() => {
|
|
5048
5451
|
if (mode !== "inline-edit") return;
|
|
5049
5452
|
const checkSize = () => {
|
|
5050
5453
|
if (containerRef.current) {
|
|
@@ -5056,7 +5459,7 @@ function YaEmbed({
|
|
|
5056
5459
|
window.addEventListener("resize", checkSize);
|
|
5057
5460
|
return () => window.removeEventListener("resize", checkSize);
|
|
5058
5461
|
}, [mode]);
|
|
5059
|
-
|
|
5462
|
+
useEffect13(() => {
|
|
5060
5463
|
if (!isSelected || mode !== "inline-edit") return;
|
|
5061
5464
|
let lastRectKey = "";
|
|
5062
5465
|
let lastTime = 0;
|
|
@@ -5093,16 +5496,16 @@ function YaEmbed({
|
|
|
5093
5496
|
const renderEmbed = (isReadOnly) => {
|
|
5094
5497
|
if (!src && !isReadOnly) {
|
|
5095
5498
|
return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-placeholder", children: [
|
|
5096
|
-
/* @__PURE__ */
|
|
5097
|
-
/* @__PURE__ */
|
|
5499
|
+
/* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }),
|
|
5500
|
+
/* @__PURE__ */ jsx15("span", { children: "No embed selected" })
|
|
5098
5501
|
] });
|
|
5099
5502
|
}
|
|
5100
5503
|
if (!isInView && loading === "lazy" && !isReadOnly) {
|
|
5101
|
-
return /* @__PURE__ */
|
|
5504
|
+
return /* @__PURE__ */ jsx15("div", { className: "ya-embed-placeholder", style: { aspectRatio }, children: /* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }) });
|
|
5102
5505
|
}
|
|
5103
5506
|
if (embedType === "spotify" && src) {
|
|
5104
5507
|
const embedUrl = buildSpotifyEmbedUrl(src);
|
|
5105
|
-
return /* @__PURE__ */
|
|
5508
|
+
return /* @__PURE__ */ jsx15(
|
|
5106
5509
|
"iframe",
|
|
5107
5510
|
{
|
|
5108
5511
|
src: embedUrl,
|
|
@@ -5120,7 +5523,7 @@ function YaEmbed({
|
|
|
5120
5523
|
}
|
|
5121
5524
|
if (embedType === "soundcloud" && src) {
|
|
5122
5525
|
const embedUrl = buildSoundCloudEmbedUrl(src);
|
|
5123
|
-
return /* @__PURE__ */
|
|
5526
|
+
return /* @__PURE__ */ jsx15(
|
|
5124
5527
|
"iframe",
|
|
5125
5528
|
{
|
|
5126
5529
|
src: embedUrl,
|
|
@@ -5137,13 +5540,13 @@ function YaEmbed({
|
|
|
5137
5540
|
}
|
|
5138
5541
|
if (embedType === "twitter" && src) {
|
|
5139
5542
|
return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-twitter", children: [
|
|
5140
|
-
/* @__PURE__ */
|
|
5141
|
-
/* @__PURE__ */
|
|
5543
|
+
/* @__PURE__ */ jsx15("blockquote", { className: "twitter-tweet", "data-dnt": "true", children: /* @__PURE__ */ jsx15("a", { href: embedData.originalUrl || `https://twitter.com/i/status/${src}`, children: "Loading tweet..." }) }),
|
|
5544
|
+
/* @__PURE__ */ jsx15(TwitterWidgetLoader, {})
|
|
5142
5545
|
] });
|
|
5143
5546
|
}
|
|
5144
5547
|
if (embedType === "instagram" && src) {
|
|
5145
5548
|
const embedUrl = buildInstagramEmbedUrl(src);
|
|
5146
|
-
return /* @__PURE__ */
|
|
5549
|
+
return /* @__PURE__ */ jsx15(
|
|
5147
5550
|
"iframe",
|
|
5148
5551
|
{
|
|
5149
5552
|
src: embedUrl,
|
|
@@ -5161,7 +5564,7 @@ function YaEmbed({
|
|
|
5161
5564
|
);
|
|
5162
5565
|
}
|
|
5163
5566
|
if (embedType === "custom" && src) {
|
|
5164
|
-
return /* @__PURE__ */
|
|
5567
|
+
return /* @__PURE__ */ jsx15(
|
|
5165
5568
|
"iframe",
|
|
5166
5569
|
{
|
|
5167
5570
|
src,
|
|
@@ -5185,7 +5588,7 @@ function YaEmbed({
|
|
|
5185
5588
|
maxWidth: maxWidth ? `${maxWidth}px` : void 0
|
|
5186
5589
|
};
|
|
5187
5590
|
if (mode === "read-only") {
|
|
5188
|
-
return /* @__PURE__ */
|
|
5591
|
+
return /* @__PURE__ */ jsx15(
|
|
5189
5592
|
"div",
|
|
5190
5593
|
{
|
|
5191
5594
|
ref: containerRef,
|
|
@@ -5209,8 +5612,8 @@ function YaEmbed({
|
|
|
5209
5612
|
strokeLinecap: "round",
|
|
5210
5613
|
strokeLinejoin: "round",
|
|
5211
5614
|
children: [
|
|
5212
|
-
/* @__PURE__ */
|
|
5213
|
-
/* @__PURE__ */
|
|
5615
|
+
/* @__PURE__ */ jsx15("polyline", { points: "16 18 22 12 16 6" }),
|
|
5616
|
+
/* @__PURE__ */ jsx15("polyline", { points: "8 6 2 12 8 18" })
|
|
5214
5617
|
]
|
|
5215
5618
|
}
|
|
5216
5619
|
);
|
|
@@ -5239,12 +5642,12 @@ function YaEmbed({
|
|
|
5239
5642
|
renderEmbed(false),
|
|
5240
5643
|
isSmallEmbed ? /* @__PURE__ */ jsxs8(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
|
|
5241
5644
|
embedIcon,
|
|
5242
|
-
/* @__PURE__ */
|
|
5645
|
+
/* @__PURE__ */ jsx15("span", { children: "Click to edit" })
|
|
5243
5646
|
] }) : (
|
|
5244
5647
|
/* For large embeds: show overlay inside the container */
|
|
5245
5648
|
/* @__PURE__ */ jsxs8("div", { className: "ya-embed-overlay", children: [
|
|
5246
|
-
/* @__PURE__ */
|
|
5247
|
-
/* @__PURE__ */
|
|
5649
|
+
/* @__PURE__ */ jsx15("div", { className: "ya-embed-edit-icon", children: embedIcon }),
|
|
5650
|
+
/* @__PURE__ */ jsx15("span", { className: "ya-embed-edit-label", children: "Click to edit" })
|
|
5248
5651
|
] })
|
|
5249
5652
|
)
|
|
5250
5653
|
]
|
|
@@ -5252,7 +5655,7 @@ function YaEmbed({
|
|
|
5252
5655
|
);
|
|
5253
5656
|
}
|
|
5254
5657
|
function TwitterWidgetLoader() {
|
|
5255
|
-
|
|
5658
|
+
useEffect13(() => {
|
|
5256
5659
|
if (window.twttr?.widgets) {
|
|
5257
5660
|
;
|
|
5258
5661
|
window.twttr.widgets.load();
|
|
@@ -5273,7 +5676,7 @@ function TwitterWidgetLoader() {
|
|
|
5273
5676
|
}
|
|
5274
5677
|
|
|
5275
5678
|
// src/components/YaLink.tsx
|
|
5276
|
-
import { useEffect as
|
|
5679
|
+
import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useRef as useRef17, useState as useState16, useCallback as useCallback18, useId } from "react";
|
|
5277
5680
|
import { createPortal as createPortal6 } from "react-dom";
|
|
5278
5681
|
import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
|
|
5279
5682
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
@@ -5283,7 +5686,7 @@ import { Extension as Extension2 } from "@tiptap/core";
|
|
|
5283
5686
|
import { Link as WouterLink, useLocation } from "wouter";
|
|
5284
5687
|
|
|
5285
5688
|
// src/components/SafeTriangleBelow.tsx
|
|
5286
|
-
import { useEffect as
|
|
5689
|
+
import { useEffect as useEffect14, useState as useState14, useRef as useRef15, useCallback as useCallback16 } from "react";
|
|
5287
5690
|
function SafeTriangleBelow({
|
|
5288
5691
|
triggerRef,
|
|
5289
5692
|
popoverRef,
|
|
@@ -5291,10 +5694,10 @@ function SafeTriangleBelow({
|
|
|
5291
5694
|
onLeave,
|
|
5292
5695
|
onStayInside
|
|
5293
5696
|
}) {
|
|
5294
|
-
const [bounds, setBounds] =
|
|
5295
|
-
const boundsRef =
|
|
5697
|
+
const [bounds, setBounds] = useState14(null);
|
|
5698
|
+
const boundsRef = useRef15(bounds);
|
|
5296
5699
|
boundsRef.current = bounds;
|
|
5297
|
-
|
|
5700
|
+
useEffect14(() => {
|
|
5298
5701
|
if (!isVisible || !triggerRef.current || !popoverRef.current) {
|
|
5299
5702
|
setBounds(null);
|
|
5300
5703
|
return;
|
|
@@ -5312,7 +5715,7 @@ function SafeTriangleBelow({
|
|
|
5312
5715
|
}, 10);
|
|
5313
5716
|
return () => clearTimeout(timer);
|
|
5314
5717
|
}, [isVisible, triggerRef, popoverRef]);
|
|
5315
|
-
const checkMousePosition =
|
|
5718
|
+
const checkMousePosition = useCallback16((e) => {
|
|
5316
5719
|
const b = boundsRef.current;
|
|
5317
5720
|
if (!b) return;
|
|
5318
5721
|
const { clientX: x, clientY: y } = e;
|
|
@@ -5324,7 +5727,7 @@ function SafeTriangleBelow({
|
|
|
5324
5727
|
onStayInside?.();
|
|
5325
5728
|
}
|
|
5326
5729
|
}, [onLeave, onStayInside]);
|
|
5327
|
-
|
|
5730
|
+
useEffect14(() => {
|
|
5328
5731
|
if (!isVisible || !bounds) return;
|
|
5329
5732
|
document.addEventListener("mousemove", checkMousePosition);
|
|
5330
5733
|
return () => document.removeEventListener("mousemove", checkMousePosition);
|
|
@@ -5333,22 +5736,22 @@ function SafeTriangleBelow({
|
|
|
5333
5736
|
}
|
|
5334
5737
|
|
|
5335
5738
|
// src/hooks/useSafeTriangle.ts
|
|
5336
|
-
import { useState as
|
|
5739
|
+
import { useState as useState15, useRef as useRef16, useCallback as useCallback17, useEffect as useEffect15 } from "react";
|
|
5337
5740
|
function useSafeTriangle(options = {}) {
|
|
5338
5741
|
const { showDelay = 0, hideDelay = 150, enabled = true } = options;
|
|
5339
|
-
const [isVisible, setIsVisible] =
|
|
5340
|
-
const [isHovering, setIsHovering] =
|
|
5341
|
-
const triggerRef =
|
|
5342
|
-
const popoverRef =
|
|
5343
|
-
const showTimeoutRef =
|
|
5344
|
-
const hideTimeoutRef =
|
|
5345
|
-
|
|
5742
|
+
const [isVisible, setIsVisible] = useState15(false);
|
|
5743
|
+
const [isHovering, setIsHovering] = useState15(false);
|
|
5744
|
+
const triggerRef = useRef16(null);
|
|
5745
|
+
const popoverRef = useRef16(null);
|
|
5746
|
+
const showTimeoutRef = useRef16(null);
|
|
5747
|
+
const hideTimeoutRef = useRef16(null);
|
|
5748
|
+
useEffect15(() => {
|
|
5346
5749
|
return () => {
|
|
5347
5750
|
if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
|
|
5348
5751
|
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
|
5349
5752
|
};
|
|
5350
5753
|
}, []);
|
|
5351
|
-
const show =
|
|
5754
|
+
const show = useCallback17(() => {
|
|
5352
5755
|
if (!enabled) return;
|
|
5353
5756
|
if (hideTimeoutRef.current) {
|
|
5354
5757
|
clearTimeout(hideTimeoutRef.current);
|
|
@@ -5356,7 +5759,7 @@ function useSafeTriangle(options = {}) {
|
|
|
5356
5759
|
}
|
|
5357
5760
|
setIsVisible(true);
|
|
5358
5761
|
}, [enabled]);
|
|
5359
|
-
const hide =
|
|
5762
|
+
const hide = useCallback17(() => {
|
|
5360
5763
|
if (showTimeoutRef.current) {
|
|
5361
5764
|
clearTimeout(showTimeoutRef.current);
|
|
5362
5765
|
showTimeoutRef.current = null;
|
|
@@ -5364,7 +5767,7 @@ function useSafeTriangle(options = {}) {
|
|
|
5364
5767
|
setIsVisible(false);
|
|
5365
5768
|
setIsHovering(false);
|
|
5366
5769
|
}, []);
|
|
5367
|
-
const handleMouseEnter =
|
|
5770
|
+
const handleMouseEnter = useCallback17(() => {
|
|
5368
5771
|
if (!enabled) return;
|
|
5369
5772
|
setIsHovering(true);
|
|
5370
5773
|
if (hideTimeoutRef.current) {
|
|
@@ -5379,7 +5782,7 @@ function useSafeTriangle(options = {}) {
|
|
|
5379
5782
|
setIsVisible(true);
|
|
5380
5783
|
}
|
|
5381
5784
|
}, [showDelay, enabled]);
|
|
5382
|
-
const handleMouseLeave =
|
|
5785
|
+
const handleMouseLeave = useCallback17(() => {
|
|
5383
5786
|
setIsHovering(false);
|
|
5384
5787
|
if (showTimeoutRef.current) {
|
|
5385
5788
|
clearTimeout(showTimeoutRef.current);
|
|
@@ -5389,16 +5792,16 @@ function useSafeTriangle(options = {}) {
|
|
|
5389
5792
|
setIsVisible(false);
|
|
5390
5793
|
}, hideDelay);
|
|
5391
5794
|
}, [hideDelay]);
|
|
5392
|
-
const handleFocus =
|
|
5795
|
+
const handleFocus = useCallback17(() => {
|
|
5393
5796
|
if (!enabled) return;
|
|
5394
5797
|
setIsVisible(true);
|
|
5395
5798
|
}, [enabled]);
|
|
5396
|
-
const handleTriangleLeave =
|
|
5799
|
+
const handleTriangleLeave = useCallback17(() => {
|
|
5397
5800
|
if (!isHovering) {
|
|
5398
5801
|
setIsVisible(false);
|
|
5399
5802
|
}
|
|
5400
5803
|
}, [isHovering]);
|
|
5401
|
-
const handleStayInside =
|
|
5804
|
+
const handleStayInside = useCallback17(() => {
|
|
5402
5805
|
if (hideTimeoutRef.current) {
|
|
5403
5806
|
clearTimeout(hideTimeoutRef.current);
|
|
5404
5807
|
hideTimeoutRef.current = null;
|
|
@@ -5429,7 +5832,7 @@ function useSafeTriangle(options = {}) {
|
|
|
5429
5832
|
styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-editing .ProseMirror {\n color: #1a1a1a !important;\n caret-color: #1a1a1a;\n}\n.ya-link-editing .ProseMirror p::selection,\n.ya-link-editing .ProseMirror::selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ya-link-editing .ProseMirror p::-moz-selection,\n.ya-link-editing .ProseMirror::-moz-selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ProseMirror-gapcursor {\n display: none !important;\n}\n.ProseMirror .ProseMirror-dropcursor {\n display: none !important;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::selection {\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::-moz-selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::-moz-selection {\n color: inherit;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n z-index: 9999;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: fixed;\n z-index: 10000;\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 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 }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n animation: ya-href-popover-fade-in-above 0.15s ease;\n}\n@keyframes ya-href-popover-fade-in-above {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n.ya-link-edit-popover {\n position: fixed;\n z-index: 10000;\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 transition: opacity 100ms ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\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');
|
|
5430
5833
|
|
|
5431
5834
|
// src/components/YaLink.tsx
|
|
5432
|
-
import { Fragment as Fragment4, jsx as
|
|
5835
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5433
5836
|
function isInternalPath(path) {
|
|
5434
5837
|
if (!path) return false;
|
|
5435
5838
|
if (path.startsWith("#")) return false;
|
|
@@ -5527,37 +5930,40 @@ function discoverSectionsFromDOM() {
|
|
|
5527
5930
|
return sections;
|
|
5528
5931
|
}
|
|
5529
5932
|
function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName, style, as: Component = "a", children, availablePages, onClick, target, rel }) {
|
|
5530
|
-
const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
|
|
5531
|
-
const [, navigate] = useLocation();
|
|
5532
|
-
const pages = availablePages ?? getPages();
|
|
5533
|
-
const [sections, setSections] = useState15([]);
|
|
5534
|
-
const [sectionsExpanded, setSectionsExpanded] = useState15(false);
|
|
5535
5933
|
const textFieldId = `${fieldId}.text`;
|
|
5536
5934
|
const hrefFieldId = `${fieldId}.href`;
|
|
5537
|
-
const
|
|
5538
|
-
const
|
|
5935
|
+
const textContent = useContent(textFieldId);
|
|
5936
|
+
const hrefContent = useContent(hrefFieldId);
|
|
5937
|
+
const { mode } = textContent;
|
|
5938
|
+
const { getPages } = useContentStore();
|
|
5939
|
+
const [, navigate] = useLocation();
|
|
5940
|
+
const pages = availablePages ?? getPages();
|
|
5941
|
+
const [sections, setSections] = useState16([]);
|
|
5942
|
+
const [sectionsExpanded, setSectionsExpanded] = useState16(false);
|
|
5943
|
+
const storeText = textContent.get();
|
|
5944
|
+
const storeHref = hrefContent.get();
|
|
5539
5945
|
const isIconMode = children != null && typeof children !== "string";
|
|
5540
5946
|
const text2 = storeText || (typeof children === "string" ? children : "");
|
|
5541
5947
|
const href = storeHref || defaultHref;
|
|
5542
5948
|
const isExternal = isExternalHref(href);
|
|
5543
5949
|
const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
|
|
5544
5950
|
const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
|
|
5545
|
-
const [editingMode, setEditingMode] =
|
|
5546
|
-
const [originalText, setOriginalText] =
|
|
5547
|
-
const [originalHref, setOriginalHref] =
|
|
5548
|
-
const [currentHref, setCurrentHref] =
|
|
5549
|
-
const [isExternalUrl, setIsExternalUrl] =
|
|
5550
|
-
const [externalUrl, setExternalUrl] =
|
|
5551
|
-
const containerRef =
|
|
5552
|
-
const hrefPopoverRef =
|
|
5553
|
-
const [actionButtonsPos, setActionButtonsPos] =
|
|
5554
|
-
const [editPopoverPos, setEditPopoverPos] =
|
|
5555
|
-
const [editPopoverVisible, setEditPopoverVisible] =
|
|
5556
|
-
const [editPopoverMounted, setEditPopoverMounted] =
|
|
5557
|
-
const [hrefPopoverPos, setHrefPopoverPos] =
|
|
5558
|
-
const handleSaveTextRef =
|
|
5951
|
+
const [editingMode, setEditingMode] = useState16(null);
|
|
5952
|
+
const [originalText, setOriginalText] = useState16(text2);
|
|
5953
|
+
const [originalHref, setOriginalHref] = useState16(href);
|
|
5954
|
+
const [currentHref, setCurrentHref] = useState16(href);
|
|
5955
|
+
const [isExternalUrl, setIsExternalUrl] = useState16(false);
|
|
5956
|
+
const [externalUrl, setExternalUrl] = useState16("");
|
|
5957
|
+
const containerRef = useRef17(null);
|
|
5958
|
+
const hrefPopoverRef = useRef17(null);
|
|
5959
|
+
const [actionButtonsPos, setActionButtonsPos] = useState16(null);
|
|
5960
|
+
const [editPopoverPos, setEditPopoverPos] = useState16(null);
|
|
5961
|
+
const [editPopoverVisible, setEditPopoverVisible] = useState16(false);
|
|
5962
|
+
const [editPopoverMounted, setEditPopoverMounted] = useState16(false);
|
|
5963
|
+
const [hrefPopoverPos, setHrefPopoverPos] = useState16(null);
|
|
5964
|
+
const handleSaveTextRef = useRef17(() => {
|
|
5559
5965
|
});
|
|
5560
|
-
const handleCancelTextRef =
|
|
5966
|
+
const handleCancelTextRef = useRef17(() => {
|
|
5561
5967
|
});
|
|
5562
5968
|
const {
|
|
5563
5969
|
popoverRef: editPopoverRef,
|
|
@@ -5571,12 +5977,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5571
5977
|
});
|
|
5572
5978
|
const triggerRef = containerRef;
|
|
5573
5979
|
const instanceId = useId();
|
|
5574
|
-
|
|
5980
|
+
useEffect16(() => {
|
|
5575
5981
|
if (showEditPopover && mode === "inline-edit" && !editingMode) {
|
|
5576
5982
|
window.dispatchEvent(new CustomEvent("yalink:popover-open", { detail: { id: instanceId } }));
|
|
5577
5983
|
}
|
|
5578
5984
|
}, [showEditPopover, mode, editingMode, instanceId]);
|
|
5579
|
-
|
|
5985
|
+
useEffect16(() => {
|
|
5580
5986
|
const handleOtherPopoverOpen = (event) => {
|
|
5581
5987
|
const customEvent = event;
|
|
5582
5988
|
if (customEvent.detail.id !== instanceId && showEditPopover) {
|
|
@@ -5630,19 +6036,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5630
6036
|
}
|
|
5631
6037
|
}
|
|
5632
6038
|
});
|
|
5633
|
-
|
|
6039
|
+
useEffect16(() => {
|
|
5634
6040
|
if (editor && editingMode !== "text") {
|
|
5635
6041
|
if (editor.getHTML() !== text2) {
|
|
5636
6042
|
editor.commands.setContent(text2);
|
|
5637
6043
|
}
|
|
5638
6044
|
}
|
|
5639
6045
|
}, [text2, editor, editingMode]);
|
|
5640
|
-
|
|
6046
|
+
useEffect16(() => {
|
|
5641
6047
|
if (editingMode !== "link") {
|
|
5642
6048
|
setCurrentHref(href);
|
|
5643
6049
|
}
|
|
5644
6050
|
}, [href, editingMode]);
|
|
5645
|
-
|
|
6051
|
+
useEffect16(() => {
|
|
5646
6052
|
if (editingMode !== "text" || !containerRef.current) {
|
|
5647
6053
|
setActionButtonsPos(null);
|
|
5648
6054
|
return;
|
|
@@ -5663,7 +6069,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5663
6069
|
window.removeEventListener("resize", updatePosition);
|
|
5664
6070
|
};
|
|
5665
6071
|
}, [editingMode]);
|
|
5666
|
-
|
|
6072
|
+
useEffect16(() => {
|
|
5667
6073
|
const shouldShow = showEditPopover && !editingMode && mode === "inline-edit";
|
|
5668
6074
|
if (shouldShow) {
|
|
5669
6075
|
setEditPopoverMounted(true);
|
|
@@ -5725,7 +6131,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5725
6131
|
window.removeEventListener("resize", updatePosition);
|
|
5726
6132
|
};
|
|
5727
6133
|
}, [editingMode]);
|
|
5728
|
-
|
|
6134
|
+
useEffect16(() => {
|
|
5729
6135
|
if (editingMode !== "link") return;
|
|
5730
6136
|
const handleClickOutside = (event) => {
|
|
5731
6137
|
const target2 = event.target;
|
|
@@ -5739,38 +6145,38 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5739
6145
|
document.addEventListener("mousedown", handleClickOutside);
|
|
5740
6146
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
5741
6147
|
}, [editingMode, originalHref]);
|
|
5742
|
-
const handleSaveText =
|
|
6148
|
+
const handleSaveText = useCallback18(() => {
|
|
5743
6149
|
if (!editor) return;
|
|
5744
6150
|
let html = editor.getHTML();
|
|
5745
6151
|
html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
|
|
5746
|
-
|
|
5747
|
-
|
|
6152
|
+
textContent.set(html, "user");
|
|
6153
|
+
textContent.save();
|
|
5748
6154
|
setEditingMode(null);
|
|
5749
|
-
}, [editor,
|
|
5750
|
-
const handleSaveLink =
|
|
5751
|
-
|
|
5752
|
-
|
|
6155
|
+
}, [editor, textContent]);
|
|
6156
|
+
const handleSaveLink = useCallback18(() => {
|
|
6157
|
+
hrefContent.set(currentHref, "user");
|
|
6158
|
+
hrefContent.save();
|
|
5753
6159
|
setEditingMode(null);
|
|
5754
6160
|
setIsExternalUrl(false);
|
|
5755
6161
|
setExternalUrl("");
|
|
5756
|
-
}, [
|
|
5757
|
-
const handleCancelText =
|
|
6162
|
+
}, [currentHref, hrefContent]);
|
|
6163
|
+
const handleCancelText = useCallback18(() => {
|
|
5758
6164
|
if (editor) {
|
|
5759
6165
|
editor.commands.setContent(originalText);
|
|
5760
6166
|
}
|
|
5761
6167
|
setEditingMode(null);
|
|
5762
6168
|
}, [editor, originalText]);
|
|
5763
|
-
const handleCancelLink =
|
|
6169
|
+
const handleCancelLink = useCallback18(() => {
|
|
5764
6170
|
setCurrentHref(originalHref);
|
|
5765
6171
|
setEditingMode(null);
|
|
5766
6172
|
setIsExternalUrl(false);
|
|
5767
6173
|
setExternalUrl("");
|
|
5768
6174
|
}, [originalHref]);
|
|
5769
|
-
|
|
6175
|
+
useEffect16(() => {
|
|
5770
6176
|
handleSaveTextRef.current = handleSaveText;
|
|
5771
6177
|
handleCancelTextRef.current = handleCancelText;
|
|
5772
6178
|
}, [handleSaveText, handleCancelText]);
|
|
5773
|
-
const handleClick =
|
|
6179
|
+
const handleClick = useCallback18(
|
|
5774
6180
|
(e) => {
|
|
5775
6181
|
const selectModeEnabled = window.__builderSelectModeEnabled;
|
|
5776
6182
|
if (selectModeEnabled) {
|
|
@@ -5802,7 +6208,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5802
6208
|
},
|
|
5803
6209
|
[href, navigate, onClick]
|
|
5804
6210
|
);
|
|
5805
|
-
const startEditText =
|
|
6211
|
+
const startEditText = useCallback18(() => {
|
|
5806
6212
|
hideEditPopover();
|
|
5807
6213
|
if (isIconMode) {
|
|
5808
6214
|
window.dispatchEvent(new CustomEvent("yatext:edit-mode", {
|
|
@@ -5816,14 +6222,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5816
6222
|
}, 20);
|
|
5817
6223
|
}
|
|
5818
6224
|
}, [text2, editor, hideEditPopover, isIconMode, fieldId]);
|
|
5819
|
-
const startEditLink =
|
|
6225
|
+
const startEditLink = useCallback18(() => {
|
|
5820
6226
|
hideEditPopover();
|
|
5821
6227
|
setEditingMode("link");
|
|
5822
6228
|
setOriginalHref(href);
|
|
5823
6229
|
setCurrentHref(href);
|
|
5824
6230
|
setSections(discoverSectionsFromDOM());
|
|
5825
6231
|
}, [href, hideEditPopover]);
|
|
5826
|
-
const handleKeyDown =
|
|
6232
|
+
const handleKeyDown = useCallback18(
|
|
5827
6233
|
(event) => {
|
|
5828
6234
|
if (editingMode !== "text") return;
|
|
5829
6235
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
@@ -5844,7 +6250,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5844
6250
|
},
|
|
5845
6251
|
[editingMode, handleSaveText, handleCancelText]
|
|
5846
6252
|
);
|
|
5847
|
-
const handleFontSizeChange =
|
|
6253
|
+
const handleFontSizeChange = useCallback18(
|
|
5848
6254
|
(e) => {
|
|
5849
6255
|
if (!editor) return;
|
|
5850
6256
|
const size = e.target.value;
|
|
@@ -5856,7 +6262,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5856
6262
|
},
|
|
5857
6263
|
[editor]
|
|
5858
6264
|
);
|
|
5859
|
-
const handleFontWeightChange =
|
|
6265
|
+
const handleFontWeightChange = useCallback18(
|
|
5860
6266
|
(e) => {
|
|
5861
6267
|
if (!editor) return;
|
|
5862
6268
|
const weight = e.target.value;
|
|
@@ -5868,11 +6274,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5868
6274
|
},
|
|
5869
6275
|
[editor]
|
|
5870
6276
|
);
|
|
5871
|
-
const handlePageSelect =
|
|
6277
|
+
const handlePageSelect = useCallback18((path) => {
|
|
5872
6278
|
setCurrentHref(path);
|
|
5873
6279
|
setIsExternalUrl(false);
|
|
5874
6280
|
}, []);
|
|
5875
|
-
const handleExternalUrlApply =
|
|
6281
|
+
const handleExternalUrlApply = useCallback18(() => {
|
|
5876
6282
|
if (externalUrl) {
|
|
5877
6283
|
setCurrentHref(externalUrl);
|
|
5878
6284
|
}
|
|
@@ -5888,9 +6294,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5888
6294
|
return attrs.fontWeight || "";
|
|
5889
6295
|
};
|
|
5890
6296
|
if (mode === "read-only") {
|
|
5891
|
-
const content = isIconMode ? children : /* @__PURE__ */
|
|
6297
|
+
const content = isIconMode ? children : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode });
|
|
5892
6298
|
if (isInternalPath(href)) {
|
|
5893
|
-
return /* @__PURE__ */
|
|
6299
|
+
return /* @__PURE__ */ jsx16(
|
|
5894
6300
|
WouterLink,
|
|
5895
6301
|
{
|
|
5896
6302
|
href,
|
|
@@ -5902,7 +6308,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5902
6308
|
}
|
|
5903
6309
|
);
|
|
5904
6310
|
}
|
|
5905
|
-
return /* @__PURE__ */
|
|
6311
|
+
return /* @__PURE__ */ jsx16(
|
|
5906
6312
|
Component,
|
|
5907
6313
|
{
|
|
5908
6314
|
ref: containerRef,
|
|
@@ -5918,7 +6324,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5918
6324
|
);
|
|
5919
6325
|
}
|
|
5920
6326
|
return /* @__PURE__ */ jsxs9("span", { className: `ya-link-wrapper ${wrapperClassName || ""}`, children: [
|
|
5921
|
-
/* @__PURE__ */
|
|
6327
|
+
/* @__PURE__ */ jsx16(
|
|
5922
6328
|
Component,
|
|
5923
6329
|
{
|
|
5924
6330
|
ref: containerRef,
|
|
@@ -5947,27 +6353,27 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5947
6353
|
options: { offset: 6, placement: "top" },
|
|
5948
6354
|
className: "ya-bubble-menu",
|
|
5949
6355
|
children: [
|
|
5950
|
-
/* @__PURE__ */
|
|
6356
|
+
/* @__PURE__ */ jsx16(
|
|
5951
6357
|
"button",
|
|
5952
6358
|
{
|
|
5953
6359
|
type: "button",
|
|
5954
6360
|
onClick: () => editor.chain().focus().toggleBold().run(),
|
|
5955
6361
|
className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
|
|
5956
6362
|
title: "Bold",
|
|
5957
|
-
children: /* @__PURE__ */
|
|
6363
|
+
children: /* @__PURE__ */ jsx16("strong", { children: "B" })
|
|
5958
6364
|
}
|
|
5959
6365
|
),
|
|
5960
|
-
/* @__PURE__ */
|
|
6366
|
+
/* @__PURE__ */ jsx16(
|
|
5961
6367
|
"button",
|
|
5962
6368
|
{
|
|
5963
6369
|
type: "button",
|
|
5964
6370
|
onClick: () => editor.chain().focus().toggleItalic().run(),
|
|
5965
6371
|
className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
|
|
5966
6372
|
title: "Italic",
|
|
5967
|
-
children: /* @__PURE__ */
|
|
6373
|
+
children: /* @__PURE__ */ jsx16("em", { children: "I" })
|
|
5968
6374
|
}
|
|
5969
6375
|
),
|
|
5970
|
-
/* @__PURE__ */
|
|
6376
|
+
/* @__PURE__ */ jsx16("span", { className: "ya-bubble-divider" }),
|
|
5971
6377
|
/* @__PURE__ */ jsxs9(
|
|
5972
6378
|
"select",
|
|
5973
6379
|
{
|
|
@@ -5976,8 +6382,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5976
6382
|
className: "ya-bubble-select",
|
|
5977
6383
|
title: "Font Size",
|
|
5978
6384
|
children: [
|
|
5979
|
-
/* @__PURE__ */
|
|
5980
|
-
Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */
|
|
6385
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "Size" }),
|
|
6386
|
+
Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx16("option", { value: size, children: name }, name))
|
|
5981
6387
|
]
|
|
5982
6388
|
}
|
|
5983
6389
|
),
|
|
@@ -5989,8 +6395,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
5989
6395
|
className: "ya-bubble-select",
|
|
5990
6396
|
title: "Font Weight",
|
|
5991
6397
|
children: [
|
|
5992
|
-
/* @__PURE__ */
|
|
5993
|
-
Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */
|
|
6398
|
+
/* @__PURE__ */ jsx16("option", { value: "", children: "Weight" }),
|
|
6399
|
+
Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx16("option", { value: weight, children: name }, name))
|
|
5994
6400
|
]
|
|
5995
6401
|
}
|
|
5996
6402
|
)
|
|
@@ -6000,7 +6406,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6000
6406
|
document.body
|
|
6001
6407
|
),
|
|
6002
6408
|
editingMode === "text" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
6003
|
-
/* @__PURE__ */
|
|
6409
|
+
/* @__PURE__ */ jsx16(EditorContent2, { editor }),
|
|
6004
6410
|
actionButtonsPos && createPortal6(
|
|
6005
6411
|
/* @__PURE__ */ jsxs9(
|
|
6006
6412
|
"div",
|
|
@@ -6012,15 +6418,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6012
6418
|
right: actionButtonsPos.right
|
|
6013
6419
|
},
|
|
6014
6420
|
children: [
|
|
6015
|
-
/* @__PURE__ */
|
|
6016
|
-
/* @__PURE__ */
|
|
6421
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
|
|
6422
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
|
|
6017
6423
|
]
|
|
6018
6424
|
}
|
|
6019
6425
|
),
|
|
6020
6426
|
document.body
|
|
6021
6427
|
)
|
|
6022
|
-
] }) : /* @__PURE__ */
|
|
6023
|
-
] }) : /* @__PURE__ */
|
|
6428
|
+
] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
|
|
6429
|
+
] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
|
|
6024
6430
|
}
|
|
6025
6431
|
),
|
|
6026
6432
|
editPopoverMounted && editPopoverPos && createPortal6(
|
|
@@ -6038,14 +6444,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6038
6444
|
onMouseEnter: safeTriangleHandlers.onMouseEnter,
|
|
6039
6445
|
onMouseLeave: safeTriangleHandlers.onMouseLeave,
|
|
6040
6446
|
children: [
|
|
6041
|
-
/* @__PURE__ */
|
|
6042
|
-
/* @__PURE__ */
|
|
6447
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditText, children: "Edit text" }),
|
|
6448
|
+
/* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditLink, children: "Edit link" })
|
|
6043
6449
|
]
|
|
6044
6450
|
}
|
|
6045
6451
|
),
|
|
6046
6452
|
document.body
|
|
6047
6453
|
),
|
|
6048
|
-
/* @__PURE__ */
|
|
6454
|
+
/* @__PURE__ */ jsx16(
|
|
6049
6455
|
SafeTriangleBelow,
|
|
6050
6456
|
{
|
|
6051
6457
|
triggerRef,
|
|
@@ -6068,7 +6474,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6068
6474
|
transform: "translateX(-50%)"
|
|
6069
6475
|
},
|
|
6070
6476
|
children: [
|
|
6071
|
-
/* @__PURE__ */
|
|
6477
|
+
/* @__PURE__ */ jsx16("div", { className: "ya-href-popover-header", children: "Link destination" }),
|
|
6072
6478
|
!isExternalUrl ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
6073
6479
|
sections.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
|
|
6074
6480
|
/* @__PURE__ */ jsxs9(
|
|
@@ -6078,14 +6484,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6078
6484
|
className: "ya-href-popover-label ya-href-collapsible-header",
|
|
6079
6485
|
onClick: () => setSectionsExpanded(!sectionsExpanded),
|
|
6080
6486
|
children: [
|
|
6081
|
-
/* @__PURE__ */
|
|
6487
|
+
/* @__PURE__ */ jsx16("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
|
|
6082
6488
|
"Scroll to section (",
|
|
6083
6489
|
sections.length,
|
|
6084
6490
|
")"
|
|
6085
6491
|
]
|
|
6086
6492
|
}
|
|
6087
6493
|
),
|
|
6088
|
-
sectionsExpanded && /* @__PURE__ */
|
|
6494
|
+
sectionsExpanded && /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs9(
|
|
6089
6495
|
"button",
|
|
6090
6496
|
{
|
|
6091
6497
|
type: "button",
|
|
@@ -6093,15 +6499,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6093
6499
|
onClick: () => handlePageSelect(section.path),
|
|
6094
6500
|
children: [
|
|
6095
6501
|
section.label,
|
|
6096
|
-
/* @__PURE__ */
|
|
6502
|
+
/* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: section.path })
|
|
6097
6503
|
]
|
|
6098
6504
|
},
|
|
6099
6505
|
section.path
|
|
6100
6506
|
)) })
|
|
6101
6507
|
] }),
|
|
6102
6508
|
pages.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
|
|
6103
|
-
/* @__PURE__ */
|
|
6104
|
-
/* @__PURE__ */
|
|
6509
|
+
/* @__PURE__ */ jsx16("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
|
|
6510
|
+
/* @__PURE__ */ jsx16("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs9(
|
|
6105
6511
|
"button",
|
|
6106
6512
|
{
|
|
6107
6513
|
type: "button",
|
|
@@ -6109,13 +6515,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6109
6515
|
onClick: () => handlePageSelect(page.path),
|
|
6110
6516
|
children: [
|
|
6111
6517
|
page.label,
|
|
6112
|
-
/* @__PURE__ */
|
|
6518
|
+
/* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: page.path })
|
|
6113
6519
|
]
|
|
6114
6520
|
},
|
|
6115
6521
|
page.path
|
|
6116
6522
|
)) })
|
|
6117
6523
|
] }),
|
|
6118
|
-
/* @__PURE__ */
|
|
6524
|
+
/* @__PURE__ */ jsx16(
|
|
6119
6525
|
"button",
|
|
6120
6526
|
{
|
|
6121
6527
|
type: "button",
|
|
@@ -6129,8 +6535,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6129
6535
|
)
|
|
6130
6536
|
] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
6131
6537
|
/* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
|
|
6132
|
-
/* @__PURE__ */
|
|
6133
|
-
/* @__PURE__ */
|
|
6538
|
+
/* @__PURE__ */ jsx16("label", { className: "ya-href-popover-label", children: "External URL" }),
|
|
6539
|
+
/* @__PURE__ */ jsx16(
|
|
6134
6540
|
"input",
|
|
6135
6541
|
{
|
|
6136
6542
|
type: "url",
|
|
@@ -6142,11 +6548,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6142
6548
|
}
|
|
6143
6549
|
)
|
|
6144
6550
|
] }),
|
|
6145
|
-
/* @__PURE__ */
|
|
6551
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
|
|
6146
6552
|
] }),
|
|
6147
6553
|
/* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-actions", children: [
|
|
6148
|
-
/* @__PURE__ */
|
|
6149
|
-
isExternalUrl ? /* @__PURE__ */
|
|
6554
|
+
/* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
|
|
6555
|
+
isExternalUrl ? /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
|
|
6150
6556
|
] })
|
|
6151
6557
|
]
|
|
6152
6558
|
}
|
|
@@ -6157,34 +6563,34 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
|
|
|
6157
6563
|
}
|
|
6158
6564
|
|
|
6159
6565
|
// src/components/YaContainer.tsx
|
|
6160
|
-
import { useCallback as
|
|
6566
|
+
import { useCallback as useCallback20, useEffect as useEffect18, useRef as useRef19, useState as useState18 } from "react";
|
|
6161
6567
|
import { createPortal as createPortal8 } from "react-dom";
|
|
6162
6568
|
|
|
6163
6569
|
// src/components/Tooltip.tsx
|
|
6164
|
-
import { useState as
|
|
6570
|
+
import { useState as useState17, useRef as useRef18, useEffect as useEffect17, useLayoutEffect as useLayoutEffect4, useCallback as useCallback19 } from "react";
|
|
6165
6571
|
import { createPortal as createPortal7 } from "react-dom";
|
|
6166
6572
|
|
|
6167
6573
|
// src/components/tooltip.css
|
|
6168
6574
|
styleInject('.ya-tooltip-trigger {\n display: inline-flex;\n}\n.ya-tooltip-v2 {\n position: fixed;\n z-index: 10000;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n animation: ya-tooltip-v2-fade-in 0.15s ease-out;\n}\n@keyframes ya-tooltip-v2-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-tooltip-v2-arrow {\n position: absolute;\n width: 0;\n height: 0;\n left: 50%;\n transform: translateX(-50%);\n}\n.ya-tooltip-v2-bottom .ya-tooltip-v2-arrow {\n top: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-top .ya-tooltip-v2-arrow {\n bottom: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-left .ya-tooltip-v2-arrow {\n right: -6px;\n left: auto;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-left: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-right .ya-tooltip-v2-arrow {\n left: -6px;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-right: 6px solid #1a1a1a;\n}\n');
|
|
6169
6575
|
|
|
6170
6576
|
// src/components/Tooltip.tsx
|
|
6171
|
-
import { Fragment as Fragment5, jsx as
|
|
6577
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
6172
6578
|
function Tooltip({
|
|
6173
6579
|
content,
|
|
6174
6580
|
children,
|
|
6175
6581
|
position = "bottom",
|
|
6176
6582
|
delay = 0
|
|
6177
6583
|
}) {
|
|
6178
|
-
const [isVisible, setIsVisible] =
|
|
6179
|
-
const [tooltipPosition, setTooltipPosition] =
|
|
6180
|
-
const [isMounted, setIsMounted] =
|
|
6181
|
-
const triggerRef =
|
|
6182
|
-
const tooltipRef =
|
|
6183
|
-
const timeoutRef =
|
|
6184
|
-
|
|
6584
|
+
const [isVisible, setIsVisible] = useState17(false);
|
|
6585
|
+
const [tooltipPosition, setTooltipPosition] = useState17(null);
|
|
6586
|
+
const [isMounted, setIsMounted] = useState17(false);
|
|
6587
|
+
const triggerRef = useRef18(null);
|
|
6588
|
+
const tooltipRef = useRef18(null);
|
|
6589
|
+
const timeoutRef = useRef18(null);
|
|
6590
|
+
useEffect17(() => {
|
|
6185
6591
|
setIsMounted(true);
|
|
6186
6592
|
}, []);
|
|
6187
|
-
const calculatePosition =
|
|
6593
|
+
const calculatePosition = useCallback19(() => {
|
|
6188
6594
|
if (!triggerRef.current) return null;
|
|
6189
6595
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
6190
6596
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
@@ -6269,7 +6675,7 @@ function Tooltip({
|
|
|
6269
6675
|
setIsVisible(false);
|
|
6270
6676
|
setTooltipPosition(null);
|
|
6271
6677
|
};
|
|
6272
|
-
|
|
6678
|
+
useEffect17(() => {
|
|
6273
6679
|
return () => {
|
|
6274
6680
|
if (timeoutRef.current) {
|
|
6275
6681
|
clearTimeout(timeoutRef.current);
|
|
@@ -6342,7 +6748,7 @@ function Tooltip({
|
|
|
6342
6748
|
role: "tooltip",
|
|
6343
6749
|
children: [
|
|
6344
6750
|
content,
|
|
6345
|
-
/* @__PURE__ */
|
|
6751
|
+
/* @__PURE__ */ jsx17(
|
|
6346
6752
|
"div",
|
|
6347
6753
|
{
|
|
6348
6754
|
className: "ya-tooltip-v2-arrow",
|
|
@@ -6355,7 +6761,7 @@ function Tooltip({
|
|
|
6355
6761
|
document.body
|
|
6356
6762
|
) : null;
|
|
6357
6763
|
return /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
6358
|
-
/* @__PURE__ */
|
|
6764
|
+
/* @__PURE__ */ jsx17(
|
|
6359
6765
|
"div",
|
|
6360
6766
|
{
|
|
6361
6767
|
ref: triggerRef,
|
|
@@ -6373,7 +6779,7 @@ function Tooltip({
|
|
|
6373
6779
|
styleInject('.ya-container {\n position: relative;\n}\n.ya-container-has-overlay::after {\n content: "";\n position: absolute;\n inset: 0;\n background: var(--ya-overlay-color, transparent);\n opacity: var(--ya-overlay-opacity, 0);\n pointer-events: none;\n z-index: 0;\n}\n.ya-container > *:not(.ya-container-toolbar) {\n position: relative;\n z-index: 1;\n}\n.ya-container-editable {\n transition: outline 0.15s ease;\n pointer-events: none;\n}\n.ya-container-editable > * {\n pointer-events: auto;\n}\n.ya-container-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: -2px;\n}\nbody.builder-selector-active .ya-container-editable:hover {\n outline: none;\n}\n.ya-container-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar {\n display: flex;\n gap: 4px;\n background: rgba(26, 26, 26, 0.95);\n padding: 6px 8px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: ya-container-toolbar-fade-in 0.15s ease;\n}\n@keyframes ya-container-toolbar-fade-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ya-container-toolbar button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: #3a3a3a;\n border: none;\n border-radius: 6px;\n color: #ffffff;\n cursor: pointer;\n transition: background 0.15s ease, transform 0.1s ease;\n}\n.ya-container-toolbar button:hover {\n background: #4a4a4a;\n transform: scale(1.05);\n}\n.ya-container-toolbar button:active {\n transform: scale(0.98);\n}\n.ya-container-toolbar button.active {\n background: var(--color-primary, #D4A574);\n color: #1a1a1a;\n}\n.ya-container-toolbar button svg {\n width: 18px;\n height: 18px;\n}\n.ya-container-toolbar button[aria-label="Clear background"] {\n background: #3a2a2a;\n}\n.ya-container-toolbar button[aria-label="Clear background"]:hover {\n background: #5a3a3a;\n}\n.ya-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar button:focus-visible {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 2px;\n}\n.ya-container-drop-target {\n outline: 2px dashed var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -2px;\n pointer-events: auto !important;\n}\n.ya-container-drop-target .ya-container-toolbar {\n display: none !important;\n}\n.ya-container-drop-hover {\n outline: 3px solid var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -3px;\n}\n.ya-container-drop-hover::before {\n content: "";\n position: absolute;\n inset: 0;\n background: rgba(59, 130, 246, 0.08);\n pointer-events: none;\n z-index: 10;\n animation: ya-container-drop-pulse 1s ease-in-out infinite;\n}\n@keyframes ya-container-drop-pulse {\n 0%, 100% {\n background: rgba(59, 130, 246, 0.05);\n }\n 50% {\n background: rgba(59, 130, 246, 0.12);\n }\n}\n.ya-container-tooltip {\n background: #1a1a1a;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n z-index: 10000;\n pointer-events: none;\n animation: ya-container-tooltip-fade-in 0.1s ease;\n}\n@keyframes ya-container-tooltip-fade-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n');
|
|
6374
6780
|
|
|
6375
6781
|
// src/components/YaContainer.tsx
|
|
6376
|
-
import { jsx as
|
|
6782
|
+
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
6377
6783
|
function parseBackgroundConfig(value) {
|
|
6378
6784
|
if (!value) {
|
|
6379
6785
|
return { type: "none" };
|
|
@@ -6415,8 +6821,8 @@ function deriveContainerLabel(element) {
|
|
|
6415
6821
|
return tagLabels[tagName] || "Section";
|
|
6416
6822
|
}
|
|
6417
6823
|
function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAIClick, onClearClick, hasBackground }) {
|
|
6418
|
-
const [position, setPosition] =
|
|
6419
|
-
|
|
6824
|
+
const [position, setPosition] = useState18(null);
|
|
6825
|
+
useEffect18(() => {
|
|
6420
6826
|
const updatePosition = () => {
|
|
6421
6827
|
if (containerRef.current) {
|
|
6422
6828
|
const rect = containerRef.current.getBoundingClientRect();
|
|
@@ -6447,40 +6853,40 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAICli
|
|
|
6447
6853
|
},
|
|
6448
6854
|
onClick: (e) => e.stopPropagation(),
|
|
6449
6855
|
children: [
|
|
6450
|
-
/* @__PURE__ */
|
|
6856
|
+
/* @__PURE__ */ jsx18(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx18(
|
|
6451
6857
|
"button",
|
|
6452
6858
|
{
|
|
6453
6859
|
type: "button",
|
|
6454
6860
|
onClick: onImageClick,
|
|
6455
6861
|
"aria-label": "Edit background image",
|
|
6456
6862
|
children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
6457
|
-
/* @__PURE__ */
|
|
6458
|
-
/* @__PURE__ */
|
|
6459
|
-
/* @__PURE__ */
|
|
6863
|
+
/* @__PURE__ */ jsx18("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
6864
|
+
/* @__PURE__ */ jsx18("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
6865
|
+
/* @__PURE__ */ jsx18("polyline", { points: "21 15 16 10 5 21" })
|
|
6460
6866
|
] })
|
|
6461
6867
|
}
|
|
6462
6868
|
) }),
|
|
6463
|
-
/* @__PURE__ */
|
|
6869
|
+
/* @__PURE__ */ jsx18(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx18(
|
|
6464
6870
|
"button",
|
|
6465
6871
|
{
|
|
6466
6872
|
type: "button",
|
|
6467
6873
|
onClick: onColorClick,
|
|
6468
6874
|
"aria-label": "Edit background color",
|
|
6469
6875
|
children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
6470
|
-
/* @__PURE__ */
|
|
6471
|
-
/* @__PURE__ */
|
|
6876
|
+
/* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "10" }),
|
|
6877
|
+
/* @__PURE__ */ jsx18("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
|
|
6472
6878
|
] })
|
|
6473
6879
|
}
|
|
6474
6880
|
) }),
|
|
6475
|
-
hasBackground && /* @__PURE__ */
|
|
6881
|
+
hasBackground && /* @__PURE__ */ jsx18(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx18(
|
|
6476
6882
|
"button",
|
|
6477
6883
|
{
|
|
6478
6884
|
type: "button",
|
|
6479
6885
|
onClick: onClearClick,
|
|
6480
6886
|
"aria-label": "Clear background",
|
|
6481
6887
|
children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
6482
|
-
/* @__PURE__ */
|
|
6483
|
-
/* @__PURE__ */
|
|
6888
|
+
/* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "10" }),
|
|
6889
|
+
/* @__PURE__ */ jsx18("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
|
|
6484
6890
|
] })
|
|
6485
6891
|
}
|
|
6486
6892
|
) })
|
|
@@ -6499,13 +6905,13 @@ function YaContainer({
|
|
|
6499
6905
|
defaultBackground
|
|
6500
6906
|
}) {
|
|
6501
6907
|
const { getValue, setValue, saveToWorker, mode } = useContentStore();
|
|
6502
|
-
const containerRef =
|
|
6503
|
-
const [isHovered, setIsHovered] =
|
|
6504
|
-
const [isSelected, setIsSelected] =
|
|
6505
|
-
const [isDropMode, setIsDropMode] =
|
|
6506
|
-
const [isDropHover, setIsDropHover] =
|
|
6507
|
-
const [previewConfig, setPreviewConfig] =
|
|
6508
|
-
|
|
6908
|
+
const containerRef = useRef19(null);
|
|
6909
|
+
const [isHovered, setIsHovered] = useState18(false);
|
|
6910
|
+
const [isSelected, setIsSelected] = useState18(false);
|
|
6911
|
+
const [isDropMode, setIsDropMode] = useState18(false);
|
|
6912
|
+
const [isDropHover, setIsDropHover] = useState18(false);
|
|
6913
|
+
const [previewConfig, setPreviewConfig] = useState18(null);
|
|
6914
|
+
useEffect18(() => {
|
|
6509
6915
|
if (mode !== "inline-edit") return;
|
|
6510
6916
|
const containerEl = containerRef.current;
|
|
6511
6917
|
if (!containerEl) return;
|
|
@@ -6548,7 +6954,7 @@ function YaContainer({
|
|
|
6548
6954
|
overlayCustomProps["--ya-overlay-color"] = displayConfig.overlay.color;
|
|
6549
6955
|
overlayCustomProps["--ya-overlay-opacity"] = displayConfig.overlay.opacity;
|
|
6550
6956
|
}
|
|
6551
|
-
const handleImageClick =
|
|
6957
|
+
const handleImageClick = useCallback20(() => {
|
|
6552
6958
|
if (mode !== "inline-edit") return;
|
|
6553
6959
|
setIsSelected(true);
|
|
6554
6960
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
@@ -6568,7 +6974,7 @@ function YaContainer({
|
|
|
6568
6974
|
"*"
|
|
6569
6975
|
);
|
|
6570
6976
|
}, [mode, fieldId, backgroundConfig]);
|
|
6571
|
-
const handleColorClick =
|
|
6977
|
+
const handleColorClick = useCallback20(() => {
|
|
6572
6978
|
if (mode !== "inline-edit") return;
|
|
6573
6979
|
setIsSelected(true);
|
|
6574
6980
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
@@ -6588,7 +6994,7 @@ function YaContainer({
|
|
|
6588
6994
|
"*"
|
|
6589
6995
|
);
|
|
6590
6996
|
}, [mode, fieldId, backgroundConfig]);
|
|
6591
|
-
const handleAIClick =
|
|
6997
|
+
const handleAIClick = useCallback20(() => {
|
|
6592
6998
|
if (mode !== "inline-edit") return;
|
|
6593
6999
|
const label = deriveContainerLabel(containerRef.current);
|
|
6594
7000
|
window.parent.postMessage(
|
|
@@ -6601,14 +7007,14 @@ function YaContainer({
|
|
|
6601
7007
|
"*"
|
|
6602
7008
|
);
|
|
6603
7009
|
}, [mode, fieldId, backgroundConfig]);
|
|
6604
|
-
const handleClearClick =
|
|
7010
|
+
const handleClearClick = useCallback20(() => {
|
|
6605
7011
|
if (mode !== "inline-edit") return;
|
|
6606
7012
|
const clearedConfig = { type: "none" };
|
|
6607
7013
|
const serialized = serializeBackgroundConfig(clearedConfig);
|
|
6608
7014
|
setValue(fieldId, serialized);
|
|
6609
7015
|
saveToWorker?.(fieldId, serialized);
|
|
6610
7016
|
}, [mode, fieldId, setValue, saveToWorker]);
|
|
6611
|
-
|
|
7017
|
+
useEffect18(() => {
|
|
6612
7018
|
if (mode !== "inline-edit") return;
|
|
6613
7019
|
const handleMessage2 = (event) => {
|
|
6614
7020
|
if (event.data?.type === "YA_CONTAINER_UPDATE_PREVIEW" && event.data.fieldId === fieldId) {
|
|
@@ -6629,7 +7035,7 @@ function YaContainer({
|
|
|
6629
7035
|
window.addEventListener("message", handleMessage2);
|
|
6630
7036
|
return () => window.removeEventListener("message", handleMessage2);
|
|
6631
7037
|
}, [mode, fieldId]);
|
|
6632
|
-
|
|
7038
|
+
useEffect18(() => {
|
|
6633
7039
|
if (mode !== "inline-edit") return;
|
|
6634
7040
|
const handleDropModeMessage = (event) => {
|
|
6635
7041
|
if (event.data?.type === "DROP_MODE_START") {
|
|
@@ -6643,7 +7049,7 @@ function YaContainer({
|
|
|
6643
7049
|
window.addEventListener("message", handleDropModeMessage);
|
|
6644
7050
|
return () => window.removeEventListener("message", handleDropModeMessage);
|
|
6645
7051
|
}, [mode]);
|
|
6646
|
-
const handleDragEnter =
|
|
7052
|
+
const handleDragEnter = useCallback20(
|
|
6647
7053
|
(e) => {
|
|
6648
7054
|
if (!isDropMode) return;
|
|
6649
7055
|
e.preventDefault();
|
|
@@ -6667,7 +7073,7 @@ function YaContainer({
|
|
|
6667
7073
|
},
|
|
6668
7074
|
[isDropMode, fieldId]
|
|
6669
7075
|
);
|
|
6670
|
-
const handleDragOver =
|
|
7076
|
+
const handleDragOver = useCallback20(
|
|
6671
7077
|
(e) => {
|
|
6672
7078
|
if (!isDropMode) return;
|
|
6673
7079
|
e.preventDefault();
|
|
@@ -6675,7 +7081,7 @@ function YaContainer({
|
|
|
6675
7081
|
},
|
|
6676
7082
|
[isDropMode]
|
|
6677
7083
|
);
|
|
6678
|
-
const handleDragLeave =
|
|
7084
|
+
const handleDragLeave = useCallback20(
|
|
6679
7085
|
(e) => {
|
|
6680
7086
|
if (!isDropMode) return;
|
|
6681
7087
|
e.preventDefault();
|
|
@@ -6689,7 +7095,7 @@ function YaContainer({
|
|
|
6689
7095
|
},
|
|
6690
7096
|
[isDropMode]
|
|
6691
7097
|
);
|
|
6692
|
-
const handleDrop =
|
|
7098
|
+
const handleDrop = useCallback20(
|
|
6693
7099
|
(e) => {
|
|
6694
7100
|
if (!isDropMode) return;
|
|
6695
7101
|
e.preventDefault();
|
|
@@ -6707,7 +7113,7 @@ function YaContainer({
|
|
|
6707
7113
|
},
|
|
6708
7114
|
[isDropMode, fieldId]
|
|
6709
7115
|
);
|
|
6710
|
-
|
|
7116
|
+
useEffect18(() => {
|
|
6711
7117
|
if (!isSelected || mode !== "inline-edit") return;
|
|
6712
7118
|
let lastRectKey = "";
|
|
6713
7119
|
let lastTime = 0;
|
|
@@ -6742,7 +7148,7 @@ function YaContainer({
|
|
|
6742
7148
|
return () => cancelAnimationFrame(rafId);
|
|
6743
7149
|
}, [isSelected, fieldId, mode]);
|
|
6744
7150
|
if (mode === "read-only") {
|
|
6745
|
-
return /* @__PURE__ */
|
|
7151
|
+
return /* @__PURE__ */ jsx18(
|
|
6746
7152
|
Tag,
|
|
6747
7153
|
{
|
|
6748
7154
|
className: `ya-container ${className || ""}`,
|
|
@@ -6785,7 +7191,7 @@ function YaContainer({
|
|
|
6785
7191
|
onDrop: handleDrop,
|
|
6786
7192
|
children: [
|
|
6787
7193
|
children,
|
|
6788
|
-
mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */
|
|
7194
|
+
mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx18(
|
|
6789
7195
|
Toolbar,
|
|
6790
7196
|
{
|
|
6791
7197
|
containerRef,
|
|
@@ -6802,10 +7208,10 @@ function YaContainer({
|
|
|
6802
7208
|
}
|
|
6803
7209
|
|
|
6804
7210
|
// src/components/StaticText.tsx
|
|
6805
|
-
import { jsx as
|
|
7211
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
6806
7212
|
function MpText({ fieldId, className, as: Component = "span", children }) {
|
|
6807
7213
|
const content = getContent(fieldId) || (typeof children === "string" ? children : "");
|
|
6808
|
-
return /* @__PURE__ */
|
|
7214
|
+
return /* @__PURE__ */ jsx19(
|
|
6809
7215
|
Component,
|
|
6810
7216
|
{
|
|
6811
7217
|
className,
|
|
@@ -6816,7 +7222,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
|
|
|
6816
7222
|
}
|
|
6817
7223
|
|
|
6818
7224
|
// src/components/StaticImage.tsx
|
|
6819
|
-
import { jsx as
|
|
7225
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
6820
7226
|
function parseImageValue2(value) {
|
|
6821
7227
|
if (!value) {
|
|
6822
7228
|
return { src: "" };
|
|
@@ -6852,7 +7258,7 @@ function MpImage({
|
|
|
6852
7258
|
const altText = imageData.alt || alt || fallbackAlt || "";
|
|
6853
7259
|
const objectFit = imageData.objectFit || propObjectFit || "cover";
|
|
6854
7260
|
const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
|
|
6855
|
-
return /* @__PURE__ */
|
|
7261
|
+
return /* @__PURE__ */ jsx20(
|
|
6856
7262
|
"img",
|
|
6857
7263
|
{
|
|
6858
7264
|
src: resolveAssetUrl(src),
|
|
@@ -6870,7 +7276,7 @@ function MpImage({
|
|
|
6870
7276
|
|
|
6871
7277
|
// src/components/MarkdownText.tsx
|
|
6872
7278
|
import { Fragment as Fragment6 } from "react";
|
|
6873
|
-
import { jsx as
|
|
7279
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
6874
7280
|
function tokenize(text2) {
|
|
6875
7281
|
const tokens = [];
|
|
6876
7282
|
let remaining = text2;
|
|
@@ -6932,13 +7338,13 @@ function tokensToElements(tokens) {
|
|
|
6932
7338
|
return tokens.map((token, index) => {
|
|
6933
7339
|
switch (token.type) {
|
|
6934
7340
|
case "text":
|
|
6935
|
-
return /* @__PURE__ */
|
|
7341
|
+
return /* @__PURE__ */ jsx21(Fragment6, { children: token.content }, index);
|
|
6936
7342
|
case "bold":
|
|
6937
|
-
return /* @__PURE__ */
|
|
7343
|
+
return /* @__PURE__ */ jsx21("strong", { children: token.content }, index);
|
|
6938
7344
|
case "italic":
|
|
6939
|
-
return /* @__PURE__ */
|
|
7345
|
+
return /* @__PURE__ */ jsx21("em", { children: token.content }, index);
|
|
6940
7346
|
case "link":
|
|
6941
|
-
return /* @__PURE__ */
|
|
7347
|
+
return /* @__PURE__ */ jsx21(
|
|
6942
7348
|
"a",
|
|
6943
7349
|
{
|
|
6944
7350
|
href: token.url,
|
|
@@ -6950,7 +7356,7 @@ function tokensToElements(tokens) {
|
|
|
6950
7356
|
index
|
|
6951
7357
|
);
|
|
6952
7358
|
case "newline":
|
|
6953
|
-
return /* @__PURE__ */
|
|
7359
|
+
return /* @__PURE__ */ jsx21("br", {}, index);
|
|
6954
7360
|
default:
|
|
6955
7361
|
return null;
|
|
6956
7362
|
}
|
|
@@ -6962,15 +7368,480 @@ function parseMarkdownToElements(content) {
|
|
|
6962
7368
|
}
|
|
6963
7369
|
function MarkdownText({ content, className }) {
|
|
6964
7370
|
const elements = parseMarkdownToElements(content);
|
|
6965
|
-
return /* @__PURE__ */
|
|
7371
|
+
return /* @__PURE__ */ jsx21("span", { className, children: elements });
|
|
7372
|
+
}
|
|
7373
|
+
|
|
7374
|
+
// src/components/CollectionPage.tsx
|
|
7375
|
+
import { useParams } from "wouter";
|
|
7376
|
+
|
|
7377
|
+
// src/hooks/useCollection.ts
|
|
7378
|
+
import { useState as useState19, useEffect as useEffect19, useCallback as useCallback21, useRef as useRef20 } from "react";
|
|
7379
|
+
|
|
7380
|
+
// src/lib/collection-client.ts
|
|
7381
|
+
function getEnvVar(key) {
|
|
7382
|
+
try {
|
|
7383
|
+
const env = import.meta.env;
|
|
7384
|
+
return env?.[key];
|
|
7385
|
+
} catch {
|
|
7386
|
+
return void 0;
|
|
7387
|
+
}
|
|
7388
|
+
}
|
|
7389
|
+
function getConfig() {
|
|
7390
|
+
if (typeof window === "undefined") {
|
|
7391
|
+
throw new Error("CollectionClient requires browser environment");
|
|
7392
|
+
}
|
|
7393
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
7394
|
+
const appId = runtimeConfig?.appId || runtimeConfig?.siteId || getEnvVar("YA_APP_ID") || getEnvVar("YA_SITE_ID");
|
|
7395
|
+
const apiUrl = runtimeConfig?.apiUrl || getEnvVar("YA_API_URL");
|
|
7396
|
+
if (!appId) {
|
|
7397
|
+
throw new Error("App ID not configured (check YOAMIGO_CONFIG.appId or YA_APP_ID)");
|
|
7398
|
+
}
|
|
7399
|
+
if (!apiUrl) {
|
|
7400
|
+
throw new Error("API URL not configured (check YOAMIGO_CONFIG.apiUrl or YA_API_URL)");
|
|
7401
|
+
}
|
|
7402
|
+
return { apiUrl, appId };
|
|
7403
|
+
}
|
|
7404
|
+
var CollectionClient = class {
|
|
7405
|
+
apiUrl;
|
|
7406
|
+
appId;
|
|
7407
|
+
constructor(config) {
|
|
7408
|
+
this.apiUrl = config.apiUrl;
|
|
7409
|
+
this.appId = config.appId;
|
|
7410
|
+
}
|
|
7411
|
+
/**
|
|
7412
|
+
* List records from a collection with optional filtering, pagination, and sorting.
|
|
7413
|
+
*/
|
|
7414
|
+
async list(collection, options = {}) {
|
|
7415
|
+
const { filters, limit, offset, orderBy, orderDir } = options;
|
|
7416
|
+
const url = new URL(`${this.apiUrl}/api/apps/${this.appId}/collections/${collection}/records`);
|
|
7417
|
+
if (filters && filters.length > 0) {
|
|
7418
|
+
url.searchParams.set("filters", JSON.stringify(filters));
|
|
7419
|
+
}
|
|
7420
|
+
if (limit !== void 0) {
|
|
7421
|
+
url.searchParams.set("limit", String(limit));
|
|
7422
|
+
}
|
|
7423
|
+
if (offset !== void 0) {
|
|
7424
|
+
url.searchParams.set("offset", String(offset));
|
|
7425
|
+
}
|
|
7426
|
+
if (orderBy) {
|
|
7427
|
+
url.searchParams.set("orderBy", orderBy);
|
|
7428
|
+
}
|
|
7429
|
+
if (orderDir) {
|
|
7430
|
+
url.searchParams.set("orderDir", orderDir);
|
|
7431
|
+
}
|
|
7432
|
+
try {
|
|
7433
|
+
const response = await fetch(url.toString(), {
|
|
7434
|
+
method: "GET",
|
|
7435
|
+
headers: {
|
|
7436
|
+
"Content-Type": "application/json"
|
|
7437
|
+
}
|
|
7438
|
+
});
|
|
7439
|
+
const result = await response.json();
|
|
7440
|
+
if (!response.ok) {
|
|
7441
|
+
return {
|
|
7442
|
+
success: false,
|
|
7443
|
+
error: result.error || `HTTP ${response.status}`,
|
|
7444
|
+
errorCode: result.errorCode
|
|
7445
|
+
};
|
|
7446
|
+
}
|
|
7447
|
+
return {
|
|
7448
|
+
success: true,
|
|
7449
|
+
data: result.data,
|
|
7450
|
+
totalCount: result.totalCount
|
|
7451
|
+
};
|
|
7452
|
+
} catch (error) {
|
|
7453
|
+
return {
|
|
7454
|
+
success: false,
|
|
7455
|
+
error: error instanceof Error ? error.message : "Network error"
|
|
7456
|
+
};
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7459
|
+
/**
|
|
7460
|
+
* Get a single record by its ID.
|
|
7461
|
+
*/
|
|
7462
|
+
async getById(collection, id) {
|
|
7463
|
+
const url = `${this.apiUrl}/api/apps/${this.appId}/collections/${collection}/records/${id}`;
|
|
7464
|
+
try {
|
|
7465
|
+
const response = await fetch(url, {
|
|
7466
|
+
method: "GET",
|
|
7467
|
+
headers: {
|
|
7468
|
+
"Content-Type": "application/json"
|
|
7469
|
+
}
|
|
7470
|
+
});
|
|
7471
|
+
const result = await response.json();
|
|
7472
|
+
if (!response.ok) {
|
|
7473
|
+
return {
|
|
7474
|
+
success: false,
|
|
7475
|
+
error: result.error || `HTTP ${response.status}`,
|
|
7476
|
+
errorCode: result.errorCode
|
|
7477
|
+
};
|
|
7478
|
+
}
|
|
7479
|
+
return {
|
|
7480
|
+
success: true,
|
|
7481
|
+
data: result.data
|
|
7482
|
+
};
|
|
7483
|
+
} catch (error) {
|
|
7484
|
+
return {
|
|
7485
|
+
success: false,
|
|
7486
|
+
error: error instanceof Error ? error.message : "Network error"
|
|
7487
|
+
};
|
|
7488
|
+
}
|
|
7489
|
+
}
|
|
7490
|
+
/**
|
|
7491
|
+
* Get a single record by a slug field value.
|
|
7492
|
+
* Convenience method that uses list with a filter.
|
|
7493
|
+
*/
|
|
7494
|
+
async getBySlug(collection, slugField, slugValue) {
|
|
7495
|
+
const result = await this.list(collection, {
|
|
7496
|
+
filters: [
|
|
7497
|
+
{ field: slugField, operator: "eq", value: slugValue }
|
|
7498
|
+
],
|
|
7499
|
+
limit: 1
|
|
7500
|
+
});
|
|
7501
|
+
if (!result.success) {
|
|
7502
|
+
return {
|
|
7503
|
+
success: false,
|
|
7504
|
+
error: result.error,
|
|
7505
|
+
errorCode: result.errorCode
|
|
7506
|
+
};
|
|
7507
|
+
}
|
|
7508
|
+
if (!result.data || result.data.length === 0) {
|
|
7509
|
+
return {
|
|
7510
|
+
success: false,
|
|
7511
|
+
error: "Record not found",
|
|
7512
|
+
errorCode: "NOT_FOUND"
|
|
7513
|
+
};
|
|
7514
|
+
}
|
|
7515
|
+
return {
|
|
7516
|
+
success: true,
|
|
7517
|
+
data: result.data[0]
|
|
7518
|
+
};
|
|
7519
|
+
}
|
|
7520
|
+
};
|
|
7521
|
+
var cachedClient = null;
|
|
7522
|
+
function getCollectionClient() {
|
|
7523
|
+
if (!cachedClient) {
|
|
7524
|
+
const config = getConfig();
|
|
7525
|
+
cachedClient = new CollectionClient(config);
|
|
7526
|
+
}
|
|
7527
|
+
return cachedClient;
|
|
7528
|
+
}
|
|
7529
|
+
function resetCollectionClient() {
|
|
7530
|
+
cachedClient = null;
|
|
7531
|
+
}
|
|
7532
|
+
|
|
7533
|
+
// src/hooks/useCollection.ts
|
|
7534
|
+
function useCollectionList(options) {
|
|
7535
|
+
const {
|
|
7536
|
+
collection,
|
|
7537
|
+
filters,
|
|
7538
|
+
page = 1,
|
|
7539
|
+
pageSize = 10,
|
|
7540
|
+
orderBy,
|
|
7541
|
+
orderDir,
|
|
7542
|
+
enabled = true
|
|
7543
|
+
} = options;
|
|
7544
|
+
const [data, setData] = useState19(null);
|
|
7545
|
+
const [isLoading, setIsLoading] = useState19(true);
|
|
7546
|
+
const [error, setError] = useState19(null);
|
|
7547
|
+
const [totalCount, setTotalCount] = useState19(0);
|
|
7548
|
+
const [currentPage, setCurrentPage] = useState19(page);
|
|
7549
|
+
const fetchVersion = useRef20(0);
|
|
7550
|
+
const fetchData = useCallback21(async (pageNum) => {
|
|
7551
|
+
if (!enabled) {
|
|
7552
|
+
setIsLoading(false);
|
|
7553
|
+
return;
|
|
7554
|
+
}
|
|
7555
|
+
setIsLoading(true);
|
|
7556
|
+
setError(null);
|
|
7557
|
+
const version = ++fetchVersion.current;
|
|
7558
|
+
try {
|
|
7559
|
+
const client = getCollectionClient();
|
|
7560
|
+
const offset = (pageNum - 1) * pageSize;
|
|
7561
|
+
const result = await client.list(collection, {
|
|
7562
|
+
filters,
|
|
7563
|
+
limit: pageSize,
|
|
7564
|
+
offset,
|
|
7565
|
+
orderBy,
|
|
7566
|
+
orderDir
|
|
7567
|
+
});
|
|
7568
|
+
if (version !== fetchVersion.current) return;
|
|
7569
|
+
if (!result.success) {
|
|
7570
|
+
setError(result.error || "Failed to fetch collection");
|
|
7571
|
+
setData(null);
|
|
7572
|
+
setTotalCount(0);
|
|
7573
|
+
} else {
|
|
7574
|
+
setData(result.data || []);
|
|
7575
|
+
setTotalCount(result.totalCount || 0);
|
|
7576
|
+
setCurrentPage(pageNum);
|
|
7577
|
+
}
|
|
7578
|
+
} catch (err) {
|
|
7579
|
+
if (version !== fetchVersion.current) return;
|
|
7580
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
7581
|
+
setData(null);
|
|
7582
|
+
} finally {
|
|
7583
|
+
if (version === fetchVersion.current) {
|
|
7584
|
+
setIsLoading(false);
|
|
7585
|
+
}
|
|
7586
|
+
}
|
|
7587
|
+
}, [collection, JSON.stringify(filters), pageSize, orderBy, orderDir, enabled]);
|
|
7588
|
+
useEffect19(() => {
|
|
7589
|
+
fetchData(page);
|
|
7590
|
+
}, [fetchData, page]);
|
|
7591
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
7592
|
+
const hasMore = currentPage < totalPages;
|
|
7593
|
+
const refetch = useCallback21(() => {
|
|
7594
|
+
fetchData(currentPage);
|
|
7595
|
+
}, [fetchData, currentPage]);
|
|
7596
|
+
const goToPage = useCallback21((newPage) => {
|
|
7597
|
+
if (newPage >= 1 && newPage <= Math.max(1, totalPages)) {
|
|
7598
|
+
fetchData(newPage);
|
|
7599
|
+
}
|
|
7600
|
+
}, [fetchData, totalPages]);
|
|
7601
|
+
return {
|
|
7602
|
+
data,
|
|
7603
|
+
isLoading,
|
|
7604
|
+
error,
|
|
7605
|
+
totalCount,
|
|
7606
|
+
hasMore,
|
|
7607
|
+
currentPage,
|
|
7608
|
+
totalPages,
|
|
7609
|
+
refetch,
|
|
7610
|
+
goToPage
|
|
7611
|
+
};
|
|
7612
|
+
}
|
|
7613
|
+
function useCollectionRecord(options) {
|
|
7614
|
+
const {
|
|
7615
|
+
collection,
|
|
7616
|
+
slugField,
|
|
7617
|
+
slugValue,
|
|
7618
|
+
enabled = true
|
|
7619
|
+
} = options;
|
|
7620
|
+
const [data, setData] = useState19(null);
|
|
7621
|
+
const [isLoading, setIsLoading] = useState19(true);
|
|
7622
|
+
const [error, setError] = useState19(null);
|
|
7623
|
+
const [notFound, setNotFound] = useState19(false);
|
|
7624
|
+
const fetchVersion = useRef20(0);
|
|
7625
|
+
const fetchData = useCallback21(async () => {
|
|
7626
|
+
if (!enabled || !slugValue) {
|
|
7627
|
+
setIsLoading(false);
|
|
7628
|
+
return;
|
|
7629
|
+
}
|
|
7630
|
+
setIsLoading(true);
|
|
7631
|
+
setError(null);
|
|
7632
|
+
setNotFound(false);
|
|
7633
|
+
const version = ++fetchVersion.current;
|
|
7634
|
+
try {
|
|
7635
|
+
const client = getCollectionClient();
|
|
7636
|
+
const result = await client.getBySlug(
|
|
7637
|
+
collection,
|
|
7638
|
+
slugField,
|
|
7639
|
+
slugValue
|
|
7640
|
+
);
|
|
7641
|
+
if (version !== fetchVersion.current) return;
|
|
7642
|
+
if (!result.success) {
|
|
7643
|
+
if (result.errorCode === "NOT_FOUND") {
|
|
7644
|
+
setNotFound(true);
|
|
7645
|
+
setData(null);
|
|
7646
|
+
} else {
|
|
7647
|
+
setError(result.error || "Failed to fetch record");
|
|
7648
|
+
setData(null);
|
|
7649
|
+
}
|
|
7650
|
+
} else {
|
|
7651
|
+
setData(result.data || null);
|
|
7652
|
+
}
|
|
7653
|
+
} catch (err) {
|
|
7654
|
+
if (version !== fetchVersion.current) return;
|
|
7655
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
7656
|
+
setData(null);
|
|
7657
|
+
} finally {
|
|
7658
|
+
if (version === fetchVersion.current) {
|
|
7659
|
+
setIsLoading(false);
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
}, [collection, slugField, slugValue, enabled]);
|
|
7663
|
+
useEffect19(() => {
|
|
7664
|
+
fetchData();
|
|
7665
|
+
}, [fetchData]);
|
|
7666
|
+
const refetch = useCallback21(() => {
|
|
7667
|
+
fetchData();
|
|
7668
|
+
}, [fetchData]);
|
|
7669
|
+
return {
|
|
7670
|
+
data,
|
|
7671
|
+
isLoading,
|
|
7672
|
+
error,
|
|
7673
|
+
notFound,
|
|
7674
|
+
refetch
|
|
7675
|
+
};
|
|
7676
|
+
}
|
|
7677
|
+
|
|
7678
|
+
// src/components/CollectionPage.tsx
|
|
7679
|
+
function CollectionListPage({
|
|
7680
|
+
collection,
|
|
7681
|
+
pageSize = 10,
|
|
7682
|
+
page = 1,
|
|
7683
|
+
filters,
|
|
7684
|
+
orderBy,
|
|
7685
|
+
orderDir,
|
|
7686
|
+
enabled = true,
|
|
7687
|
+
render
|
|
7688
|
+
}) {
|
|
7689
|
+
const result = useCollectionList({
|
|
7690
|
+
collection,
|
|
7691
|
+
pageSize,
|
|
7692
|
+
page,
|
|
7693
|
+
filters,
|
|
7694
|
+
orderBy,
|
|
7695
|
+
orderDir,
|
|
7696
|
+
enabled
|
|
7697
|
+
});
|
|
7698
|
+
return render(result);
|
|
7699
|
+
}
|
|
7700
|
+
function CollectionDetailPage({
|
|
7701
|
+
collection,
|
|
7702
|
+
slugField = "slug",
|
|
7703
|
+
slugParam = "slug",
|
|
7704
|
+
slug: slugOverride,
|
|
7705
|
+
enabled = true,
|
|
7706
|
+
render
|
|
7707
|
+
}) {
|
|
7708
|
+
const params = useParams();
|
|
7709
|
+
const slug = slugOverride || params[slugParam] || "";
|
|
7710
|
+
const result = useCollectionRecord({
|
|
7711
|
+
collection,
|
|
7712
|
+
slugField,
|
|
7713
|
+
slugValue: slug,
|
|
7714
|
+
enabled: enabled && Boolean(slug)
|
|
7715
|
+
});
|
|
7716
|
+
return render({
|
|
7717
|
+
...result,
|
|
7718
|
+
slug
|
|
7719
|
+
});
|
|
7720
|
+
}
|
|
7721
|
+
|
|
7722
|
+
// src/components/CollectionList.tsx
|
|
7723
|
+
import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
7724
|
+
function CollectionList({
|
|
7725
|
+
collection,
|
|
7726
|
+
prefix,
|
|
7727
|
+
filters,
|
|
7728
|
+
page,
|
|
7729
|
+
pageSize,
|
|
7730
|
+
orderBy,
|
|
7731
|
+
orderDir,
|
|
7732
|
+
children,
|
|
7733
|
+
skeleton,
|
|
7734
|
+
empty,
|
|
7735
|
+
error,
|
|
7736
|
+
appId,
|
|
7737
|
+
enabled = true,
|
|
7738
|
+
pagination,
|
|
7739
|
+
wrapper: Wrapper
|
|
7740
|
+
}) {
|
|
7741
|
+
const result = useCollectionList({
|
|
7742
|
+
collection,
|
|
7743
|
+
filters,
|
|
7744
|
+
page,
|
|
7745
|
+
pageSize,
|
|
7746
|
+
orderBy,
|
|
7747
|
+
orderDir,
|
|
7748
|
+
enabled
|
|
7749
|
+
});
|
|
7750
|
+
if (result.isLoading) {
|
|
7751
|
+
const skeletonCount = pageSize || 10;
|
|
7752
|
+
const skeletonItems = Array.from(
|
|
7753
|
+
{ length: skeletonCount },
|
|
7754
|
+
(_, index) => skeleton({ index })
|
|
7755
|
+
);
|
|
7756
|
+
return Wrapper ? /* @__PURE__ */ jsx22(Wrapper, { children: skeletonItems }) : /* @__PURE__ */ jsx22(Fragment7, { children: skeletonItems });
|
|
7757
|
+
}
|
|
7758
|
+
if (result.error) {
|
|
7759
|
+
return error?.(result.error) ?? null;
|
|
7760
|
+
}
|
|
7761
|
+
if (!result.data || result.data.length === 0) {
|
|
7762
|
+
return empty ?? null;
|
|
7763
|
+
}
|
|
7764
|
+
const items = result.data.map((record, index) => {
|
|
7765
|
+
const fieldPrefix = `${prefix}.${record.id}`;
|
|
7766
|
+
return /* @__PURE__ */ jsx22(
|
|
7767
|
+
CollectionContentProvider,
|
|
7768
|
+
{
|
|
7769
|
+
record: record.data,
|
|
7770
|
+
prefix: fieldPrefix,
|
|
7771
|
+
recordId: record.id,
|
|
7772
|
+
collectionSlug: collection,
|
|
7773
|
+
appId,
|
|
7774
|
+
children: children({ record, index, fieldPrefix })
|
|
7775
|
+
},
|
|
7776
|
+
record.id
|
|
7777
|
+
);
|
|
7778
|
+
});
|
|
7779
|
+
const content = Wrapper ? /* @__PURE__ */ jsx22(Wrapper, { children: items }) : /* @__PURE__ */ jsx22(Fragment7, { children: items });
|
|
7780
|
+
if (pagination) {
|
|
7781
|
+
return /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
7782
|
+
content,
|
|
7783
|
+
pagination({
|
|
7784
|
+
currentPage: result.currentPage,
|
|
7785
|
+
totalPages: result.totalPages,
|
|
7786
|
+
totalCount: result.totalCount,
|
|
7787
|
+
hasMore: result.hasMore,
|
|
7788
|
+
goToPage: result.goToPage
|
|
7789
|
+
})
|
|
7790
|
+
] });
|
|
7791
|
+
}
|
|
7792
|
+
return content;
|
|
7793
|
+
}
|
|
7794
|
+
|
|
7795
|
+
// src/components/CollectionItem.tsx
|
|
7796
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
7797
|
+
function CollectionItem({
|
|
7798
|
+
collection,
|
|
7799
|
+
prefix,
|
|
7800
|
+
slugField = "slug",
|
|
7801
|
+
slugValue,
|
|
7802
|
+
children,
|
|
7803
|
+
skeleton,
|
|
7804
|
+
appId,
|
|
7805
|
+
enabled = true
|
|
7806
|
+
}) {
|
|
7807
|
+
const result = useCollectionRecord({
|
|
7808
|
+
collection,
|
|
7809
|
+
slugField,
|
|
7810
|
+
slugValue,
|
|
7811
|
+
enabled: enabled && Boolean(slugValue)
|
|
7812
|
+
});
|
|
7813
|
+
const renderProps = {
|
|
7814
|
+
record: result.data,
|
|
7815
|
+
isLoading: result.isLoading,
|
|
7816
|
+
notFound: result.notFound,
|
|
7817
|
+
error: result.error,
|
|
7818
|
+
refetch: result.refetch
|
|
7819
|
+
};
|
|
7820
|
+
if (result.isLoading) {
|
|
7821
|
+
return skeleton;
|
|
7822
|
+
}
|
|
7823
|
+
if (result.error || result.notFound || !result.data) {
|
|
7824
|
+
return children(renderProps);
|
|
7825
|
+
}
|
|
7826
|
+
return /* @__PURE__ */ jsx23(
|
|
7827
|
+
CollectionContentProvider,
|
|
7828
|
+
{
|
|
7829
|
+
record: result.data.data,
|
|
7830
|
+
prefix,
|
|
7831
|
+
recordId: result.data.id,
|
|
7832
|
+
collectionSlug: collection,
|
|
7833
|
+
appId,
|
|
7834
|
+
children: children(renderProps)
|
|
7835
|
+
}
|
|
7836
|
+
);
|
|
6966
7837
|
}
|
|
6967
7838
|
|
|
6968
7839
|
// src/router/Link.tsx
|
|
6969
7840
|
import { Link as WouterLink2 } from "wouter";
|
|
6970
|
-
import { jsx as
|
|
7841
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
6971
7842
|
function Link2({ to, href, children, className, onClick, replace, ...props }) {
|
|
6972
7843
|
const target = href ?? to ?? "/";
|
|
6973
|
-
return /* @__PURE__ */
|
|
7844
|
+
return /* @__PURE__ */ jsx24(WouterLink2, { href: target, className, onClick, replace, ...props, children });
|
|
6974
7845
|
}
|
|
6975
7846
|
|
|
6976
7847
|
// src/router/useNavigate.ts
|
|
@@ -6989,7 +7860,7 @@ function useNavigate() {
|
|
|
6989
7860
|
|
|
6990
7861
|
// src/router/Router.tsx
|
|
6991
7862
|
import { Router as WouterRouter } from "wouter";
|
|
6992
|
-
import { jsx as
|
|
7863
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
6993
7864
|
function detectBasename() {
|
|
6994
7865
|
if (typeof window === "undefined") return "";
|
|
6995
7866
|
const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
|
|
@@ -7004,11 +7875,11 @@ function detectBasename() {
|
|
|
7004
7875
|
}
|
|
7005
7876
|
function Router({ children, base }) {
|
|
7006
7877
|
const basename = base ?? detectBasename();
|
|
7007
|
-
return /* @__PURE__ */
|
|
7878
|
+
return /* @__PURE__ */ jsx25(WouterRouter, { base: basename, children });
|
|
7008
7879
|
}
|
|
7009
7880
|
|
|
7010
7881
|
// src/router/ScrollRestoration.tsx
|
|
7011
|
-
import { useEffect as
|
|
7882
|
+
import { useEffect as useEffect20, useRef as useRef21 } from "react";
|
|
7012
7883
|
import { useLocation as useLocation3 } from "wouter";
|
|
7013
7884
|
var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
|
|
7014
7885
|
var HISTORY_INDEX_KEY = "yoamigo-history-index";
|
|
@@ -7044,10 +7915,10 @@ function setHistoryIndex(index) {
|
|
|
7044
7915
|
var globalHistoryIndex = 0;
|
|
7045
7916
|
function ScrollRestoration() {
|
|
7046
7917
|
const [location] = useLocation3();
|
|
7047
|
-
const previousLocation =
|
|
7048
|
-
const isPopState =
|
|
7049
|
-
const scrollPositionsRef =
|
|
7050
|
-
|
|
7918
|
+
const previousLocation = useRef21(location);
|
|
7919
|
+
const isPopState = useRef21(false);
|
|
7920
|
+
const scrollPositionsRef = useRef21({});
|
|
7921
|
+
useEffect20(() => {
|
|
7051
7922
|
if (typeof history !== "undefined" && "scrollRestoration" in history) {
|
|
7052
7923
|
history.scrollRestoration = "manual";
|
|
7053
7924
|
}
|
|
@@ -7065,7 +7936,7 @@ function ScrollRestoration() {
|
|
|
7065
7936
|
window.addEventListener("popstate", handlePopState);
|
|
7066
7937
|
return () => window.removeEventListener("popstate", handlePopState);
|
|
7067
7938
|
}, []);
|
|
7068
|
-
|
|
7939
|
+
useEffect20(() => {
|
|
7069
7940
|
if (previousLocation.current === location) return;
|
|
7070
7941
|
const prevHistoryIndex = globalHistoryIndex;
|
|
7071
7942
|
const currentScrollY = window.scrollY;
|
|
@@ -7085,7 +7956,7 @@ function ScrollRestoration() {
|
|
|
7085
7956
|
}
|
|
7086
7957
|
previousLocation.current = location;
|
|
7087
7958
|
}, [location]);
|
|
7088
|
-
|
|
7959
|
+
useEffect20(() => {
|
|
7089
7960
|
let timeoutId;
|
|
7090
7961
|
const handleScroll = () => {
|
|
7091
7962
|
clearTimeout(timeoutId);
|
|
@@ -7104,7 +7975,74 @@ function ScrollRestoration() {
|
|
|
7104
7975
|
}
|
|
7105
7976
|
|
|
7106
7977
|
// src/router/index.ts
|
|
7107
|
-
import { Route, Switch, useParams } from "wouter";
|
|
7978
|
+
import { Route, Switch, useParams as useParams2, useLocation as useLocation4 } from "wouter";
|
|
7979
|
+
|
|
7980
|
+
// src/router/route-utils.ts
|
|
7981
|
+
function filePathToRoutePath(filePath, options = {}) {
|
|
7982
|
+
const {
|
|
7983
|
+
pagesDir = "/src/pages",
|
|
7984
|
+
extensions = [".tsx", ".ts", ".jsx", ".js"]
|
|
7985
|
+
} = options;
|
|
7986
|
+
let path = filePath;
|
|
7987
|
+
if (path.startsWith(pagesDir)) {
|
|
7988
|
+
path = path.slice(pagesDir.length);
|
|
7989
|
+
}
|
|
7990
|
+
for (const ext of extensions) {
|
|
7991
|
+
if (path.endsWith(ext)) {
|
|
7992
|
+
path = path.slice(0, -ext.length);
|
|
7993
|
+
break;
|
|
7994
|
+
}
|
|
7995
|
+
}
|
|
7996
|
+
if (path.endsWith("/index")) {
|
|
7997
|
+
path = path.slice(0, -6) || "/";
|
|
7998
|
+
}
|
|
7999
|
+
path = path.replace(/\[\.\.\.([^\]]+)\]/g, ":$1*");
|
|
8000
|
+
path = path.replace(/\[([^\]]+)\]/g, ":$1");
|
|
8001
|
+
if (!path.startsWith("/")) {
|
|
8002
|
+
path = "/" + path;
|
|
8003
|
+
}
|
|
8004
|
+
if (path === "" || path === "/index") {
|
|
8005
|
+
return "/";
|
|
8006
|
+
}
|
|
8007
|
+
return path;
|
|
8008
|
+
}
|
|
8009
|
+
function extractRouteParams(filePath) {
|
|
8010
|
+
const matches = filePath.matchAll(/\[\.\.\.([^\]]+)\]|\[([^\]]+)\]/g);
|
|
8011
|
+
const params = [];
|
|
8012
|
+
for (const match of matches) {
|
|
8013
|
+
params.push(match[1] || match[2]);
|
|
8014
|
+
}
|
|
8015
|
+
return params;
|
|
8016
|
+
}
|
|
8017
|
+
function createRouteDefinition(filePath, options) {
|
|
8018
|
+
const path = filePathToRoutePath(filePath, options);
|
|
8019
|
+
const params = extractRouteParams(filePath);
|
|
8020
|
+
return {
|
|
8021
|
+
path,
|
|
8022
|
+
filePath,
|
|
8023
|
+
params,
|
|
8024
|
+
isDynamic: params.length > 0
|
|
8025
|
+
};
|
|
8026
|
+
}
|
|
8027
|
+
function sortRoutesBySpecificity(routes) {
|
|
8028
|
+
return [...routes].sort((a, b) => {
|
|
8029
|
+
if (!a.isDynamic && b.isDynamic) return -1;
|
|
8030
|
+
if (a.isDynamic && !b.isDynamic) return 1;
|
|
8031
|
+
const aSegments = a.path.split("/").filter(Boolean);
|
|
8032
|
+
const bSegments = b.path.split("/").filter(Boolean);
|
|
8033
|
+
if (aSegments.length !== bSegments.length) {
|
|
8034
|
+
return bSegments.length - aSegments.length;
|
|
8035
|
+
}
|
|
8036
|
+
return a.params.length - b.params.length;
|
|
8037
|
+
});
|
|
8038
|
+
}
|
|
8039
|
+
function generatePath(routePath, params) {
|
|
8040
|
+
let path = routePath;
|
|
8041
|
+
for (const [key, value] of Object.entries(params)) {
|
|
8042
|
+
path = path.replace(new RegExp(`:${key}\\*?`, "g"), encodeURIComponent(value));
|
|
8043
|
+
}
|
|
8044
|
+
return path;
|
|
8045
|
+
}
|
|
7108
8046
|
|
|
7109
8047
|
// src/lib/content-helpers.ts
|
|
7110
8048
|
function text(content) {
|
|
@@ -7122,8 +8060,952 @@ function video(config) {
|
|
|
7122
8060
|
function embed(config) {
|
|
7123
8061
|
return JSON.stringify(config);
|
|
7124
8062
|
}
|
|
8063
|
+
|
|
8064
|
+
// src/contexts/CartContext.tsx
|
|
8065
|
+
import { createContext as createContext5, useContext as useContext5, useEffect as useEffect22 } from "react";
|
|
8066
|
+
|
|
8067
|
+
// src/hooks/useCart.ts
|
|
8068
|
+
import { useState as useState20, useEffect as useEffect21, useCallback as useCallback22, useRef as useRef22 } from "react";
|
|
8069
|
+
|
|
8070
|
+
// src/lib/cart-storage.ts
|
|
8071
|
+
var CART_STORAGE_KEY_PREFIX = "yoamigo_cart_";
|
|
8072
|
+
var SESSION_ID_KEY = "yoamigo_cart_session";
|
|
8073
|
+
var CART_EXPIRY_DAYS = 7;
|
|
8074
|
+
function generateSessionId() {
|
|
8075
|
+
return `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
8076
|
+
}
|
|
8077
|
+
function getSessionId() {
|
|
8078
|
+
if (typeof window === "undefined") {
|
|
8079
|
+
throw new Error("getSessionId requires browser environment");
|
|
8080
|
+
}
|
|
8081
|
+
let sessionId = localStorage.getItem(SESSION_ID_KEY);
|
|
8082
|
+
if (!sessionId) {
|
|
8083
|
+
sessionId = generateSessionId();
|
|
8084
|
+
localStorage.setItem(SESSION_ID_KEY, sessionId);
|
|
8085
|
+
}
|
|
8086
|
+
return sessionId;
|
|
8087
|
+
}
|
|
8088
|
+
function clearSessionId() {
|
|
8089
|
+
if (typeof window === "undefined") return;
|
|
8090
|
+
localStorage.removeItem(SESSION_ID_KEY);
|
|
8091
|
+
}
|
|
8092
|
+
function getStorageKey(appId) {
|
|
8093
|
+
return `${CART_STORAGE_KEY_PREFIX}${appId}`;
|
|
8094
|
+
}
|
|
8095
|
+
function getLocalCart(appId) {
|
|
8096
|
+
if (typeof window === "undefined") return null;
|
|
8097
|
+
try {
|
|
8098
|
+
const key = getStorageKey(appId);
|
|
8099
|
+
const data = localStorage.getItem(key);
|
|
8100
|
+
if (!data) return null;
|
|
8101
|
+
const cart = JSON.parse(data);
|
|
8102
|
+
const updatedAt = new Date(cart.updatedAt);
|
|
8103
|
+
const expiryDate = /* @__PURE__ */ new Date();
|
|
8104
|
+
expiryDate.setDate(expiryDate.getDate() - CART_EXPIRY_DAYS);
|
|
8105
|
+
if (updatedAt < expiryDate) {
|
|
8106
|
+
localStorage.removeItem(key);
|
|
8107
|
+
return null;
|
|
8108
|
+
}
|
|
8109
|
+
return cart;
|
|
8110
|
+
} catch (error) {
|
|
8111
|
+
console.warn("Failed to read cart from localStorage:", error);
|
|
8112
|
+
return null;
|
|
8113
|
+
}
|
|
8114
|
+
}
|
|
8115
|
+
function saveLocalCart(appId, items) {
|
|
8116
|
+
if (typeof window === "undefined") return;
|
|
8117
|
+
try {
|
|
8118
|
+
const key = getStorageKey(appId);
|
|
8119
|
+
const cart = {
|
|
8120
|
+
sessionId: getSessionId(),
|
|
8121
|
+
items,
|
|
8122
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8123
|
+
};
|
|
8124
|
+
localStorage.setItem(key, JSON.stringify(cart));
|
|
8125
|
+
} catch (error) {
|
|
8126
|
+
console.warn("Failed to save cart to localStorage:", error);
|
|
8127
|
+
}
|
|
8128
|
+
}
|
|
8129
|
+
function clearLocalCart(appId) {
|
|
8130
|
+
if (typeof window === "undefined") return;
|
|
8131
|
+
try {
|
|
8132
|
+
const key = getStorageKey(appId);
|
|
8133
|
+
localStorage.removeItem(key);
|
|
8134
|
+
} catch (error) {
|
|
8135
|
+
console.warn("Failed to clear cart from localStorage:", error);
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
function getLocalCartItems(appId) {
|
|
8139
|
+
const cart = getLocalCart(appId);
|
|
8140
|
+
return cart?.items || [];
|
|
8141
|
+
}
|
|
8142
|
+
function addLocalCartItem(appId, productId, collectionSlug, quantity = 1, variantId, data) {
|
|
8143
|
+
const items = getLocalCartItems(appId);
|
|
8144
|
+
const existingIndex = items.findIndex(
|
|
8145
|
+
(item) => item.productId === productId && item.variantId === variantId
|
|
8146
|
+
);
|
|
8147
|
+
if (existingIndex >= 0) {
|
|
8148
|
+
items[existingIndex].quantity += quantity;
|
|
8149
|
+
} else {
|
|
8150
|
+
items.push({
|
|
8151
|
+
id: `local_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
8152
|
+
productId,
|
|
8153
|
+
collectionSlug,
|
|
8154
|
+
quantity,
|
|
8155
|
+
variantId,
|
|
8156
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8157
|
+
data
|
|
8158
|
+
});
|
|
8159
|
+
}
|
|
8160
|
+
saveLocalCart(appId, items);
|
|
8161
|
+
return items;
|
|
8162
|
+
}
|
|
8163
|
+
function updateLocalCartItem(appId, itemId, quantity) {
|
|
8164
|
+
const items = getLocalCartItems(appId);
|
|
8165
|
+
const itemIndex = items.findIndex((item) => item.id === itemId);
|
|
8166
|
+
if (itemIndex < 0) return items;
|
|
8167
|
+
if (quantity === 0) {
|
|
8168
|
+
items.splice(itemIndex, 1);
|
|
8169
|
+
} else {
|
|
8170
|
+
items[itemIndex].quantity = quantity;
|
|
8171
|
+
}
|
|
8172
|
+
saveLocalCart(appId, items);
|
|
8173
|
+
return items;
|
|
8174
|
+
}
|
|
8175
|
+
function removeLocalCartItem(appId, itemId) {
|
|
8176
|
+
const items = getLocalCartItems(appId);
|
|
8177
|
+
const filteredItems = items.filter((item) => item.id !== itemId);
|
|
8178
|
+
saveLocalCart(appId, filteredItems);
|
|
8179
|
+
return filteredItems;
|
|
8180
|
+
}
|
|
8181
|
+
function getLocalCartItemCount(appId) {
|
|
8182
|
+
const items = getLocalCartItems(appId);
|
|
8183
|
+
return items.reduce((sum, item) => sum + item.quantity, 0);
|
|
8184
|
+
}
|
|
8185
|
+
|
|
8186
|
+
// src/hooks/useCart.ts
|
|
8187
|
+
function getConfig2(options) {
|
|
8188
|
+
if (typeof window === "undefined") {
|
|
8189
|
+
throw new Error("useCart requires browser environment");
|
|
8190
|
+
}
|
|
8191
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8192
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8193
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8194
|
+
if (!appId) {
|
|
8195
|
+
throw new Error("App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)");
|
|
8196
|
+
}
|
|
8197
|
+
if (!apiUrl) {
|
|
8198
|
+
throw new Error("API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)");
|
|
8199
|
+
}
|
|
8200
|
+
return { appId, apiUrl };
|
|
8201
|
+
}
|
|
8202
|
+
function useCart(options = {}) {
|
|
8203
|
+
const { userToken } = options;
|
|
8204
|
+
const [items, setItems] = useState20([]);
|
|
8205
|
+
const [isLoading, setIsLoading] = useState20(true);
|
|
8206
|
+
const [error, setError] = useState20(null);
|
|
8207
|
+
const fetchVersion = useRef22(0);
|
|
8208
|
+
const configRef = useRef22(null);
|
|
8209
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8210
|
+
try {
|
|
8211
|
+
configRef.current = getConfig2(options);
|
|
8212
|
+
} catch {
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8215
|
+
const isAuthenticated = !!userToken;
|
|
8216
|
+
const sessionId = typeof window !== "undefined" ? getSessionId() : null;
|
|
8217
|
+
const apiCall = useCallback22(async (endpoint, method = "GET", body) => {
|
|
8218
|
+
const config = configRef.current;
|
|
8219
|
+
if (!config) throw new Error("Cart not configured");
|
|
8220
|
+
const headers = {
|
|
8221
|
+
"Content-Type": "application/json"
|
|
8222
|
+
};
|
|
8223
|
+
if (isAuthenticated) {
|
|
8224
|
+
headers["X-App-User-Token"] = userToken;
|
|
8225
|
+
} else if (sessionId) {
|
|
8226
|
+
headers["X-Session-Id"] = sessionId;
|
|
8227
|
+
}
|
|
8228
|
+
const response = await fetch(
|
|
8229
|
+
`${config.apiUrl}/api/apps/${config.appId}/cart${endpoint}`,
|
|
8230
|
+
{
|
|
8231
|
+
method,
|
|
8232
|
+
headers,
|
|
8233
|
+
body: body ? JSON.stringify(body) : void 0
|
|
8234
|
+
}
|
|
8235
|
+
);
|
|
8236
|
+
return response.json();
|
|
8237
|
+
}, [userToken, isAuthenticated, sessionId]);
|
|
8238
|
+
const fetchCart = useCallback22(async () => {
|
|
8239
|
+
const config = configRef.current;
|
|
8240
|
+
if (!config) {
|
|
8241
|
+
setIsLoading(false);
|
|
8242
|
+
setError("Cart not configured");
|
|
8243
|
+
return;
|
|
8244
|
+
}
|
|
8245
|
+
const version = ++fetchVersion.current;
|
|
8246
|
+
setIsLoading(true);
|
|
8247
|
+
setError(null);
|
|
8248
|
+
try {
|
|
8249
|
+
if (isAuthenticated || sessionId) {
|
|
8250
|
+
const result = await apiCall("");
|
|
8251
|
+
if (version !== fetchVersion.current) return;
|
|
8252
|
+
if (result.success && result.data) {
|
|
8253
|
+
setItems(result.data.items);
|
|
8254
|
+
} else {
|
|
8255
|
+
if (!isAuthenticated) {
|
|
8256
|
+
setItems(getLocalCartItems(config.appId));
|
|
8257
|
+
} else {
|
|
8258
|
+
setError(result.error || "Failed to fetch cart");
|
|
8259
|
+
}
|
|
8260
|
+
}
|
|
8261
|
+
} else {
|
|
8262
|
+
setItems(getLocalCartItems(config.appId));
|
|
8263
|
+
}
|
|
8264
|
+
} catch (err) {
|
|
8265
|
+
if (version !== fetchVersion.current) return;
|
|
8266
|
+
if (!isAuthenticated) {
|
|
8267
|
+
setItems(getLocalCartItems(config.appId));
|
|
8268
|
+
} else {
|
|
8269
|
+
setError(err instanceof Error ? err.message : "Failed to fetch cart");
|
|
8270
|
+
}
|
|
8271
|
+
} finally {
|
|
8272
|
+
if (version === fetchVersion.current) {
|
|
8273
|
+
setIsLoading(false);
|
|
8274
|
+
}
|
|
8275
|
+
}
|
|
8276
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8277
|
+
useEffect21(() => {
|
|
8278
|
+
fetchCart();
|
|
8279
|
+
}, [fetchCart]);
|
|
8280
|
+
const addItem = useCallback22(async (productId, collectionSlug, quantity = 1, variantId, data) => {
|
|
8281
|
+
const config = configRef.current;
|
|
8282
|
+
if (!config) throw new Error("Cart not configured");
|
|
8283
|
+
setError(null);
|
|
8284
|
+
try {
|
|
8285
|
+
if (isAuthenticated || sessionId) {
|
|
8286
|
+
const result = await apiCall("/items", "POST", {
|
|
8287
|
+
productId,
|
|
8288
|
+
collectionSlug,
|
|
8289
|
+
quantity,
|
|
8290
|
+
variantId,
|
|
8291
|
+
data
|
|
8292
|
+
});
|
|
8293
|
+
if (result.success && result.data) {
|
|
8294
|
+
setItems(result.data.items);
|
|
8295
|
+
} else {
|
|
8296
|
+
throw new Error(result.error || "Failed to add item");
|
|
8297
|
+
}
|
|
8298
|
+
} else {
|
|
8299
|
+
const newItems = addLocalCartItem(config.appId, productId, collectionSlug, quantity, variantId, data);
|
|
8300
|
+
setItems(newItems);
|
|
8301
|
+
}
|
|
8302
|
+
} catch (err) {
|
|
8303
|
+
const message = err instanceof Error ? err.message : "Failed to add item";
|
|
8304
|
+
setError(message);
|
|
8305
|
+
throw err;
|
|
8306
|
+
}
|
|
8307
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8308
|
+
const updateQuantity = useCallback22(async (itemId, quantity) => {
|
|
8309
|
+
const config = configRef.current;
|
|
8310
|
+
if (!config) throw new Error("Cart not configured");
|
|
8311
|
+
setError(null);
|
|
8312
|
+
try {
|
|
8313
|
+
if (isAuthenticated || sessionId) {
|
|
8314
|
+
const result = await apiCall(`/items/${itemId}`, "PATCH", { quantity });
|
|
8315
|
+
if (result.success && result.data) {
|
|
8316
|
+
setItems(result.data.items);
|
|
8317
|
+
} else {
|
|
8318
|
+
throw new Error(result.error || "Failed to update item");
|
|
8319
|
+
}
|
|
8320
|
+
} else {
|
|
8321
|
+
const newItems = updateLocalCartItem(config.appId, itemId, quantity);
|
|
8322
|
+
setItems(newItems);
|
|
8323
|
+
}
|
|
8324
|
+
} catch (err) {
|
|
8325
|
+
const message = err instanceof Error ? err.message : "Failed to update item";
|
|
8326
|
+
setError(message);
|
|
8327
|
+
throw err;
|
|
8328
|
+
}
|
|
8329
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8330
|
+
const removeItem = useCallback22(async (itemId) => {
|
|
8331
|
+
const config = configRef.current;
|
|
8332
|
+
if (!config) throw new Error("Cart not configured");
|
|
8333
|
+
setError(null);
|
|
8334
|
+
try {
|
|
8335
|
+
if (isAuthenticated || sessionId) {
|
|
8336
|
+
const result = await apiCall(`/items/${itemId}`, "DELETE");
|
|
8337
|
+
if (result.success && result.data) {
|
|
8338
|
+
setItems(result.data.items);
|
|
8339
|
+
} else {
|
|
8340
|
+
throw new Error(result.error || "Failed to remove item");
|
|
8341
|
+
}
|
|
8342
|
+
} else {
|
|
8343
|
+
const newItems = removeLocalCartItem(config.appId, itemId);
|
|
8344
|
+
setItems(newItems);
|
|
8345
|
+
}
|
|
8346
|
+
} catch (err) {
|
|
8347
|
+
const message = err instanceof Error ? err.message : "Failed to remove item";
|
|
8348
|
+
setError(message);
|
|
8349
|
+
throw err;
|
|
8350
|
+
}
|
|
8351
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8352
|
+
const clearCart = useCallback22(async () => {
|
|
8353
|
+
const config = configRef.current;
|
|
8354
|
+
if (!config) throw new Error("Cart not configured");
|
|
8355
|
+
setError(null);
|
|
8356
|
+
try {
|
|
8357
|
+
if (isAuthenticated || sessionId) {
|
|
8358
|
+
const result = await apiCall("", "DELETE");
|
|
8359
|
+
if (result.success) {
|
|
8360
|
+
setItems([]);
|
|
8361
|
+
} else {
|
|
8362
|
+
throw new Error(result.error || "Failed to clear cart");
|
|
8363
|
+
}
|
|
8364
|
+
} else {
|
|
8365
|
+
clearLocalCart(config.appId);
|
|
8366
|
+
setItems([]);
|
|
8367
|
+
}
|
|
8368
|
+
} catch (err) {
|
|
8369
|
+
const message = err instanceof Error ? err.message : "Failed to clear cart";
|
|
8370
|
+
setError(message);
|
|
8371
|
+
throw err;
|
|
8372
|
+
}
|
|
8373
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8374
|
+
const mergeGuestCart = useCallback22(async () => {
|
|
8375
|
+
if (!isAuthenticated || !sessionId) return;
|
|
8376
|
+
setError(null);
|
|
8377
|
+
try {
|
|
8378
|
+
const result = await apiCall("/merge", "POST", {
|
|
8379
|
+
guestSessionId: sessionId,
|
|
8380
|
+
mergeStrategy: "sum"
|
|
8381
|
+
});
|
|
8382
|
+
if (result.success && result.data) {
|
|
8383
|
+
setItems(result.data.items);
|
|
8384
|
+
if (configRef.current) {
|
|
8385
|
+
clearLocalCart(configRef.current.appId);
|
|
8386
|
+
}
|
|
8387
|
+
} else {
|
|
8388
|
+
throw new Error(result.error || "Failed to merge cart");
|
|
8389
|
+
}
|
|
8390
|
+
} catch (err) {
|
|
8391
|
+
const message = err instanceof Error ? err.message : "Failed to merge cart";
|
|
8392
|
+
setError(message);
|
|
8393
|
+
}
|
|
8394
|
+
}, [apiCall, isAuthenticated, sessionId]);
|
|
8395
|
+
const itemCount = items.reduce((sum, item) => sum + item.quantity, 0);
|
|
8396
|
+
return {
|
|
8397
|
+
items,
|
|
8398
|
+
itemCount,
|
|
8399
|
+
isLoading,
|
|
8400
|
+
error,
|
|
8401
|
+
addItem,
|
|
8402
|
+
updateQuantity,
|
|
8403
|
+
removeItem,
|
|
8404
|
+
clearCart,
|
|
8405
|
+
mergeGuestCart,
|
|
8406
|
+
refresh: fetchCart
|
|
8407
|
+
};
|
|
8408
|
+
}
|
|
8409
|
+
|
|
8410
|
+
// src/contexts/CartContext.tsx
|
|
8411
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
8412
|
+
var CartContext = createContext5(null);
|
|
8413
|
+
function CartProvider({
|
|
8414
|
+
children,
|
|
8415
|
+
userToken,
|
|
8416
|
+
onUserTokenChange,
|
|
8417
|
+
...options
|
|
8418
|
+
}) {
|
|
8419
|
+
const cart = useCart({ ...options, userToken });
|
|
8420
|
+
useEffect22(() => {
|
|
8421
|
+
if (userToken) {
|
|
8422
|
+
cart.mergeGuestCart();
|
|
8423
|
+
}
|
|
8424
|
+
onUserTokenChange?.(!!userToken);
|
|
8425
|
+
}, [userToken]);
|
|
8426
|
+
return /* @__PURE__ */ jsx26(CartContext.Provider, { value: cart, children });
|
|
8427
|
+
}
|
|
8428
|
+
function useCartContext() {
|
|
8429
|
+
const context = useContext5(CartContext);
|
|
8430
|
+
if (!context) {
|
|
8431
|
+
throw new Error("useCartContext must be used within a CartProvider");
|
|
8432
|
+
}
|
|
8433
|
+
return context;
|
|
8434
|
+
}
|
|
8435
|
+
function useOptionalCartContext() {
|
|
8436
|
+
return useContext5(CartContext);
|
|
8437
|
+
}
|
|
8438
|
+
|
|
8439
|
+
// src/hooks/useCheckout.ts
|
|
8440
|
+
import { useState as useState21, useCallback as useCallback23, useRef as useRef23 } from "react";
|
|
8441
|
+
function getConfig3(options) {
|
|
8442
|
+
if (typeof window === "undefined") {
|
|
8443
|
+
throw new Error("useCheckout requires browser environment");
|
|
8444
|
+
}
|
|
8445
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8446
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8447
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8448
|
+
if (!appId) {
|
|
8449
|
+
throw new Error("App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)");
|
|
8450
|
+
}
|
|
8451
|
+
if (!apiUrl) {
|
|
8452
|
+
throw new Error("API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)");
|
|
8453
|
+
}
|
|
8454
|
+
return { appId, apiUrl };
|
|
8455
|
+
}
|
|
8456
|
+
function useCheckout(options = {}) {
|
|
8457
|
+
const { userToken } = options;
|
|
8458
|
+
const [isLoading, setIsLoading] = useState21(false);
|
|
8459
|
+
const [error, setError] = useState21(null);
|
|
8460
|
+
const configRef = useRef23(null);
|
|
8461
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8462
|
+
try {
|
|
8463
|
+
configRef.current = getConfig3(options);
|
|
8464
|
+
} catch {
|
|
8465
|
+
}
|
|
8466
|
+
}
|
|
8467
|
+
const isAuthenticated = !!userToken;
|
|
8468
|
+
const sessionId = typeof window !== "undefined" ? getSessionId() : null;
|
|
8469
|
+
const initiateCheckout = useCallback23(async (checkoutOptions) => {
|
|
8470
|
+
const config = configRef.current;
|
|
8471
|
+
if (!config) {
|
|
8472
|
+
throw new Error("Checkout not configured");
|
|
8473
|
+
}
|
|
8474
|
+
setIsLoading(true);
|
|
8475
|
+
setError(null);
|
|
8476
|
+
try {
|
|
8477
|
+
const headers = {
|
|
8478
|
+
"Content-Type": "application/json"
|
|
8479
|
+
};
|
|
8480
|
+
if (isAuthenticated) {
|
|
8481
|
+
headers["X-App-User-Token"] = userToken;
|
|
8482
|
+
} else if (sessionId) {
|
|
8483
|
+
headers["X-Session-Id"] = sessionId;
|
|
8484
|
+
}
|
|
8485
|
+
const response = await fetch(
|
|
8486
|
+
`${config.apiUrl}/api/apps/${config.appId}/checkout/session`,
|
|
8487
|
+
{
|
|
8488
|
+
method: "POST",
|
|
8489
|
+
headers,
|
|
8490
|
+
body: JSON.stringify(checkoutOptions)
|
|
8491
|
+
}
|
|
8492
|
+
);
|
|
8493
|
+
const result = await response.json();
|
|
8494
|
+
if (!result.success || !result.data) {
|
|
8495
|
+
throw new Error(result.error || "Failed to create checkout session");
|
|
8496
|
+
}
|
|
8497
|
+
return result.data;
|
|
8498
|
+
} catch (err) {
|
|
8499
|
+
const message = err instanceof Error ? err.message : "Failed to initiate checkout";
|
|
8500
|
+
setError(message);
|
|
8501
|
+
throw err;
|
|
8502
|
+
} finally {
|
|
8503
|
+
setIsLoading(false);
|
|
8504
|
+
}
|
|
8505
|
+
}, [userToken, isAuthenticated, sessionId]);
|
|
8506
|
+
return {
|
|
8507
|
+
initiateCheckout,
|
|
8508
|
+
isLoading,
|
|
8509
|
+
error
|
|
8510
|
+
};
|
|
8511
|
+
}
|
|
8512
|
+
function useCheckoutStatus(options) {
|
|
8513
|
+
const { userToken, sessionId: checkoutSessionId, poll = false, pollInterval = 2e3 } = options;
|
|
8514
|
+
const [status, setStatus] = useState21(null);
|
|
8515
|
+
const [isLoading, setIsLoading] = useState21(true);
|
|
8516
|
+
const [error, setError] = useState21(null);
|
|
8517
|
+
const configRef = useRef23(null);
|
|
8518
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8519
|
+
try {
|
|
8520
|
+
configRef.current = getConfig3(options);
|
|
8521
|
+
} catch {
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
const isAuthenticated = !!userToken;
|
|
8525
|
+
const guestSessionId = typeof window !== "undefined" ? getSessionId() : null;
|
|
8526
|
+
const fetchStatus = useCallback23(async () => {
|
|
8527
|
+
const config = configRef.current;
|
|
8528
|
+
if (!config || !checkoutSessionId) {
|
|
8529
|
+
setIsLoading(false);
|
|
8530
|
+
return;
|
|
8531
|
+
}
|
|
8532
|
+
try {
|
|
8533
|
+
const headers = {
|
|
8534
|
+
"Content-Type": "application/json"
|
|
8535
|
+
};
|
|
8536
|
+
if (isAuthenticated) {
|
|
8537
|
+
headers["X-App-User-Token"] = userToken;
|
|
8538
|
+
} else if (guestSessionId) {
|
|
8539
|
+
headers["X-Session-Id"] = guestSessionId;
|
|
8540
|
+
}
|
|
8541
|
+
const response = await fetch(
|
|
8542
|
+
`${config.apiUrl}/api/apps/${config.appId}/checkout/session/${checkoutSessionId}/status`,
|
|
8543
|
+
{ headers }
|
|
8544
|
+
);
|
|
8545
|
+
const result = await response.json();
|
|
8546
|
+
if (result.success && result.data) {
|
|
8547
|
+
setStatus(result.data);
|
|
8548
|
+
setError(null);
|
|
8549
|
+
} else {
|
|
8550
|
+
setError(result.error || "Failed to fetch status");
|
|
8551
|
+
}
|
|
8552
|
+
} catch (err) {
|
|
8553
|
+
setError(err instanceof Error ? err.message : "Failed to fetch status");
|
|
8554
|
+
} finally {
|
|
8555
|
+
setIsLoading(false);
|
|
8556
|
+
}
|
|
8557
|
+
}, [checkoutSessionId, userToken, isAuthenticated, guestSessionId]);
|
|
8558
|
+
useState21(() => {
|
|
8559
|
+
fetchStatus();
|
|
8560
|
+
if (poll) {
|
|
8561
|
+
const interval = setInterval(() => {
|
|
8562
|
+
if (status?.paymentStatus === "paid" || status?.status === "expired") {
|
|
8563
|
+
return;
|
|
8564
|
+
}
|
|
8565
|
+
fetchStatus();
|
|
8566
|
+
}, pollInterval);
|
|
8567
|
+
return () => clearInterval(interval);
|
|
8568
|
+
}
|
|
8569
|
+
});
|
|
8570
|
+
return {
|
|
8571
|
+
status,
|
|
8572
|
+
isLoading,
|
|
8573
|
+
error,
|
|
8574
|
+
refresh: fetchStatus
|
|
8575
|
+
};
|
|
8576
|
+
}
|
|
8577
|
+
|
|
8578
|
+
// src/hooks/useProducts.ts
|
|
8579
|
+
function useProducts(options = {}) {
|
|
8580
|
+
const {
|
|
8581
|
+
collection = "products",
|
|
8582
|
+
activeOnly = true,
|
|
8583
|
+
category,
|
|
8584
|
+
productType,
|
|
8585
|
+
filters = [],
|
|
8586
|
+
page,
|
|
8587
|
+
pageSize,
|
|
8588
|
+
orderBy = "createdAt",
|
|
8589
|
+
orderDir = "desc",
|
|
8590
|
+
enabled
|
|
8591
|
+
} = options;
|
|
8592
|
+
const allFilters = [...filters];
|
|
8593
|
+
if (activeOnly) {
|
|
8594
|
+
allFilters.push({
|
|
8595
|
+
field: "status",
|
|
8596
|
+
operator: "eq",
|
|
8597
|
+
value: "active"
|
|
8598
|
+
});
|
|
8599
|
+
}
|
|
8600
|
+
if (category) {
|
|
8601
|
+
allFilters.push({
|
|
8602
|
+
field: "category",
|
|
8603
|
+
operator: "eq",
|
|
8604
|
+
value: category
|
|
8605
|
+
});
|
|
8606
|
+
}
|
|
8607
|
+
if (productType) {
|
|
8608
|
+
allFilters.push({
|
|
8609
|
+
field: "productType",
|
|
8610
|
+
operator: "eq",
|
|
8611
|
+
value: productType
|
|
8612
|
+
});
|
|
8613
|
+
}
|
|
8614
|
+
const result = useCollectionList({
|
|
8615
|
+
collection,
|
|
8616
|
+
filters: allFilters,
|
|
8617
|
+
page,
|
|
8618
|
+
pageSize,
|
|
8619
|
+
orderBy,
|
|
8620
|
+
orderDir,
|
|
8621
|
+
enabled
|
|
8622
|
+
});
|
|
8623
|
+
return {
|
|
8624
|
+
...result,
|
|
8625
|
+
products: result.data
|
|
8626
|
+
};
|
|
8627
|
+
}
|
|
8628
|
+
function useProduct(options) {
|
|
8629
|
+
const { collection = "products", slug, enabled = true } = options;
|
|
8630
|
+
const result = useCollectionList({
|
|
8631
|
+
collection,
|
|
8632
|
+
filters: [
|
|
8633
|
+
{ field: "slug", operator: "eq", value: slug }
|
|
8634
|
+
],
|
|
8635
|
+
pageSize: 1,
|
|
8636
|
+
enabled: enabled && !!slug
|
|
8637
|
+
});
|
|
8638
|
+
const product = result.data?.[0] || null;
|
|
8639
|
+
const notFound = !result.isLoading && !product && !result.error;
|
|
8640
|
+
return {
|
|
8641
|
+
product,
|
|
8642
|
+
isLoading: result.isLoading,
|
|
8643
|
+
error: result.error,
|
|
8644
|
+
notFound,
|
|
8645
|
+
refetch: result.refetch
|
|
8646
|
+
};
|
|
8647
|
+
}
|
|
8648
|
+
|
|
8649
|
+
// src/hooks/useSubscription.ts
|
|
8650
|
+
import { useState as useState22, useCallback as useCallback24, useRef as useRef24 } from "react";
|
|
8651
|
+
function getConfig4(options) {
|
|
8652
|
+
if (typeof window === "undefined") {
|
|
8653
|
+
throw new Error("useSubscription requires browser environment");
|
|
8654
|
+
}
|
|
8655
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8656
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8657
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8658
|
+
if (!appId) {
|
|
8659
|
+
throw new Error("App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)");
|
|
8660
|
+
}
|
|
8661
|
+
if (!apiUrl) {
|
|
8662
|
+
throw new Error("API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)");
|
|
8663
|
+
}
|
|
8664
|
+
return { appId, apiUrl };
|
|
8665
|
+
}
|
|
8666
|
+
function useSubscription(options = {}) {
|
|
8667
|
+
const { userToken } = options;
|
|
8668
|
+
const [isLoading, setIsLoading] = useState22(false);
|
|
8669
|
+
const [error, setError] = useState22(null);
|
|
8670
|
+
const configRef = useRef24(null);
|
|
8671
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8672
|
+
try {
|
|
8673
|
+
configRef.current = getConfig4(options);
|
|
8674
|
+
} catch {
|
|
8675
|
+
}
|
|
8676
|
+
}
|
|
8677
|
+
const subscribe = useCallback24(async (params) => {
|
|
8678
|
+
const config = configRef.current;
|
|
8679
|
+
if (!config) {
|
|
8680
|
+
return {
|
|
8681
|
+
success: false,
|
|
8682
|
+
error: "Subscription not configured"
|
|
8683
|
+
};
|
|
8684
|
+
}
|
|
8685
|
+
setIsLoading(true);
|
|
8686
|
+
setError(null);
|
|
8687
|
+
try {
|
|
8688
|
+
const headers = {
|
|
8689
|
+
"Content-Type": "application/json"
|
|
8690
|
+
};
|
|
8691
|
+
if (userToken) {
|
|
8692
|
+
headers["X-App-User-Token"] = userToken;
|
|
8693
|
+
}
|
|
8694
|
+
const response = await fetch(
|
|
8695
|
+
`${config.apiUrl}/api/apps/${config.appId}/subscriptions/checkout`,
|
|
8696
|
+
{
|
|
8697
|
+
method: "POST",
|
|
8698
|
+
headers,
|
|
8699
|
+
body: JSON.stringify({
|
|
8700
|
+
tierSlug: params.tierSlug,
|
|
8701
|
+
successUrl: params.successUrl,
|
|
8702
|
+
cancelUrl: params.cancelUrl,
|
|
8703
|
+
quantity: params.quantity,
|
|
8704
|
+
trialDays: params.trialDays,
|
|
8705
|
+
customerEmail: params.customerEmail,
|
|
8706
|
+
metadata: params.metadata
|
|
8707
|
+
})
|
|
8708
|
+
}
|
|
8709
|
+
);
|
|
8710
|
+
const result = await response.json();
|
|
8711
|
+
if (!result.success || !result.data) {
|
|
8712
|
+
const errorMessage = result.error || "Failed to create subscription checkout";
|
|
8713
|
+
setError(errorMessage);
|
|
8714
|
+
return {
|
|
8715
|
+
success: false,
|
|
8716
|
+
error: errorMessage
|
|
8717
|
+
};
|
|
8718
|
+
}
|
|
8719
|
+
return {
|
|
8720
|
+
success: true,
|
|
8721
|
+
checkoutUrl: result.data.url,
|
|
8722
|
+
sessionId: result.data.sessionId
|
|
8723
|
+
};
|
|
8724
|
+
} catch (err) {
|
|
8725
|
+
const message = err instanceof Error ? err.message : "Failed to create subscription checkout";
|
|
8726
|
+
setError(message);
|
|
8727
|
+
return {
|
|
8728
|
+
success: false,
|
|
8729
|
+
error: message
|
|
8730
|
+
};
|
|
8731
|
+
} finally {
|
|
8732
|
+
setIsLoading(false);
|
|
8733
|
+
}
|
|
8734
|
+
}, [userToken]);
|
|
8735
|
+
return {
|
|
8736
|
+
subscribe,
|
|
8737
|
+
isLoading,
|
|
8738
|
+
error
|
|
8739
|
+
};
|
|
8740
|
+
}
|
|
8741
|
+
|
|
8742
|
+
// src/hooks/useSubscriptionTiers.ts
|
|
8743
|
+
import { useState as useState23, useCallback as useCallback25, useEffect as useEffect23, useRef as useRef25 } from "react";
|
|
8744
|
+
function getConfig5(options) {
|
|
8745
|
+
if (typeof window === "undefined") {
|
|
8746
|
+
throw new Error("useSubscriptionTiers requires browser environment");
|
|
8747
|
+
}
|
|
8748
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8749
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8750
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8751
|
+
if (!appId) {
|
|
8752
|
+
throw new Error(
|
|
8753
|
+
"App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)"
|
|
8754
|
+
);
|
|
8755
|
+
}
|
|
8756
|
+
if (!apiUrl) {
|
|
8757
|
+
throw new Error(
|
|
8758
|
+
"API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)"
|
|
8759
|
+
);
|
|
8760
|
+
}
|
|
8761
|
+
return { appId, apiUrl };
|
|
8762
|
+
}
|
|
8763
|
+
function useSubscriptionTiers(options = {}) {
|
|
8764
|
+
const { fetchOnMount = true } = options;
|
|
8765
|
+
const [tiers, setTiers] = useState23([]);
|
|
8766
|
+
const [isLoading, setIsLoading] = useState23(false);
|
|
8767
|
+
const [error, setError] = useState23(null);
|
|
8768
|
+
const configRef = useRef25(null);
|
|
8769
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8770
|
+
try {
|
|
8771
|
+
configRef.current = getConfig5(options);
|
|
8772
|
+
} catch {
|
|
8773
|
+
}
|
|
8774
|
+
}
|
|
8775
|
+
const refresh = useCallback25(async () => {
|
|
8776
|
+
const config = configRef.current;
|
|
8777
|
+
if (!config) {
|
|
8778
|
+
setError("Subscription tiers not configured");
|
|
8779
|
+
return;
|
|
8780
|
+
}
|
|
8781
|
+
setIsLoading(true);
|
|
8782
|
+
setError(null);
|
|
8783
|
+
try {
|
|
8784
|
+
const response = await fetch(
|
|
8785
|
+
`${config.apiUrl}/api/apps/${config.appId}/subscriptions/tiers`,
|
|
8786
|
+
{
|
|
8787
|
+
method: "GET",
|
|
8788
|
+
headers: {
|
|
8789
|
+
"Content-Type": "application/json"
|
|
8790
|
+
}
|
|
8791
|
+
}
|
|
8792
|
+
);
|
|
8793
|
+
const result = await response.json();
|
|
8794
|
+
if (!result.success || !result.data) {
|
|
8795
|
+
const errorMessage = result.error || "Failed to fetch subscription tiers";
|
|
8796
|
+
setError(errorMessage);
|
|
8797
|
+
return;
|
|
8798
|
+
}
|
|
8799
|
+
setTiers(result.data.tiers);
|
|
8800
|
+
} catch (err) {
|
|
8801
|
+
const message = err instanceof Error ? err.message : "Failed to fetch subscription tiers";
|
|
8802
|
+
setError(message);
|
|
8803
|
+
} finally {
|
|
8804
|
+
setIsLoading(false);
|
|
8805
|
+
}
|
|
8806
|
+
}, []);
|
|
8807
|
+
useEffect23(() => {
|
|
8808
|
+
if (fetchOnMount && configRef.current) {
|
|
8809
|
+
refresh();
|
|
8810
|
+
}
|
|
8811
|
+
}, [fetchOnMount, refresh]);
|
|
8812
|
+
return {
|
|
8813
|
+
tiers,
|
|
8814
|
+
isLoading,
|
|
8815
|
+
error,
|
|
8816
|
+
refresh
|
|
8817
|
+
};
|
|
8818
|
+
}
|
|
8819
|
+
|
|
8820
|
+
// src/hooks/useCustomerPortal.ts
|
|
8821
|
+
import { useState as useState24, useCallback as useCallback26, useRef as useRef26 } from "react";
|
|
8822
|
+
function getConfig6(options) {
|
|
8823
|
+
if (typeof window === "undefined") {
|
|
8824
|
+
throw new Error("useCustomerPortal requires browser environment");
|
|
8825
|
+
}
|
|
8826
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8827
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8828
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8829
|
+
if (!appId) {
|
|
8830
|
+
throw new Error("App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)");
|
|
8831
|
+
}
|
|
8832
|
+
if (!apiUrl) {
|
|
8833
|
+
throw new Error("API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)");
|
|
8834
|
+
}
|
|
8835
|
+
return { appId, apiUrl };
|
|
8836
|
+
}
|
|
8837
|
+
function useCustomerPortal(options) {
|
|
8838
|
+
const { userToken } = options;
|
|
8839
|
+
const [isLoading, setIsLoading] = useState24(false);
|
|
8840
|
+
const [error, setError] = useState24(null);
|
|
8841
|
+
const configRef = useRef26(null);
|
|
8842
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8843
|
+
try {
|
|
8844
|
+
configRef.current = getConfig6(options);
|
|
8845
|
+
} catch {
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
const openPortal = useCallback26(async (params) => {
|
|
8849
|
+
const config = configRef.current;
|
|
8850
|
+
if (!config) {
|
|
8851
|
+
return {
|
|
8852
|
+
success: false,
|
|
8853
|
+
error: "Customer portal not configured"
|
|
8854
|
+
};
|
|
8855
|
+
}
|
|
8856
|
+
if (!userToken) {
|
|
8857
|
+
return {
|
|
8858
|
+
success: false,
|
|
8859
|
+
error: "Authentication required to access customer portal"
|
|
8860
|
+
};
|
|
8861
|
+
}
|
|
8862
|
+
setIsLoading(true);
|
|
8863
|
+
setError(null);
|
|
8864
|
+
try {
|
|
8865
|
+
const response = await fetch(
|
|
8866
|
+
`${config.apiUrl}/api/apps/${config.appId}/subscriptions/portal`,
|
|
8867
|
+
{
|
|
8868
|
+
method: "POST",
|
|
8869
|
+
headers: {
|
|
8870
|
+
"Content-Type": "application/json",
|
|
8871
|
+
"X-App-User-Token": userToken
|
|
8872
|
+
},
|
|
8873
|
+
body: JSON.stringify({
|
|
8874
|
+
returnUrl: params.returnUrl
|
|
8875
|
+
})
|
|
8876
|
+
}
|
|
8877
|
+
);
|
|
8878
|
+
const result = await response.json();
|
|
8879
|
+
if (!result.success || !result.data) {
|
|
8880
|
+
const errorMessage = result.error || "Failed to create portal session";
|
|
8881
|
+
setError(errorMessage);
|
|
8882
|
+
return {
|
|
8883
|
+
success: false,
|
|
8884
|
+
error: errorMessage
|
|
8885
|
+
};
|
|
8886
|
+
}
|
|
8887
|
+
return {
|
|
8888
|
+
success: true,
|
|
8889
|
+
portalUrl: result.data.portalUrl
|
|
8890
|
+
};
|
|
8891
|
+
} catch (err) {
|
|
8892
|
+
const message = err instanceof Error ? err.message : "Failed to create portal session";
|
|
8893
|
+
setError(message);
|
|
8894
|
+
return {
|
|
8895
|
+
success: false,
|
|
8896
|
+
error: message
|
|
8897
|
+
};
|
|
8898
|
+
} finally {
|
|
8899
|
+
setIsLoading(false);
|
|
8900
|
+
}
|
|
8901
|
+
}, [userToken]);
|
|
8902
|
+
return {
|
|
8903
|
+
openPortal,
|
|
8904
|
+
isLoading,
|
|
8905
|
+
error
|
|
8906
|
+
};
|
|
8907
|
+
}
|
|
8908
|
+
|
|
8909
|
+
// src/hooks/useSubscriptionStatus.ts
|
|
8910
|
+
import { useState as useState25, useCallback as useCallback27, useRef as useRef27, useEffect as useEffect24 } from "react";
|
|
8911
|
+
function getConfig7(options) {
|
|
8912
|
+
if (typeof window === "undefined") {
|
|
8913
|
+
throw new Error("useSubscriptionStatus requires browser environment");
|
|
8914
|
+
}
|
|
8915
|
+
const runtimeConfig = window.YOAMIGO_CONFIG;
|
|
8916
|
+
const appId = options.appId || runtimeConfig?.appId;
|
|
8917
|
+
const apiUrl = options.apiUrl || runtimeConfig?.apiUrl;
|
|
8918
|
+
if (!appId) {
|
|
8919
|
+
throw new Error("App ID not configured (provide appId option or set YOAMIGO_CONFIG.appId)");
|
|
8920
|
+
}
|
|
8921
|
+
if (!apiUrl) {
|
|
8922
|
+
throw new Error("API URL not configured (provide apiUrl option or set YOAMIGO_CONFIG.apiUrl)");
|
|
8923
|
+
}
|
|
8924
|
+
return { appId, apiUrl };
|
|
8925
|
+
}
|
|
8926
|
+
function useSubscriptionStatus(options) {
|
|
8927
|
+
const { userToken, autoFetch = true, pollInterval = 0 } = options;
|
|
8928
|
+
const [status, setStatus] = useState25(null);
|
|
8929
|
+
const [subscriptions, setSubscriptions] = useState25([]);
|
|
8930
|
+
const [isLoading, setIsLoading] = useState25(autoFetch);
|
|
8931
|
+
const [error, setError] = useState25(null);
|
|
8932
|
+
const configRef = useRef27(null);
|
|
8933
|
+
if (!configRef.current && typeof window !== "undefined") {
|
|
8934
|
+
try {
|
|
8935
|
+
configRef.current = getConfig7(options);
|
|
8936
|
+
} catch {
|
|
8937
|
+
}
|
|
8938
|
+
}
|
|
8939
|
+
const fetchStatus = useCallback27(async () => {
|
|
8940
|
+
const config = configRef.current;
|
|
8941
|
+
if (!config) {
|
|
8942
|
+
setError("Subscription status not configured");
|
|
8943
|
+
setIsLoading(false);
|
|
8944
|
+
return;
|
|
8945
|
+
}
|
|
8946
|
+
if (!userToken) {
|
|
8947
|
+
setStatus("none");
|
|
8948
|
+
setSubscriptions([]);
|
|
8949
|
+
setIsLoading(false);
|
|
8950
|
+
return;
|
|
8951
|
+
}
|
|
8952
|
+
setIsLoading(true);
|
|
8953
|
+
try {
|
|
8954
|
+
const response = await fetch(
|
|
8955
|
+
`${config.apiUrl}/api/apps/${config.appId}/subscriptions/status`,
|
|
8956
|
+
{
|
|
8957
|
+
method: "GET",
|
|
8958
|
+
headers: {
|
|
8959
|
+
"Content-Type": "application/json",
|
|
8960
|
+
"X-App-User-Token": userToken
|
|
8961
|
+
}
|
|
8962
|
+
}
|
|
8963
|
+
);
|
|
8964
|
+
const result = await response.json();
|
|
8965
|
+
if (!result.success) {
|
|
8966
|
+
setError(result.error || "Failed to fetch subscription status");
|
|
8967
|
+
return;
|
|
8968
|
+
}
|
|
8969
|
+
setStatus(result.data?.status ?? "none");
|
|
8970
|
+
setSubscriptions(result.data?.subscriptions ?? []);
|
|
8971
|
+
setError(null);
|
|
8972
|
+
} catch (err) {
|
|
8973
|
+
setError(err instanceof Error ? err.message : "Failed to fetch subscription status");
|
|
8974
|
+
} finally {
|
|
8975
|
+
setIsLoading(false);
|
|
8976
|
+
}
|
|
8977
|
+
}, [userToken]);
|
|
8978
|
+
useEffect24(() => {
|
|
8979
|
+
if (autoFetch && userToken) {
|
|
8980
|
+
fetchStatus();
|
|
8981
|
+
}
|
|
8982
|
+
}, [autoFetch, userToken, fetchStatus]);
|
|
8983
|
+
useEffect24(() => {
|
|
8984
|
+
if (pollInterval <= 0 || !userToken) {
|
|
8985
|
+
return;
|
|
8986
|
+
}
|
|
8987
|
+
const interval = setInterval(() => {
|
|
8988
|
+
fetchStatus();
|
|
8989
|
+
}, pollInterval);
|
|
8990
|
+
return () => clearInterval(interval);
|
|
8991
|
+
}, [pollInterval, userToken, fetchStatus]);
|
|
8992
|
+
return {
|
|
8993
|
+
status,
|
|
8994
|
+
subscriptions,
|
|
8995
|
+
isLoading,
|
|
8996
|
+
error,
|
|
8997
|
+
refresh: fetchStatus
|
|
8998
|
+
};
|
|
8999
|
+
}
|
|
7125
9000
|
export {
|
|
7126
9001
|
AIEditProvider,
|
|
9002
|
+
CartProvider,
|
|
9003
|
+
CollectionClient,
|
|
9004
|
+
CollectionContentProvider,
|
|
9005
|
+
CollectionDetailPage,
|
|
9006
|
+
CollectionItem,
|
|
9007
|
+
CollectionList,
|
|
9008
|
+
CollectionListPage,
|
|
7127
9009
|
ContentStoreProvider,
|
|
7128
9010
|
ContentStoreProvider2 as ContentStoreProviderProd,
|
|
7129
9011
|
Link2 as Link,
|
|
@@ -7146,12 +9028,21 @@ export {
|
|
|
7146
9028
|
background,
|
|
7147
9029
|
buildIntermediateText,
|
|
7148
9030
|
calculateAnimationTiming,
|
|
9031
|
+
clearSessionId,
|
|
7149
9032
|
computeTextDiff,
|
|
7150
9033
|
containsHtml,
|
|
7151
9034
|
contentRegistry,
|
|
9035
|
+
createRouteDefinition,
|
|
7152
9036
|
embed,
|
|
9037
|
+
extractRouteParams,
|
|
9038
|
+
filePathToRoutePath,
|
|
9039
|
+
generatePath,
|
|
7153
9040
|
getAllContent,
|
|
9041
|
+
getCollectionClient,
|
|
7154
9042
|
getContent,
|
|
9043
|
+
getLocalCartItemCount,
|
|
9044
|
+
getLocalCartItems,
|
|
9045
|
+
getSessionId,
|
|
7155
9046
|
getTextCursorPosition,
|
|
7156
9047
|
hasContent,
|
|
7157
9048
|
image,
|
|
@@ -7160,13 +9051,17 @@ export {
|
|
|
7160
9051
|
linkTransitionStrategy,
|
|
7161
9052
|
parseBackgroundConfig,
|
|
7162
9053
|
parseEmbedUrl,
|
|
9054
|
+
parseFieldValue,
|
|
7163
9055
|
registerContent,
|
|
9056
|
+
resetCollectionClient,
|
|
7164
9057
|
resolveAssetUrl,
|
|
7165
9058
|
serializeBackgroundConfig,
|
|
7166
9059
|
serializeEmbedValue,
|
|
7167
9060
|
serializeImageValue,
|
|
7168
9061
|
serializeVideoValue,
|
|
7169
9062
|
setAssetResolver,
|
|
9063
|
+
sortRoutesBySpecificity,
|
|
9064
|
+
stringifyFieldValue,
|
|
7170
9065
|
stripHtml,
|
|
7171
9066
|
text,
|
|
7172
9067
|
textTypingStrategy,
|
|
@@ -7174,10 +9069,26 @@ export {
|
|
|
7174
9069
|
useAIEditContext,
|
|
7175
9070
|
useAIEditContextOptional,
|
|
7176
9071
|
useAnimatedText,
|
|
9072
|
+
useCart,
|
|
9073
|
+
useCartContext,
|
|
9074
|
+
useCheckout,
|
|
9075
|
+
useCheckoutStatus,
|
|
9076
|
+
useCollectionContent,
|
|
9077
|
+
useCollectionList,
|
|
9078
|
+
useCollectionRecord,
|
|
9079
|
+
useContent,
|
|
7177
9080
|
useContentStore,
|
|
7178
9081
|
useContentStore2 as useContentStoreProd,
|
|
9082
|
+
useCustomerPortal,
|
|
9083
|
+
useLocation4 as useLocation,
|
|
7179
9084
|
useNavigate,
|
|
7180
|
-
|
|
9085
|
+
useOptionalCartContext,
|
|
9086
|
+
useParams2 as useParams,
|
|
9087
|
+
useProduct,
|
|
9088
|
+
useProducts,
|
|
7181
9089
|
useSafeTriangle,
|
|
9090
|
+
useSubscription,
|
|
9091
|
+
useSubscriptionStatus,
|
|
9092
|
+
useSubscriptionTiers,
|
|
7182
9093
|
video
|
|
7183
9094
|
};
|