@yoamigo.com/core 0.4.7 → 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/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 && href.startsWith("/")) {
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, viewport) {
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
- requestIdleCallback(() => resolve(), { timeout: 1e3 });
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);
@@ -1124,7 +1159,7 @@ function ContentStoreProvider({
1124
1159
  const defaultContent = initialContent ?? getAllContent2();
1125
1160
  const defaultMode = initialMode ?? (isBuilderPreview() ? "inline-edit" : "read-only");
1126
1161
  const [content, setContent] = useState(
1127
- new Map(Object.entries(defaultContent))
1162
+ () => new Map(Object.entries(defaultContent))
1128
1163
  );
1129
1164
  const [mode, setModeState] = useState(defaultMode);
1130
1165
  const [listeners, setListeners] = useState(/* @__PURE__ */ new Set());
@@ -1264,21 +1299,101 @@ function ContentStoreProvider({
1264
1299
  document.removeEventListener("mousedown", handleClickOutside);
1265
1300
  };
1266
1301
  }, [activeFieldId]);
1302
+ const getValueRef = useRef(getValue);
1303
+ const setValueRef = useRef(setValue);
1304
+ const getChangeSourceRef = useRef(getChangeSource);
1305
+ const setModeRef = useRef(setMode);
1306
+ const subscribeRef = useRef(subscribe);
1307
+ const saveToWorkerRef = useRef(saveToWorker);
1308
+ const modeRef = useRef(mode);
1309
+ useEffect(() => {
1310
+ getValueRef.current = getValue;
1311
+ }, [getValue]);
1312
+ useEffect(() => {
1313
+ setValueRef.current = setValue;
1314
+ }, [setValue]);
1315
+ useEffect(() => {
1316
+ getChangeSourceRef.current = getChangeSource;
1317
+ }, [getChangeSource]);
1318
+ useEffect(() => {
1319
+ setModeRef.current = setMode;
1320
+ }, [setMode]);
1321
+ useEffect(() => {
1322
+ subscribeRef.current = subscribe;
1323
+ }, [subscribe]);
1324
+ useEffect(() => {
1325
+ saveToWorkerRef.current = saveToWorker;
1326
+ }, [saveToWorker]);
1327
+ useEffect(() => {
1328
+ modeRef.current = mode;
1329
+ }, [mode]);
1330
+ const contentRef = useRef(content);
1331
+ useEffect(() => {
1332
+ contentRef.current = content;
1333
+ }, [content]);
1267
1334
  useEffect(() => {
1268
1335
  ;
1269
- window.mpContentStore = {
1270
- getValue,
1271
- setValue,
1272
- getChangeSource,
1273
- getMode: () => mode,
1274
- setMode,
1275
- subscribe,
1276
- saveToWorker
1336
+ window.yaContentStore = {
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
+ },
1359
+ getMode: () => modeRef.current,
1360
+ setMode: (mode2) => setModeRef.current(mode2),
1361
+ subscribe: (listener) => subscribeRef.current(listener),
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
+ }
1277
1392
  };
1278
1393
  return () => {
1279
- delete window.mpContentStore;
1394
+ delete window.yaContentStore;
1280
1395
  };
1281
- }, [getValue, setValue, getChangeSource, mode, setMode, subscribe, saveToWorker]);
1396
+ }, []);
1282
1397
  const getPages = useCallback(() => pages, [pages]);
1283
1398
  const value = {
1284
1399
  getValue,
@@ -1361,7 +1476,7 @@ function ContentStoreProvider2({ children, initialContent }) {
1361
1476
  }
1362
1477
 
1363
1478
  // src/components/YaText.tsx
1364
- import { useEffect as useEffect7, useRef as useRef8, useState as useState7, useCallback as useCallback9 } from "react";
1479
+ import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback10 } from "react";
1365
1480
  import { createPortal as createPortal4 } from "react-dom";
1366
1481
  import { useEditor, EditorContent } from "@tiptap/react";
1367
1482
 
@@ -1471,11 +1586,322 @@ import Link from "@tiptap/extension-link";
1471
1586
  import { TextStyle } from "@tiptap/extension-text-style";
1472
1587
  import { Extension } from "@tiptap/core";
1473
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
+
1474
1900
  // src/components/SafeHtml.tsx
1475
- import { useEffect as useEffect3, useRef as useRef3, useState as useState3, useCallback as useCallback3 } from "react";
1901
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState4, useCallback as useCallback4 } from "react";
1476
1902
  import { createPortal as createPortal2 } from "react-dom";
1477
1903
  import DOMPurify from "dompurify";
1478
- import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
1904
+ import { Fragment, jsx as jsx5, jsxs } from "react/jsx-runtime";
1479
1905
  var ALLOWED_TAGS = ["strong", "em", "a", "span", "br", "b", "i", "u"];
1480
1906
  var ALLOWED_ATTR = ["href", "style", "class", "target", "rel"];
1481
1907
  if (typeof window !== "undefined") {
@@ -1533,8 +1959,8 @@ function LinkIcon() {
1533
1959
  strokeLinecap: "round",
1534
1960
  strokeLinejoin: "round",
1535
1961
  children: [
1536
- /* @__PURE__ */ jsx4("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
1537
- /* @__PURE__ */ jsx4("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
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" })
1538
1964
  ]
1539
1965
  }
1540
1966
  );
@@ -1566,20 +1992,20 @@ function LinkPopover({
1566
1992
  }
1567
1993
  },
1568
1994
  children: [
1569
- /* @__PURE__ */ jsx4(LinkIcon, {}),
1995
+ /* @__PURE__ */ jsx5(LinkIcon, {}),
1570
1996
  /* @__PURE__ */ jsxs("span", { className: "ya-link-popover-text", children: [
1571
- /* @__PURE__ */ jsx4("span", { className: "ya-link-popover-prefix", children: "Go to " }),
1572
- /* @__PURE__ */ jsx4("span", { className: "ya-link-popover-name", children: displayText })
1997
+ /* @__PURE__ */ jsx5("span", { className: "ya-link-popover-prefix", children: "Go to " }),
1998
+ /* @__PURE__ */ jsx5("span", { className: "ya-link-popover-name", children: displayText })
1573
1999
  ] })
1574
2000
  ]
1575
2001
  }
1576
2002
  );
1577
2003
  }
1578
2004
  function SafeHtml({ content, className, mode = "read-only" }) {
1579
- const containerRef = useRef3(null);
1580
- const showTimerRef = useRef3(void 0);
1581
- const hideTimerRef = useRef3(void 0);
1582
- const [popoverState, setPopoverState] = useState3({
2005
+ const containerRef = useRef4(null);
2006
+ const showTimerRef = useRef4(void 0);
2007
+ const hideTimerRef = useRef4(void 0);
2008
+ const [popoverState, setPopoverState] = useState4({
1583
2009
  isVisible: false,
1584
2010
  href: "",
1585
2011
  displayText: "",
@@ -1590,20 +2016,20 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1590
2016
  ALLOWED_TAGS,
1591
2017
  ALLOWED_ATTR
1592
2018
  });
1593
- const hidePopover = useCallback3(() => {
2019
+ const hidePopover = useCallback4(() => {
1594
2020
  clearTimeout(showTimerRef.current);
1595
2021
  setPopoverState((prev) => ({ ...prev, isVisible: false }));
1596
2022
  }, []);
1597
- const scheduleHide = useCallback3(() => {
2023
+ const scheduleHide = useCallback4(() => {
1598
2024
  clearTimeout(showTimerRef.current);
1599
2025
  hideTimerRef.current = window.setTimeout(() => {
1600
2026
  hidePopover();
1601
2027
  }, 100);
1602
2028
  }, [hidePopover]);
1603
- const cancelHide = useCallback3(() => {
2029
+ const cancelHide = useCallback4(() => {
1604
2030
  clearTimeout(hideTimerRef.current);
1605
2031
  }, []);
1606
- const handlePopoverClick = useCallback3(() => {
2032
+ const handlePopoverClick = useCallback4(() => {
1607
2033
  if (popoverState.isExternal) {
1608
2034
  window.open(popoverState.href, "_blank", "noopener,noreferrer");
1609
2035
  } else {
@@ -1611,7 +2037,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1611
2037
  }
1612
2038
  hidePopover();
1613
2039
  }, [popoverState.href, popoverState.isExternal, hidePopover]);
1614
- useEffect3(() => {
2040
+ useEffect4(() => {
1615
2041
  if (mode !== "inline-edit" || !containerRef.current) return;
1616
2042
  const container = containerRef.current;
1617
2043
  const handleMouseOver = (e) => {
@@ -1669,7 +2095,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1669
2095
  };
1670
2096
  }, [mode, scheduleHide]);
1671
2097
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1672
- /* @__PURE__ */ jsx4(
2098
+ /* @__PURE__ */ jsx5(
1673
2099
  "span",
1674
2100
  {
1675
2101
  ref: containerRef,
@@ -1678,7 +2104,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1678
2104
  }
1679
2105
  ),
1680
2106
  mode === "inline-edit" && popoverState.isVisible && createPortal2(
1681
- /* @__PURE__ */ jsx4(
2107
+ /* @__PURE__ */ jsx5(
1682
2108
  LinkPopover,
1683
2109
  {
1684
2110
  displayText: popoverState.displayText,
@@ -1694,37 +2120,37 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1694
2120
  }
1695
2121
 
1696
2122
  // src/hooks/useAnimatedText.ts
1697
- import { useMemo as useMemo4 } from "react";
2123
+ import { useMemo as useMemo6 } from "react";
1698
2124
 
1699
2125
  // src/hooks/useAIEditAnimation.ts
1700
- import { useState as useState4, useEffect as useEffect4, useRef as useRef5, useCallback as useCallback5, useMemo as useMemo3 } from "react";
2126
+ import { useState as useState5, useEffect as useEffect5, useRef as useRef6, useCallback as useCallback6, useMemo as useMemo5 } from "react";
1701
2127
 
1702
2128
  // src/contexts/AIEditContext.tsx
1703
- import { createContext as createContext3, useContext as useContext3, useCallback as useCallback4, useRef as useRef4, useMemo as useMemo2 } from "react";
1704
- import { jsx as jsx5 } from "react/jsx-runtime";
1705
- var AIEditContext = createContext3(null);
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);
1706
2132
  function useAIEditContext() {
1707
- const context = useContext3(AIEditContext);
2133
+ const context = useContext4(AIEditContext);
1708
2134
  if (!context) {
1709
2135
  throw new Error("useAIEditContext must be used within an AIEditProvider");
1710
2136
  }
1711
2137
  return context;
1712
2138
  }
1713
2139
  function useAIEditContextOptional() {
1714
- return useContext3(AIEditContext);
2140
+ return useContext4(AIEditContext);
1715
2141
  }
1716
2142
  function AIEditProvider({ children, staggerDelay = 100 }) {
1717
- const animationsRef = useRef4(/* @__PURE__ */ new Map());
1718
- const listenersRef = useRef4(/* @__PURE__ */ new Map());
1719
- const queueRef = useRef4([]);
1720
- const processingRef = useRef4(false);
1721
- const notifyListeners = useCallback4((fieldId) => {
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) => {
1722
2148
  const listeners = listenersRef.current.get(fieldId);
1723
2149
  if (listeners) {
1724
2150
  listeners.forEach((listener) => listener());
1725
2151
  }
1726
2152
  }, []);
1727
- const processQueue = useCallback4(() => {
2153
+ const processQueue = useCallback5(() => {
1728
2154
  if (processingRef.current || queueRef.current.length === 0) return;
1729
2155
  processingRef.current = true;
1730
2156
  const fieldId = queueRef.current.shift();
@@ -1739,7 +2165,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1739
2165
  processQueue();
1740
2166
  }, staggerDelay);
1741
2167
  }, [staggerDelay, notifyListeners]);
1742
- const queueAnimation = useCallback4(
2168
+ const queueAnimation = useCallback5(
1743
2169
  (fieldId, config) => {
1744
2170
  const existing = animationsRef.current.get(fieldId);
1745
2171
  if (existing?.status === "animating") {
@@ -1762,7 +2188,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1762
2188
  },
1763
2189
  [notifyListeners, processQueue]
1764
2190
  );
1765
- const cancelAnimation = useCallback4(
2191
+ const cancelAnimation = useCallback5(
1766
2192
  (fieldId) => {
1767
2193
  const state = animationsRef.current.get(fieldId);
1768
2194
  if (state) {
@@ -1776,14 +2202,14 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1776
2202
  },
1777
2203
  [notifyListeners]
1778
2204
  );
1779
- const isAnimating = useCallback4((fieldId) => {
2205
+ const isAnimating = useCallback5((fieldId) => {
1780
2206
  const state = animationsRef.current.get(fieldId);
1781
2207
  return state?.status === "animating" || state?.status === "pending";
1782
2208
  }, []);
1783
- const getAnimationState = useCallback4((fieldId) => {
2209
+ const getAnimationState = useCallback5((fieldId) => {
1784
2210
  return animationsRef.current.get(fieldId);
1785
2211
  }, []);
1786
- const subscribe = useCallback4((fieldId, listener) => {
2212
+ const subscribe = useCallback5((fieldId, listener) => {
1787
2213
  let listeners = listenersRef.current.get(fieldId);
1788
2214
  if (!listeners) {
1789
2215
  listeners = /* @__PURE__ */ new Set();
@@ -1797,7 +2223,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1797
2223
  }
1798
2224
  };
1799
2225
  }, []);
1800
- const completeAnimation = useCallback4(
2226
+ const completeAnimation = useCallback5(
1801
2227
  (fieldId) => {
1802
2228
  const state = animationsRef.current.get(fieldId);
1803
2229
  if (state) {
@@ -1812,7 +2238,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1812
2238
  },
1813
2239
  [notifyListeners]
1814
2240
  );
1815
- const value = useMemo2(
2241
+ const value = useMemo4(
1816
2242
  () => ({
1817
2243
  queueAnimation,
1818
2244
  cancelAnimation,
@@ -1823,7 +2249,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1823
2249
  }),
1824
2250
  [queueAnimation, cancelAnimation, isAnimating, getAnimationState, subscribe, completeAnimation]
1825
2251
  );
1826
- return /* @__PURE__ */ jsx5(AIEditContext.Provider, { value, children });
2252
+ return /* @__PURE__ */ jsx6(AIEditContext.Provider, { value, children });
1827
2253
  }
1828
2254
 
1829
2255
  // src/hooks/useAIEditAnimation.ts
@@ -1831,15 +2257,15 @@ function useAIEditAnimation(fieldId, value, options) {
1831
2257
  const { enabled = true, strategy, maxDuration = 2e3, onStart, onComplete } = options;
1832
2258
  const context = useAIEditContextOptional();
1833
2259
  const { getChangeSource, clearChangeSource } = useContentStore();
1834
- const previousValueRef = useRef5(value);
1835
- const isFirstRender = useRef5(true);
1836
- const [phase, setPhase] = useState4("idle");
1837
- const [progress, setProgress] = useState4(0);
1838
- const [displayValue, setDisplayValue] = useState4(value);
1839
- const metadataRef = useRef5(null);
1840
- const animationFrameRef = useRef5(null);
1841
- const startTimeRef = useRef5(0);
1842
- const cancel = useCallback5(() => {
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(() => {
1843
2269
  if (animationFrameRef.current !== null) {
1844
2270
  cancelAnimationFrame(animationFrameRef.current);
1845
2271
  animationFrameRef.current = null;
@@ -1850,7 +2276,7 @@ function useAIEditAnimation(fieldId, value, options) {
1850
2276
  metadataRef.current = null;
1851
2277
  context?.cancelAnimation(fieldId);
1852
2278
  }, [value, context, fieldId]);
1853
- const runAnimation = useCallback5(() => {
2279
+ const runAnimation = useCallback6(() => {
1854
2280
  if (!metadataRef.current) return;
1855
2281
  const metadata = metadataRef.current;
1856
2282
  const elapsed = performance.now() - startTimeRef.current;
@@ -1875,7 +2301,7 @@ function useAIEditAnimation(fieldId, value, options) {
1875
2301
  setDisplayValue(interpolatedValue);
1876
2302
  animationFrameRef.current = requestAnimationFrame(runAnimation);
1877
2303
  }, [strategy, maxDuration, context, fieldId, onComplete, clearChangeSource]);
1878
- useEffect4(() => {
2304
+ useEffect5(() => {
1879
2305
  if (isFirstRender.current) {
1880
2306
  isFirstRender.current = false;
1881
2307
  previousValueRef.current = value;
@@ -1902,6 +2328,9 @@ function useAIEditAnimation(fieldId, value, options) {
1902
2328
  if (!strategy.canAnimate(oldValue, newValue)) {
1903
2329
  setDisplayValue(newValue);
1904
2330
  previousValueRef.current = newValue;
2331
+ if (phase === "animating") {
2332
+ setPhase("idle");
2333
+ }
1905
2334
  return;
1906
2335
  }
1907
2336
  if (animationFrameRef.current !== null) {
@@ -1926,14 +2355,14 @@ function useAIEditAnimation(fieldId, value, options) {
1926
2355
  }
1927
2356
  };
1928
2357
  }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation, getChangeSource, clearChangeSource]);
1929
- useEffect4(() => {
2358
+ useEffect5(() => {
1930
2359
  return () => {
1931
2360
  if (animationFrameRef.current !== null) {
1932
2361
  cancelAnimationFrame(animationFrameRef.current);
1933
2362
  }
1934
2363
  };
1935
2364
  }, []);
1936
- const wrapperProps = useMemo3(
2365
+ const wrapperProps = useMemo5(
1937
2366
  () => ({
1938
2367
  className: phase === "animating" ? "ya-ai-editing" : phase === "complete" ? "ya-ai-complete" : "",
1939
2368
  "data-ai-editing": phase === "animating"
@@ -2155,7 +2584,7 @@ function useAnimatedText(fieldId, content, options = {}) {
2155
2584
  onStart,
2156
2585
  onComplete
2157
2586
  } = options;
2158
- const customStrategy = useMemo4(() => {
2587
+ const customStrategy = useMemo6(() => {
2159
2588
  if (charDelay === 50) {
2160
2589
  return textTypingStrategy;
2161
2590
  }
@@ -2194,7 +2623,7 @@ function useAnimatedText(fieldId, content, options = {}) {
2194
2623
  onStart,
2195
2624
  onComplete
2196
2625
  });
2197
- const cursorPosition = useMemo4(() => {
2626
+ const cursorPosition = useMemo6(() => {
2198
2627
  if (!isAnimating) return null;
2199
2628
  const diff = computeTextDiff(content, displayValue);
2200
2629
  const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
@@ -2225,7 +2654,7 @@ function useAnimatedText(fieldId, content, options = {}) {
2225
2654
  }
2226
2655
 
2227
2656
  // src/components/BubbleIcons.tsx
2228
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
2657
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
2229
2658
  function BoldIcon({ size = 16, className }) {
2230
2659
  return /* @__PURE__ */ jsxs2(
2231
2660
  "svg",
@@ -2240,8 +2669,8 @@ function BoldIcon({ size = 16, className }) {
2240
2669
  strokeLinejoin: "round",
2241
2670
  className,
2242
2671
  children: [
2243
- /* @__PURE__ */ jsx6("path", { d: "M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" }),
2244
- /* @__PURE__ */ jsx6("path", { d: "M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" })
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" })
2245
2674
  ]
2246
2675
  }
2247
2676
  );
@@ -2260,9 +2689,9 @@ function ItalicIcon({ size = 16, className }) {
2260
2689
  strokeLinejoin: "round",
2261
2690
  className,
2262
2691
  children: [
2263
- /* @__PURE__ */ jsx6("line", { x1: "19", y1: "4", x2: "10", y2: "4" }),
2264
- /* @__PURE__ */ jsx6("line", { x1: "14", y1: "20", x2: "5", y2: "20" }),
2265
- /* @__PURE__ */ jsx6("line", { x1: "15", y1: "4", x2: "9", y2: "20" })
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" })
2266
2695
  ]
2267
2696
  }
2268
2697
  );
@@ -2281,14 +2710,14 @@ function LinkIcon2({ size = 16, className }) {
2281
2710
  strokeLinejoin: "round",
2282
2711
  className,
2283
2712
  children: [
2284
- /* @__PURE__ */ jsx6("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
2285
- /* @__PURE__ */ jsx6("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
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" })
2286
2715
  ]
2287
2716
  }
2288
2717
  );
2289
2718
  }
2290
2719
  function ChevronDownIcon({ size = 12, className }) {
2291
- return /* @__PURE__ */ jsx6(
2720
+ return /* @__PURE__ */ jsx7(
2292
2721
  "svg",
2293
2722
  {
2294
2723
  width: size,
@@ -2300,15 +2729,15 @@ function ChevronDownIcon({ size = 12, className }) {
2300
2729
  strokeLinecap: "round",
2301
2730
  strokeLinejoin: "round",
2302
2731
  className,
2303
- children: /* @__PURE__ */ jsx6("polyline", { points: "6 9 12 15 18 9" })
2732
+ children: /* @__PURE__ */ jsx7("polyline", { points: "6 9 12 15 18 9" })
2304
2733
  }
2305
2734
  );
2306
2735
  }
2307
2736
 
2308
2737
  // src/components/BubbleDropdown.tsx
2309
- import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useState as useState5, useRef as useRef6, useCallback as useCallback6 } from "react";
2738
+ import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useState as useState6, useRef as useRef7, useCallback as useCallback7 } from "react";
2310
2739
  import { createPortal as createPortal3 } from "react-dom";
2311
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
2740
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
2312
2741
  function BubbleDropdown({
2313
2742
  label,
2314
2743
  open,
@@ -2317,14 +2746,14 @@ function BubbleDropdown({
2317
2746
  triggerClassName = "",
2318
2747
  panelClassName = ""
2319
2748
  }) {
2320
- const triggerRef = useRef6(null);
2321
- const panelRef = useRef6(null);
2322
- const [position, setPosition] = useState5(null);
2323
- const [isMounted, setIsMounted] = useState5(false);
2324
- useEffect5(() => {
2749
+ const triggerRef = useRef7(null);
2750
+ const panelRef = useRef7(null);
2751
+ const [position, setPosition] = useState6(null);
2752
+ const [isMounted, setIsMounted] = useState6(false);
2753
+ useEffect6(() => {
2325
2754
  setIsMounted(true);
2326
2755
  }, []);
2327
- const calculatePosition = useCallback6(() => {
2756
+ const calculatePosition = useCallback7(() => {
2328
2757
  if (!triggerRef.current) return null;
2329
2758
  const triggerRect = triggerRef.current.getBoundingClientRect();
2330
2759
  const gap = 4;
@@ -2340,7 +2769,7 @@ function BubbleDropdown({
2340
2769
  }
2341
2770
  return { top, left, adjusted: false };
2342
2771
  }, []);
2343
- useEffect5(() => {
2772
+ useEffect6(() => {
2344
2773
  if (open) {
2345
2774
  const pos = calculatePosition();
2346
2775
  setPosition(pos);
@@ -2369,7 +2798,7 @@ function BubbleDropdown({
2369
2798
  setPosition((prev) => prev ? { ...prev, adjusted: true } : null);
2370
2799
  }
2371
2800
  }, [open, position]);
2372
- useEffect5(() => {
2801
+ useEffect6(() => {
2373
2802
  if (!open) return;
2374
2803
  const handleClickOutside = (e) => {
2375
2804
  if (triggerRef.current?.contains(e.target) || panelRef.current?.contains(e.target)) {
@@ -2422,13 +2851,13 @@ function BubbleDropdown({
2422
2851
  onClick: handleTriggerClick,
2423
2852
  onMouseDown: handleTriggerMouseDown,
2424
2853
  children: [
2425
- /* @__PURE__ */ jsx7("span", { className: "ya-bubble-dropdown-label", children: label }),
2426
- /* @__PURE__ */ jsx7(ChevronDownIcon, { size: 10, className: `ya-bubble-dropdown-arrow ${open ? "is-open" : ""}` })
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" : ""}` })
2427
2856
  ]
2428
2857
  }
2429
2858
  ),
2430
2859
  isMounted && open && position && createPortal3(
2431
- /* @__PURE__ */ jsx7(
2860
+ /* @__PURE__ */ jsx8(
2432
2861
  "div",
2433
2862
  {
2434
2863
  ref: panelRef,
@@ -2444,8 +2873,8 @@ function BubbleDropdown({
2444
2873
  }
2445
2874
 
2446
2875
  // src/components/FontSizePicker.tsx
2447
- import { useState as useState6, useEffect as useEffect6, useCallback as useCallback7, useRef as useRef7 } from "react";
2448
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
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";
2449
2878
  var SIZE_PRESETS = [
2450
2879
  { name: "S", value: "0.875rem" },
2451
2880
  { name: "M", value: "1rem" },
@@ -2502,28 +2931,28 @@ function normalizeValue(input) {
2502
2931
  return `${num}${unit}`;
2503
2932
  }
2504
2933
  function FontSizePicker({ value, onChange, onClose }) {
2505
- const [inputValue, setInputValue] = useState6(value || "");
2506
- const inputRef = useRef7(null);
2507
- useEffect6(() => {
2934
+ const [inputValue, setInputValue] = useState7(value || "");
2935
+ const inputRef = useRef8(null);
2936
+ useEffect7(() => {
2508
2937
  inputRef.current?.focus();
2509
2938
  inputRef.current?.select();
2510
2939
  }, []);
2511
- useEffect6(() => {
2940
+ useEffect7(() => {
2512
2941
  setInputValue(value || "");
2513
2942
  }, [value]);
2514
- const handlePresetClick = useCallback7((e, presetValue) => {
2943
+ const handlePresetClick = useCallback8((e, presetValue) => {
2515
2944
  e.stopPropagation();
2516
2945
  onChange(presetValue);
2517
2946
  onClose();
2518
2947
  }, [onChange, onClose]);
2519
- const handlePresetMouseDown = useCallback7((e) => {
2948
+ const handlePresetMouseDown = useCallback8((e) => {
2520
2949
  e.preventDefault();
2521
2950
  e.stopPropagation();
2522
2951
  }, []);
2523
- const handleInputChange = useCallback7((e) => {
2952
+ const handleInputChange = useCallback8((e) => {
2524
2953
  setInputValue(e.target.value);
2525
2954
  }, []);
2526
- const handleInputKeyDown = useCallback7((e) => {
2955
+ const handleInputKeyDown = useCallback8((e) => {
2527
2956
  if (e.key === "ArrowUp" || e.key === "ArrowDown") {
2528
2957
  e.preventDefault();
2529
2958
  e.stopPropagation();
@@ -2565,7 +2994,7 @@ function FontSizePicker({ value, onChange, onClose }) {
2565
2994
  }, [inputValue, value, onChange, onClose]);
2566
2995
  const activePreset = getPresetName(value);
2567
2996
  return /* @__PURE__ */ jsxs4("div", { className: "ya-font-size-picker", children: [
2568
- /* @__PURE__ */ jsx8("div", { className: "ya-size-presets", children: SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs4(
2997
+ /* @__PURE__ */ jsx9("div", { className: "ya-size-presets", children: SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs4(
2569
2998
  "button",
2570
2999
  {
2571
3000
  type: "button",
@@ -2573,13 +3002,13 @@ function FontSizePicker({ value, onChange, onClose }) {
2573
3002
  onClick: (e) => handlePresetClick(e, preset.value),
2574
3003
  onMouseDown: handlePresetMouseDown,
2575
3004
  children: [
2576
- /* @__PURE__ */ jsx8("span", { className: "ya-size-preset-name", children: preset.name }),
2577
- /* @__PURE__ */ jsx8("span", { className: "ya-size-preset-value", children: preset.value })
3005
+ /* @__PURE__ */ jsx9("span", { className: "ya-size-preset-name", children: preset.name }),
3006
+ /* @__PURE__ */ jsx9("span", { className: "ya-size-preset-value", children: preset.value })
2578
3007
  ]
2579
3008
  },
2580
3009
  preset.name
2581
3010
  )) }),
2582
- /* @__PURE__ */ jsx8("div", { className: "ya-size-combobox", children: /* @__PURE__ */ jsx8(
3011
+ /* @__PURE__ */ jsx9("div", { className: "ya-size-combobox", children: /* @__PURE__ */ jsx9(
2583
3012
  "input",
2584
3013
  {
2585
3014
  ref: inputRef,
@@ -2599,8 +3028,8 @@ function FontSizePicker({ value, onChange, onClose }) {
2599
3028
  }
2600
3029
 
2601
3030
  // src/components/FontWeightPicker.tsx
2602
- import { useCallback as useCallback8 } from "react";
2603
- import { jsx as jsx9 } from "react/jsx-runtime";
3031
+ import { useCallback as useCallback9 } from "react";
3032
+ import { jsx as jsx10 } from "react/jsx-runtime";
2604
3033
  var WEIGHT_PRESETS = [
2605
3034
  { name: "Regular", value: "400" },
2606
3035
  { name: "Semi-bold", value: "600" },
@@ -2614,16 +3043,16 @@ function getFontWeightLabel(value) {
2614
3043
  return value;
2615
3044
  }
2616
3045
  function FontWeightPicker({ value, onChange, onClose }) {
2617
- const handleClick = useCallback8((e, weightValue) => {
3046
+ const handleClick = useCallback9((e, weightValue) => {
2618
3047
  e.stopPropagation();
2619
3048
  onChange(weightValue);
2620
3049
  onClose();
2621
3050
  }, [onChange, onClose]);
2622
- const handleMouseDown = useCallback8((e) => {
3051
+ const handleMouseDown = useCallback9((e) => {
2623
3052
  e.preventDefault();
2624
3053
  e.stopPropagation();
2625
3054
  }, []);
2626
- return /* @__PURE__ */ jsx9("div", { className: "ya-font-weight-picker", children: WEIGHT_PRESETS.map((preset) => /* @__PURE__ */ jsx9(
3055
+ return /* @__PURE__ */ jsx10("div", { className: "ya-font-weight-picker", children: WEIGHT_PRESETS.map((preset) => /* @__PURE__ */ jsx10(
2627
3056
  "button",
2628
3057
  {
2629
3058
  type: "button",
@@ -2986,7 +3415,7 @@ body.builder-selector-active .ya-text-editable:not(.ya-text-editing) *::-moz-sel
2986
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');
2987
3416
 
2988
3417
  // src/components/YaText.tsx
2989
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
3418
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
2990
3419
  var FontSize = Extension.create({
2991
3420
  name: "fontSize",
2992
3421
  addOptions() {
@@ -3066,13 +3495,15 @@ var FontWeight = Extension.create({
3066
3495
  }
3067
3496
  });
3068
3497
  function YaText({ fieldId, className, as: Component = "span", children }) {
3069
- const { getValue, setValue, mode, saveToWorker, activeFieldId, setActiveField } = useContentStore();
3070
- const storeContent = getValue(fieldId);
3498
+ const contentHandle = useContent(fieldId);
3499
+ const { mode } = contentHandle;
3500
+ const { activeFieldId, setActiveField } = useContentStore();
3501
+ const storeContent = contentHandle.get();
3071
3502
  const content = storeContent || (typeof children === "string" ? children : "");
3072
- const [isEditing, setIsEditing] = useState7(false);
3073
- const [showBubbleMenu, setShowBubbleMenu] = useState7(false);
3074
- const [fontSizeOpen, setFontSizeOpen] = useState7(false);
3075
- const [fontWeightOpen, setFontWeightOpen] = useState7(false);
3503
+ const [isEditing, setIsEditing] = useState8(false);
3504
+ const [showBubbleMenu, setShowBubbleMenu] = useState8(false);
3505
+ const [fontSizeOpen, setFontSizeOpen] = useState8(false);
3506
+ const [fontWeightOpen, setFontWeightOpen] = useState8(false);
3076
3507
  const {
3077
3508
  displayContent,
3078
3509
  isAnimating,
@@ -3080,16 +3511,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3080
3511
  } = useAnimatedText(fieldId, content, {
3081
3512
  enabled: mode === "inline-edit" && !isEditing
3082
3513
  });
3083
- const [originalContent, setOriginalContent] = useState7(content);
3084
- const containerRef = useRef8(null);
3085
- const originalContentRef = useRef8(content);
3086
- const originalHadLineBreaksRef = useRef8(false);
3087
- const [actionButtonsPos, setActionButtonsPos] = useState7(null);
3088
- const handleSaveRef = useRef8(() => {
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(() => {
3089
3520
  });
3090
- const handleCancelRef = useRef8(() => {
3521
+ const handleCancelRef = useRef9(() => {
3091
3522
  });
3092
- const handleCloseRef = useRef8(() => {
3523
+ const handleCloseRef = useRef9(() => {
3093
3524
  });
3094
3525
  const editor = useEditor({
3095
3526
  extensions: [
@@ -3145,19 +3576,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3145
3576
  },
3146
3577
  parseOptions: { preserveWhitespace: "full" }
3147
3578
  });
3148
- useEffect7(() => {
3579
+ useEffect8(() => {
3149
3580
  if (editor && !isEditing) {
3150
3581
  if (editor.getHTML() !== content) {
3151
3582
  editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
3152
3583
  }
3153
3584
  }
3154
3585
  }, [content, editor, isEditing]);
3155
- useEffect7(() => {
3586
+ useEffect8(() => {
3156
3587
  if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
3157
3588
  setIsEditing(false);
3158
3589
  }
3159
3590
  }, [activeFieldId, fieldId, isEditing]);
3160
- useEffect7(() => {
3591
+ useEffect8(() => {
3161
3592
  if (!isEditing || !containerRef.current || !editor) {
3162
3593
  setActionButtonsPos(null);
3163
3594
  return;
@@ -3182,31 +3613,31 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3182
3613
  window.removeEventListener("resize", updatePosition);
3183
3614
  };
3184
3615
  }, [isEditing, editor]);
3185
- const handleSave = useCallback9(() => {
3616
+ const handleSave = useCallback10(() => {
3186
3617
  if (!editor) return;
3187
3618
  let html = editor.getHTML();
3188
3619
  const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
3189
3620
  html = html.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
3190
3621
  if (html !== originalContentRef.current) {
3191
- setValue(fieldId, html, "user");
3192
- saveToWorker?.(fieldId, html);
3622
+ contentHandle.set(html, "user");
3623
+ contentHandle.save();
3193
3624
  originalContentRef.current = html;
3194
3625
  }
3195
3626
  setShowBubbleMenu(false);
3196
3627
  setIsEditing(false);
3197
- }, [editor, fieldId, setValue, saveToWorker]);
3198
- const handleCancel = useCallback9(() => {
3628
+ }, [editor, contentHandle]);
3629
+ const handleCancel = useCallback10(() => {
3199
3630
  if (editor) {
3200
3631
  editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
3201
3632
  }
3202
3633
  setShowBubbleMenu(false);
3203
3634
  setIsEditing(false);
3204
3635
  }, [editor, originalContent]);
3205
- useEffect7(() => {
3636
+ useEffect8(() => {
3206
3637
  handleSaveRef.current = handleSave;
3207
3638
  handleCancelRef.current = handleCancel;
3208
3639
  }, [handleSave, handleCancel]);
3209
- useEffect7(() => {
3640
+ useEffect8(() => {
3210
3641
  if (mode !== "inline-edit") return;
3211
3642
  const handleEditRequest = (event) => {
3212
3643
  const customEvent = event;
@@ -3229,7 +3660,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3229
3660
  window.addEventListener("yatext:edit-mode", handleEditRequest);
3230
3661
  return () => window.removeEventListener("yatext:edit-mode", handleEditRequest);
3231
3662
  }, [mode, fieldId, content, editor, setActiveField]);
3232
- const handleClose = useCallback9(() => {
3663
+ const handleClose = useCallback10(() => {
3233
3664
  if (!editor) {
3234
3665
  setShowBubbleMenu(false);
3235
3666
  setIsEditing(false);
@@ -3239,16 +3670,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3239
3670
  const separator = originalHadLineBreaksRef.current ? "<br><br>" : " ";
3240
3671
  currentHtml = currentHtml.replace(/<\/p><p>/g, separator).replace(/^<p>/, "").replace(/<\/p>$/, "");
3241
3672
  if (currentHtml !== originalContentRef.current) {
3242
- setValue(fieldId, currentHtml, "user");
3243
- saveToWorker?.(fieldId, currentHtml);
3673
+ contentHandle.set(currentHtml, "user");
3674
+ contentHandle.save();
3244
3675
  }
3245
3676
  setShowBubbleMenu(false);
3246
3677
  setIsEditing(false);
3247
- }, [editor, fieldId, setValue, saveToWorker]);
3248
- useEffect7(() => {
3678
+ }, [editor, contentHandle]);
3679
+ useEffect8(() => {
3249
3680
  handleCloseRef.current = handleClose;
3250
3681
  }, [handleClose]);
3251
- const handleClick = useCallback9((e) => {
3682
+ const handleClick = useCallback10((e) => {
3252
3683
  if (isEditing) {
3253
3684
  e.preventDefault();
3254
3685
  e.stopPropagation();
@@ -3279,7 +3710,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3279
3710
  }, 20);
3280
3711
  }
3281
3712
  }, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
3282
- const handleKeyDown = useCallback9(
3713
+ const handleKeyDown = useCallback10(
3283
3714
  (event) => {
3284
3715
  if (!isEditing) return;
3285
3716
  if (event.key === "Enter" && !event.shiftKey) {
@@ -3300,7 +3731,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3300
3731
  },
3301
3732
  [isEditing, handleSave, handleCancel]
3302
3733
  );
3303
- const handleLink = useCallback9(() => {
3734
+ const handleLink = useCallback10(() => {
3304
3735
  if (!editor) return;
3305
3736
  const previousUrl = editor.getAttributes("link").href;
3306
3737
  const url = window.prompt("Enter URL:", previousUrl || "https://");
@@ -3311,7 +3742,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3311
3742
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
3312
3743
  }
3313
3744
  }, [editor]);
3314
- const handleFontSizeChange = useCallback9(
3745
+ const handleFontSizeChange = useCallback10(
3315
3746
  (size) => {
3316
3747
  if (!editor) return;
3317
3748
  if (size === "") {
@@ -3322,7 +3753,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3322
3753
  },
3323
3754
  [editor]
3324
3755
  );
3325
- const handleFontWeightChange = useCallback9(
3756
+ const handleFontWeightChange = useCallback10(
3326
3757
  (weight) => {
3327
3758
  if (!editor) return;
3328
3759
  if (weight === "") {
@@ -3367,14 +3798,14 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3367
3798
  return "";
3368
3799
  };
3369
3800
  if (mode === "read-only") {
3370
- return /* @__PURE__ */ jsx10(
3801
+ return /* @__PURE__ */ jsx11(
3371
3802
  Component,
3372
3803
  {
3373
3804
  ref: containerRef,
3374
3805
  className,
3375
3806
  "data-ya-restricted": "true",
3376
3807
  "data-field-id": fieldId,
3377
- children: /* @__PURE__ */ jsx10(SafeHtml, { content, mode })
3808
+ children: /* @__PURE__ */ jsx11(SafeHtml, { content, mode })
3378
3809
  }
3379
3810
  );
3380
3811
  }
@@ -3387,7 +3818,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3387
3818
  wrapperClassName
3388
3819
  ].filter(Boolean).join(" ");
3389
3820
  const EditSafeComponent = isEditing && Component === "p" ? "div" : Component;
3390
- return /* @__PURE__ */ jsx10(
3821
+ return /* @__PURE__ */ jsx11(
3391
3822
  EditSafeComponent,
3392
3823
  {
3393
3824
  ref: containerRef,
@@ -3405,7 +3836,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3405
3836
  open: showBubbleMenu,
3406
3837
  className: "ya-bubble-menu",
3407
3838
  children: [
3408
- /* @__PURE__ */ jsx10(
3839
+ /* @__PURE__ */ jsx11(
3409
3840
  "button",
3410
3841
  {
3411
3842
  type: "button",
@@ -3413,10 +3844,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3413
3844
  onMouseDown: (e) => e.preventDefault(),
3414
3845
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
3415
3846
  title: "Bold",
3416
- children: /* @__PURE__ */ jsx10(BoldIcon, { size: 16 })
3847
+ children: /* @__PURE__ */ jsx11(BoldIcon, { size: 16 })
3417
3848
  }
3418
3849
  ),
3419
- /* @__PURE__ */ jsx10(
3850
+ /* @__PURE__ */ jsx11(
3420
3851
  "button",
3421
3852
  {
3422
3853
  type: "button",
@@ -3424,10 +3855,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3424
3855
  onMouseDown: (e) => e.preventDefault(),
3425
3856
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
3426
3857
  title: "Italic",
3427
- children: /* @__PURE__ */ jsx10(ItalicIcon, { size: 16 })
3858
+ children: /* @__PURE__ */ jsx11(ItalicIcon, { size: 16 })
3428
3859
  }
3429
3860
  ),
3430
- /* @__PURE__ */ jsx10(
3861
+ /* @__PURE__ */ jsx11(
3431
3862
  "button",
3432
3863
  {
3433
3864
  type: "button",
@@ -3435,17 +3866,17 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3435
3866
  onMouseDown: (e) => e.preventDefault(),
3436
3867
  className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
3437
3868
  title: "Link",
3438
- children: /* @__PURE__ */ jsx10(LinkIcon2, { size: 16 })
3869
+ children: /* @__PURE__ */ jsx11(LinkIcon2, { size: 16 })
3439
3870
  }
3440
3871
  ),
3441
- /* @__PURE__ */ jsx10("span", { className: "ya-bubble-divider" }),
3442
- /* @__PURE__ */ jsx10(
3872
+ /* @__PURE__ */ jsx11("span", { className: "ya-bubble-divider" }),
3873
+ /* @__PURE__ */ jsx11(
3443
3874
  BubbleDropdown,
3444
3875
  {
3445
3876
  label: getFontSizeLabel(getCurrentFontSize()),
3446
3877
  open: fontSizeOpen,
3447
3878
  onOpenChange: setFontSizeOpen,
3448
- children: /* @__PURE__ */ jsx10(
3879
+ children: /* @__PURE__ */ jsx11(
3449
3880
  FontSizePicker,
3450
3881
  {
3451
3882
  value: getCurrentFontSize(),
@@ -3455,13 +3886,13 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3455
3886
  )
3456
3887
  }
3457
3888
  ),
3458
- /* @__PURE__ */ jsx10(
3889
+ /* @__PURE__ */ jsx11(
3459
3890
  BubbleDropdown,
3460
3891
  {
3461
3892
  label: getFontWeightLabel(getCurrentFontWeight()),
3462
3893
  open: fontWeightOpen,
3463
3894
  onOpenChange: setFontWeightOpen,
3464
- children: /* @__PURE__ */ jsx10(
3895
+ children: /* @__PURE__ */ jsx11(
3465
3896
  FontWeightPicker,
3466
3897
  {
3467
3898
  value: getCurrentFontWeight(),
@@ -3475,7 +3906,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3475
3906
  }
3476
3907
  ),
3477
3908
  isEditing ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3478
- /* @__PURE__ */ jsx10(EditorContent, { editor }),
3909
+ /* @__PURE__ */ jsx11(EditorContent, { editor }),
3479
3910
  actionButtonsPos && createPortal4(
3480
3911
  /* @__PURE__ */ jsxs5(
3481
3912
  "div",
@@ -3489,7 +3920,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3489
3920
  // Right edge aligns with text end
3490
3921
  },
3491
3922
  children: [
3492
- /* @__PURE__ */ jsx10(
3923
+ /* @__PURE__ */ jsx11(
3493
3924
  "button",
3494
3925
  {
3495
3926
  type: "button",
@@ -3498,7 +3929,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3498
3929
  children: "Cancel"
3499
3930
  }
3500
3931
  ),
3501
- /* @__PURE__ */ jsx10(
3932
+ /* @__PURE__ */ jsx11(
3502
3933
  "button",
3503
3934
  {
3504
3935
  type: "button",
@@ -3513,19 +3944,19 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3513
3944
  document.body
3514
3945
  )
3515
3946
  ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3516
- /* @__PURE__ */ jsx10(SafeHtml, { content: displayContent, mode }),
3517
- isAnimating && /* @__PURE__ */ jsx10("span", { className: "ya-typing-cursor" })
3947
+ /* @__PURE__ */ jsx11(SafeHtml, { content: displayContent, mode }),
3948
+ isAnimating && /* @__PURE__ */ jsx11("span", { className: "ya-typing-cursor" })
3518
3949
  ] })
3519
3950
  ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3520
- /* @__PURE__ */ jsx10(SafeHtml, { content: displayContent, mode }),
3521
- isAnimating && /* @__PURE__ */ jsx10("span", { className: "ya-typing-cursor" })
3951
+ /* @__PURE__ */ jsx11(SafeHtml, { content: displayContent, mode }),
3952
+ isAnimating && /* @__PURE__ */ jsx11("span", { className: "ya-typing-cursor" })
3522
3953
  ] })
3523
3954
  }
3524
3955
  );
3525
3956
  }
3526
3957
 
3527
3958
  // src/components/YaImage.tsx
3528
- import { useCallback as useCallback12, useEffect as useEffect10, useRef as useRef11, useState as useState10 } from "react";
3959
+ import { useCallback as useCallback13, useEffect as useEffect11, useRef as useRef12, useState as useState11 } from "react";
3529
3960
 
3530
3961
  // src/lib/asset-resolver.ts
3531
3962
  var assetResolver = (path) => path;
@@ -3541,25 +3972,25 @@ function resolveAssetUrl(path) {
3541
3972
  }
3542
3973
 
3543
3974
  // src/components/YaTooltip.tsx
3544
- import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback10 } from "react";
3975
+ import { useEffect as useEffect9, useRef as useRef10, useState as useState9, useCallback as useCallback11 } from "react";
3545
3976
  import { createPortal as createPortal5 } from "react-dom";
3546
3977
 
3547
3978
  // src/components/ya-tooltip.css
3548
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');
3549
3980
 
3550
3981
  // src/components/YaTooltip.tsx
3551
- import { jsx as jsx11 } from "react/jsx-runtime";
3982
+ import { jsx as jsx12 } from "react/jsx-runtime";
3552
3983
  function YaTooltip({
3553
3984
  anchorRef,
3554
3985
  children,
3555
3986
  show,
3556
3987
  preferredPosition = "bottom"
3557
3988
  }) {
3558
- const [position, setPosition] = useState8(preferredPosition);
3559
- const [coords, setCoords] = useState8({ top: 0, left: 0 });
3560
- const [isPositioned, setIsPositioned] = useState8(false);
3561
- const tooltipRef = useRef9(null);
3562
- const calculatePosition = useCallback10(() => {
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(() => {
3563
3994
  if (!anchorRef.current) return;
3564
3995
  const anchor = anchorRef.current.getBoundingClientRect();
3565
3996
  const tooltip = tooltipRef.current?.getBoundingClientRect();
@@ -3634,7 +4065,7 @@ function YaTooltip({
3634
4065
  setCoords({ top, left });
3635
4066
  setIsPositioned(true);
3636
4067
  }, [anchorRef, preferredPosition]);
3637
- useEffect8(() => {
4068
+ useEffect9(() => {
3638
4069
  if (!show) {
3639
4070
  setIsPositioned(false);
3640
4071
  return;
@@ -3647,14 +4078,14 @@ function YaTooltip({
3647
4078
  window.removeEventListener("resize", calculatePosition);
3648
4079
  };
3649
4080
  }, [show, calculatePosition]);
3650
- useEffect8(() => {
4081
+ useEffect9(() => {
3651
4082
  if (show && tooltipRef.current) {
3652
4083
  calculatePosition();
3653
4084
  }
3654
4085
  }, [show, children, calculatePosition]);
3655
4086
  if (!show) return null;
3656
4087
  return createPortal5(
3657
- /* @__PURE__ */ jsx11(
4088
+ /* @__PURE__ */ jsx12(
3658
4089
  "div",
3659
4090
  {
3660
4091
  ref: tooltipRef,
@@ -3673,7 +4104,7 @@ function YaTooltip({
3673
4104
  }
3674
4105
 
3675
4106
  // src/hooks/useImageShaderTransition.ts
3676
- import { useCallback as useCallback11, useEffect as useEffect9, useRef as useRef10, useState as useState9 } from "react";
4107
+ import { useCallback as useCallback12, useEffect as useEffect10, useRef as useRef11, useState as useState10 } from "react";
3677
4108
 
3678
4109
  // src/lib/image-shader-transition.ts
3679
4110
  var VERTEX_SHADER = `
@@ -3933,14 +4364,14 @@ function preloadImage(src) {
3933
4364
  var TRANSITION_DURATION = 500;
3934
4365
  function useImageShaderTransition(options = {}) {
3935
4366
  const { duration = TRANSITION_DURATION, onComplete } = options;
3936
- const canvasRef = useRef10(null);
3937
- const rendererRef = useRef10(null);
3938
- const rafRef = useRef10(null);
3939
- const startTimeRef = useRef10(0);
3940
- const newSrcRef = useRef10("");
3941
- const [isTransitioning, setIsTransitioning] = useState9(false);
3942
- const [webglAvailable] = useState9(() => isWebGLAvailable());
3943
- useEffect9(() => {
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(() => {
3944
4375
  return () => {
3945
4376
  if (rafRef.current) {
3946
4377
  cancelAnimationFrame(rafRef.current);
@@ -3948,7 +4379,7 @@ function useImageShaderTransition(options = {}) {
3948
4379
  rendererRef.current?.destroy();
3949
4380
  };
3950
4381
  }, []);
3951
- const animate = useCallback11(() => {
4382
+ const animate = useCallback12(() => {
3952
4383
  const renderer = rendererRef.current;
3953
4384
  if (!renderer) return;
3954
4385
  const elapsed = performance.now() - startTimeRef.current;
@@ -3963,7 +4394,7 @@ function useImageShaderTransition(options = {}) {
3963
4394
  });
3964
4395
  }
3965
4396
  }, [duration, onComplete]);
3966
- const startTransition = useCallback11(
4397
+ const startTransition = useCallback12(
3967
4398
  (oldSrc, newSrc) => {
3968
4399
  if (!webglAvailable) {
3969
4400
  return;
@@ -3995,7 +4426,7 @@ function useImageShaderTransition(options = {}) {
3995
4426
  },
3996
4427
  [webglAvailable, animate]
3997
4428
  );
3998
- const cancelTransition = useCallback11(() => {
4429
+ const cancelTransition = useCallback12(() => {
3999
4430
  if (rafRef.current) {
4000
4431
  cancelAnimationFrame(rafRef.current);
4001
4432
  rafRef.current = null;
@@ -4015,7 +4446,7 @@ function useImageShaderTransition(options = {}) {
4015
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');
4016
4447
 
4017
4448
  // src/components/YaImage.tsx
4018
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
4449
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
4019
4450
  function parseImageValue(value) {
4020
4451
  if (!value) {
4021
4452
  return { src: "" };
@@ -4059,17 +4490,18 @@ function YaImage({
4059
4490
  fallbackSrc,
4060
4491
  fallbackAlt
4061
4492
  }) {
4062
- const { getValue, setValue, mode, getChangeSource, clearChangeSource } = useContentStore();
4063
- const containerRef = useRef11(null);
4064
- const imgRef = useRef11(null);
4065
- const [isSelected, setIsSelected] = useState10(false);
4066
- const [isHovered, setIsHovered] = useState10(false);
4067
- const [isSmallImage, setIsSmallImage] = useState10(false);
4068
- const [isDropMode, setIsDropMode] = useState10(false);
4069
- const [isDropHover, setIsDropHover] = useState10(false);
4070
- const [previewOverride, setPreviewOverride] = useState10(null);
4071
- const prevSrcRef = useRef11(null);
4072
- const rawValue = getValue(fieldId);
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();
4073
4505
  const imageData = parseImageValue(rawValue);
4074
4506
  const displayData = previewOverride || imageData;
4075
4507
  const src = displayData.src || fallbackSrc || PLACEHOLDER_SVG;
@@ -4085,36 +4517,34 @@ function YaImage({
4085
4517
  } = useImageShaderTransition({
4086
4518
  duration: 500,
4087
4519
  onComplete: () => {
4088
- clearChangeSource(fieldId);
4520
+ content.clearChangeSource();
4089
4521
  }
4090
4522
  });
4091
- useEffect10(() => {
4092
- const changeSource = getChangeSource(fieldId);
4523
+ useEffect11(() => {
4524
+ const changeSource = content.changeSource;
4093
4525
  const resolvedSrc = resolveAssetUrl(src);
4094
4526
  const prevResolvedSrc = prevSrcRef.current;
4095
4527
  if (changeSource === "ai") {
4096
4528
  if (prevResolvedSrc !== null && prevResolvedSrc !== resolvedSrc && webglAvailable) {
4097
4529
  startTransition(prevResolvedSrc, resolvedSrc);
4098
4530
  } else {
4099
- clearChangeSource(fieldId);
4531
+ content.clearChangeSource();
4100
4532
  }
4101
4533
  }
4102
4534
  prevSrcRef.current = resolvedSrc;
4103
4535
  }, [
4104
4536
  rawValue,
4105
4537
  src,
4106
- fieldId,
4107
- getChangeSource,
4108
- clearChangeSource,
4538
+ content,
4109
4539
  startTransition,
4110
4540
  webglAvailable
4111
4541
  ]);
4112
- useEffect10(() => {
4542
+ useEffect11(() => {
4113
4543
  return () => {
4114
4544
  cancelTransition();
4115
4545
  };
4116
4546
  }, [cancelTransition]);
4117
- const handleClick = useCallback12(() => {
4547
+ const handleClick = useCallback13(() => {
4118
4548
  if (mode !== "inline-edit") return;
4119
4549
  if (document.body.classList.contains("builder-selector-active")) return;
4120
4550
  setIsSelected(true);
@@ -4142,12 +4572,14 @@ function YaImage({
4142
4572
  "*"
4143
4573
  );
4144
4574
  }, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
4145
- useEffect10(() => {
4575
+ useEffect11(() => {
4146
4576
  if (mode !== "inline-edit") return;
4147
4577
  const handleMessage2 = (event) => {
4148
4578
  if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
4149
4579
  const value = event.data.value;
4150
- setValue(fieldId, serializeImageValue(value), "user");
4580
+ const serializedValue = serializeImageValue(value);
4581
+ content.set(serializedValue, "user");
4582
+ content.save();
4151
4583
  setPreviewOverride(null);
4152
4584
  setIsSelected(false);
4153
4585
  }
@@ -4162,8 +4594,8 @@ function YaImage({
4162
4594
  };
4163
4595
  window.addEventListener("message", handleMessage2);
4164
4596
  return () => window.removeEventListener("message", handleMessage2);
4165
- }, [mode, fieldId, setValue]);
4166
- useEffect10(() => {
4597
+ }, [mode, fieldId, content]);
4598
+ useEffect11(() => {
4167
4599
  if (mode !== "inline-edit") return;
4168
4600
  const handleDropModeMessage = (event) => {
4169
4601
  if (event.data?.type === "DROP_MODE_START") {
@@ -4177,7 +4609,7 @@ function YaImage({
4177
4609
  window.addEventListener("message", handleDropModeMessage);
4178
4610
  return () => window.removeEventListener("message", handleDropModeMessage);
4179
4611
  }, [mode]);
4180
- const handleDragEnter = useCallback12(
4612
+ const handleDragEnter = useCallback13(
4181
4613
  (e) => {
4182
4614
  if (!isDropMode) return;
4183
4615
  e.preventDefault();
@@ -4201,7 +4633,7 @@ function YaImage({
4201
4633
  },
4202
4634
  [isDropMode, fieldId]
4203
4635
  );
4204
- const handleDragOver = useCallback12(
4636
+ const handleDragOver = useCallback13(
4205
4637
  (e) => {
4206
4638
  if (!isDropMode) return;
4207
4639
  e.preventDefault();
@@ -4209,7 +4641,7 @@ function YaImage({
4209
4641
  },
4210
4642
  [isDropMode]
4211
4643
  );
4212
- const handleDragLeave = useCallback12(
4644
+ const handleDragLeave = useCallback13(
4213
4645
  (e) => {
4214
4646
  if (!isDropMode) return;
4215
4647
  e.preventDefault();
@@ -4223,7 +4655,7 @@ function YaImage({
4223
4655
  },
4224
4656
  [isDropMode]
4225
4657
  );
4226
- const handleDrop = useCallback12(
4658
+ const handleDrop = useCallback13(
4227
4659
  (e) => {
4228
4660
  if (!isDropMode) return;
4229
4661
  e.preventDefault();
@@ -4241,7 +4673,7 @@ function YaImage({
4241
4673
  },
4242
4674
  [isDropMode, fieldId]
4243
4675
  );
4244
- useEffect10(() => {
4676
+ useEffect11(() => {
4245
4677
  if (mode !== "inline-edit") return;
4246
4678
  const checkSize = () => {
4247
4679
  if (imgRef.current) {
@@ -4263,7 +4695,7 @@ function YaImage({
4263
4695
  window.removeEventListener("resize", checkSize);
4264
4696
  };
4265
4697
  }, [mode]);
4266
- useEffect10(() => {
4698
+ useEffect11(() => {
4267
4699
  if (!isSelected || mode !== "inline-edit") return;
4268
4700
  let lastRectKey = "";
4269
4701
  let lastTime = 0;
@@ -4305,7 +4737,7 @@ function YaImage({
4305
4737
  "data-ya-restricted": "true",
4306
4738
  "data-field-id": fieldId,
4307
4739
  children: [
4308
- /* @__PURE__ */ jsx12(
4740
+ /* @__PURE__ */ jsx13(
4309
4741
  "img",
4310
4742
  {
4311
4743
  src: resolveAssetUrl(src),
@@ -4321,7 +4753,7 @@ function YaImage({
4321
4753
  loading
4322
4754
  }
4323
4755
  ),
4324
- /* @__PURE__ */ jsx12(
4756
+ /* @__PURE__ */ jsx13(
4325
4757
  "canvas",
4326
4758
  {
4327
4759
  ref: canvasRef,
@@ -4355,9 +4787,9 @@ function YaImage({
4355
4787
  strokeLinecap: "round",
4356
4788
  strokeLinejoin: "round",
4357
4789
  children: [
4358
- /* @__PURE__ */ jsx12("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
4359
- /* @__PURE__ */ jsx12("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
4360
- /* @__PURE__ */ jsx12("polyline", { points: "21 15 16 10 5 21" })
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" })
4361
4793
  ]
4362
4794
  }
4363
4795
  );
@@ -4393,7 +4825,7 @@ function YaImage({
4393
4825
  }
4394
4826
  },
4395
4827
  children: [
4396
- /* @__PURE__ */ jsx12(
4828
+ /* @__PURE__ */ jsx13(
4397
4829
  "img",
4398
4830
  {
4399
4831
  ref: imgRef,
@@ -4410,7 +4842,7 @@ function YaImage({
4410
4842
  loading
4411
4843
  }
4412
4844
  ),
4413
- /* @__PURE__ */ jsx12(
4845
+ /* @__PURE__ */ jsx13(
4414
4846
  "canvas",
4415
4847
  {
4416
4848
  ref: canvasRef,
@@ -4430,12 +4862,12 @@ function YaImage({
4430
4862
  ),
4431
4863
  isSmallImage ? /* @__PURE__ */ jsxs6(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
4432
4864
  editIcon,
4433
- /* @__PURE__ */ jsx12("span", { children: "Click to edit" })
4865
+ /* @__PURE__ */ jsx13("span", { children: "Click to edit" })
4434
4866
  ] }) : (
4435
4867
  /* For large images: show overlay inside the image */
4436
4868
  /* @__PURE__ */ jsxs6("div", { className: "ya-image-overlay", children: [
4437
- /* @__PURE__ */ jsx12("div", { className: "ya-image-edit-icon", children: editIcon }),
4438
- /* @__PURE__ */ jsx12("span", { className: "ya-image-edit-label", children: "Click to edit" })
4869
+ /* @__PURE__ */ jsx13("div", { className: "ya-image-edit-icon", children: editIcon }),
4870
+ /* @__PURE__ */ jsx13("span", { className: "ya-image-edit-label", children: "Click to edit" })
4439
4871
  ] })
4440
4872
  )
4441
4873
  ]
@@ -4444,13 +4876,13 @@ function YaImage({
4444
4876
  }
4445
4877
 
4446
4878
  // src/components/YaVideo.tsx
4447
- import { useCallback as useCallback13, useEffect as useEffect11, useRef as useRef12, useState as useState11 } from "react";
4879
+ import { useCallback as useCallback14, useEffect as useEffect12, useRef as useRef13, useState as useState12 } from "react";
4448
4880
 
4449
4881
  // src/components/ya-video.css
4450
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');
4451
4883
 
4452
4884
  // src/components/YaVideo.tsx
4453
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
4885
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
4454
4886
  function parseVideoValue(value) {
4455
4887
  if (!value) {
4456
4888
  return { type: "upload", src: "" };
@@ -4522,14 +4954,15 @@ function YaVideo({
4522
4954
  fallbackSrc,
4523
4955
  fallbackPoster
4524
4956
  }) {
4525
- const { getValue, mode } = useContentStore();
4526
- const containerRef = useRef12(null);
4527
- const videoRef = useRef12(null);
4528
- const [isSelected, setIsSelected] = useState11(false);
4529
- const [isHovered, setIsHovered] = useState11(false);
4530
- const [isSmallVideo, setIsSmallVideo] = useState11(false);
4531
- const [isInView, setIsInView] = useState11(loading === "eager");
4532
- const rawValue = getValue(fieldId);
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();
4533
4966
  const parsedValue = parseVideoValue(rawValue);
4534
4967
  const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
4535
4968
  const src = videoData.src || fallbackSrc || "";
@@ -4542,8 +4975,8 @@ function YaVideo({
4542
4975
  const controls = videoData.controls ?? true;
4543
4976
  const playsinline = videoData.playsinline ?? true;
4544
4977
  const preload = videoData.preload ?? "metadata";
4545
- const [prefersReducedMotion, setPrefersReducedMotion] = useState11(false);
4546
- useEffect11(() => {
4978
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState12(false);
4979
+ useEffect12(() => {
4547
4980
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
4548
4981
  setPrefersReducedMotion(mediaQuery.matches);
4549
4982
  const handleChange = (e) => {
@@ -4553,7 +4986,7 @@ function YaVideo({
4553
4986
  return () => mediaQuery.removeEventListener("change", handleChange);
4554
4987
  }, []);
4555
4988
  const effectiveAutoplay = autoplay && !prefersReducedMotion;
4556
- useEffect11(() => {
4989
+ useEffect12(() => {
4557
4990
  if (loading === "eager" || isInView) return;
4558
4991
  const observer = new IntersectionObserver(
4559
4992
  (entries) => {
@@ -4570,7 +5003,7 @@ function YaVideo({
4570
5003
  }
4571
5004
  return () => observer.disconnect();
4572
5005
  }, [loading, isInView]);
4573
- const handleKeyDown = useCallback13(
5006
+ const handleKeyDown = useCallback14(
4574
5007
  (e) => {
4575
5008
  if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
4576
5009
  e.preventDefault();
@@ -4586,7 +5019,7 @@ function YaVideo({
4586
5019
  },
4587
5020
  [videoData.type, controls]
4588
5021
  );
4589
- const handleClick = useCallback13(() => {
5022
+ const handleClick = useCallback14(() => {
4590
5023
  if (mode !== "inline-edit") return;
4591
5024
  if (document.body.classList.contains("builder-selector-active")) return;
4592
5025
  setIsSelected(true);
@@ -4606,7 +5039,7 @@ function YaVideo({
4606
5039
  "*"
4607
5040
  );
4608
5041
  }, [mode, fieldId, videoData]);
4609
- useEffect11(() => {
5042
+ useEffect12(() => {
4610
5043
  if (mode !== "inline-edit") return;
4611
5044
  const handleMessage2 = (event) => {
4612
5045
  if (event.data?.type === "YA_VIDEO_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4619,7 +5052,7 @@ function YaVideo({
4619
5052
  window.addEventListener("message", handleMessage2);
4620
5053
  return () => window.removeEventListener("message", handleMessage2);
4621
5054
  }, [mode, fieldId]);
4622
- useEffect11(() => {
5055
+ useEffect12(() => {
4623
5056
  if (mode !== "inline-edit") return;
4624
5057
  const checkSize = () => {
4625
5058
  if (containerRef.current) {
@@ -4631,7 +5064,7 @@ function YaVideo({
4631
5064
  window.addEventListener("resize", checkSize);
4632
5065
  return () => window.removeEventListener("resize", checkSize);
4633
5066
  }, [mode]);
4634
- useEffect11(() => {
5067
+ useEffect12(() => {
4635
5068
  if (!isSelected || mode !== "inline-edit") return;
4636
5069
  let lastRectKey = "";
4637
5070
  let lastTime = 0;
@@ -4668,23 +5101,23 @@ function YaVideo({
4668
5101
  const renderVideo = (isReadOnly) => {
4669
5102
  if (!src && !isReadOnly) {
4670
5103
  return /* @__PURE__ */ jsxs7("div", { className: "ya-video-placeholder", children: [
4671
- /* @__PURE__ */ jsx13("img", { src: PLACEHOLDER_SVG2, alt: "" }),
4672
- /* @__PURE__ */ jsx13("span", { children: "No video selected" })
5104
+ /* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG2, alt: "" }),
5105
+ /* @__PURE__ */ jsx14("span", { children: "No video selected" })
4673
5106
  ] });
4674
5107
  }
4675
5108
  if (!isInView && loading === "lazy" && !isReadOnly) {
4676
- return /* @__PURE__ */ jsx13(
5109
+ return /* @__PURE__ */ jsx14(
4677
5110
  "div",
4678
5111
  {
4679
5112
  className: "ya-video-placeholder",
4680
5113
  style: { aspectRatio },
4681
- children: /* @__PURE__ */ jsx13("img", { src: PLACEHOLDER_SVG2, alt: "" })
5114
+ children: /* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG2, alt: "" })
4682
5115
  }
4683
5116
  );
4684
5117
  }
4685
5118
  if (videoData.type === "youtube" && src) {
4686
5119
  const embedUrl = buildYouTubeEmbedUrl(src, videoData);
4687
- return /* @__PURE__ */ jsx13(
5120
+ return /* @__PURE__ */ jsx14(
4688
5121
  "iframe",
4689
5122
  {
4690
5123
  src: embedUrl,
@@ -4704,7 +5137,7 @@ function YaVideo({
4704
5137
  }
4705
5138
  if (videoData.type === "vimeo" && src) {
4706
5139
  const embedUrl = buildVimeoEmbedUrl(src, videoData);
4707
- return /* @__PURE__ */ jsx13(
5140
+ return /* @__PURE__ */ jsx14(
4708
5141
  "iframe",
4709
5142
  {
4710
5143
  src: embedUrl,
@@ -4724,7 +5157,7 @@ function YaVideo({
4724
5157
  }
4725
5158
  const resolvedSrc = resolveAssetUrl(src);
4726
5159
  const resolvedPoster = poster ? resolveAssetUrl(poster) : void 0;
4727
- return /* @__PURE__ */ jsx13(
5160
+ return /* @__PURE__ */ jsx14(
4728
5161
  "video",
4729
5162
  {
4730
5163
  ref: videoRef,
@@ -4759,7 +5192,7 @@ function YaVideo({
4759
5192
  );
4760
5193
  };
4761
5194
  if (mode === "read-only") {
4762
- return /* @__PURE__ */ jsx13(
5195
+ return /* @__PURE__ */ jsx14(
4763
5196
  "div",
4764
5197
  {
4765
5198
  ref: containerRef,
@@ -4787,8 +5220,8 @@ function YaVideo({
4787
5220
  strokeLinecap: "round",
4788
5221
  strokeLinejoin: "round",
4789
5222
  children: [
4790
- /* @__PURE__ */ jsx13("rect", { x: "2", y: "4", width: "15", height: "13", rx: "2", ry: "2" }),
4791
- /* @__PURE__ */ jsx13("polygon", { points: "22 7 15 12 22 17 22 7", fill: "currentColor" })
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" })
4792
5225
  ]
4793
5226
  }
4794
5227
  );
@@ -4817,12 +5250,12 @@ function YaVideo({
4817
5250
  renderVideo(false),
4818
5251
  isSmallVideo ? /* @__PURE__ */ jsxs7(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
4819
5252
  videoIcon,
4820
- /* @__PURE__ */ jsx13("span", { children: "Click to edit" })
5253
+ /* @__PURE__ */ jsx14("span", { children: "Click to edit" })
4821
5254
  ] }) : (
4822
5255
  /* For large videos: show overlay inside the container */
4823
5256
  /* @__PURE__ */ jsxs7("div", { className: "ya-video-overlay", children: [
4824
- /* @__PURE__ */ jsx13("div", { className: "ya-video-edit-icon", children: videoIcon }),
4825
- /* @__PURE__ */ jsx13("span", { className: "ya-video-edit-label", children: "Click to edit" })
5257
+ /* @__PURE__ */ jsx14("div", { className: "ya-video-edit-icon", children: videoIcon }),
5258
+ /* @__PURE__ */ jsx14("span", { className: "ya-video-edit-label", children: "Click to edit" })
4826
5259
  ] })
4827
5260
  )
4828
5261
  ]
@@ -4831,13 +5264,13 @@ function YaVideo({
4831
5264
  }
4832
5265
 
4833
5266
  // src/components/YaEmbed.tsx
4834
- import { useCallback as useCallback14, useEffect as useEffect12, useRef as useRef13, useState as useState12 } from "react";
5267
+ import { useCallback as useCallback15, useEffect as useEffect13, useRef as useRef14, useState as useState13 } from "react";
4835
5268
 
4836
5269
  // src/components/ya-embed.css
4837
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');
4838
5271
 
4839
5272
  // src/components/YaEmbed.tsx
4840
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5273
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
4841
5274
  function parseEmbedUrl(url) {
4842
5275
  if (!url) return null;
4843
5276
  const trimmedUrl = url.trim();
@@ -4950,20 +5383,21 @@ function YaEmbed({
4950
5383
  loading = "lazy",
4951
5384
  defaultValue
4952
5385
  }) {
4953
- const { getValue, mode } = useContentStore();
4954
- const containerRef = useRef13(null);
4955
- const [isSelected, setIsSelected] = useState12(false);
4956
- const [isHovered, setIsHovered] = useState12(false);
4957
- const [isSmallEmbed, setIsSmallEmbed] = useState12(false);
4958
- const [isInView, setIsInView] = useState12(loading === "eager");
4959
- const rawValue = getValue(fieldId);
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();
4960
5394
  const parsedValue = parseEmbedValue(rawValue);
4961
5395
  const embedData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
4962
5396
  const src = embedData.src || "";
4963
5397
  const embedType = embedData.type || "custom";
4964
5398
  const height = embedData.height;
4965
5399
  const aspectRatio = embedData.aspectRatio || propAspectRatio || "16/9";
4966
- useEffect12(() => {
5400
+ useEffect13(() => {
4967
5401
  if (loading === "eager" || isInView) return;
4968
5402
  const observer = new IntersectionObserver(
4969
5403
  (entries) => {
@@ -4980,7 +5414,7 @@ function YaEmbed({
4980
5414
  }
4981
5415
  return () => observer.disconnect();
4982
5416
  }, [loading, isInView]);
4983
- const handleClick = useCallback14(() => {
5417
+ const handleClick = useCallback15(() => {
4984
5418
  if (mode !== "inline-edit") return;
4985
5419
  if (document.body.classList.contains("builder-selector-active")) return;
4986
5420
  setIsSelected(true);
@@ -5000,7 +5434,7 @@ function YaEmbed({
5000
5434
  "*"
5001
5435
  );
5002
5436
  }, [mode, fieldId, embedData]);
5003
- useEffect12(() => {
5437
+ useEffect13(() => {
5004
5438
  if (mode !== "inline-edit") return;
5005
5439
  const handleMessage2 = (event) => {
5006
5440
  if (event.data?.type === "YA_EMBED_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -5013,7 +5447,7 @@ function YaEmbed({
5013
5447
  window.addEventListener("message", handleMessage2);
5014
5448
  return () => window.removeEventListener("message", handleMessage2);
5015
5449
  }, [mode, fieldId]);
5016
- useEffect12(() => {
5450
+ useEffect13(() => {
5017
5451
  if (mode !== "inline-edit") return;
5018
5452
  const checkSize = () => {
5019
5453
  if (containerRef.current) {
@@ -5025,7 +5459,7 @@ function YaEmbed({
5025
5459
  window.addEventListener("resize", checkSize);
5026
5460
  return () => window.removeEventListener("resize", checkSize);
5027
5461
  }, [mode]);
5028
- useEffect12(() => {
5462
+ useEffect13(() => {
5029
5463
  if (!isSelected || mode !== "inline-edit") return;
5030
5464
  let lastRectKey = "";
5031
5465
  let lastTime = 0;
@@ -5062,16 +5496,16 @@ function YaEmbed({
5062
5496
  const renderEmbed = (isReadOnly) => {
5063
5497
  if (!src && !isReadOnly) {
5064
5498
  return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-placeholder", children: [
5065
- /* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG3, alt: "" }),
5066
- /* @__PURE__ */ jsx14("span", { children: "No embed selected" })
5499
+ /* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }),
5500
+ /* @__PURE__ */ jsx15("span", { children: "No embed selected" })
5067
5501
  ] });
5068
5502
  }
5069
5503
  if (!isInView && loading === "lazy" && !isReadOnly) {
5070
- return /* @__PURE__ */ jsx14("div", { className: "ya-embed-placeholder", style: { aspectRatio }, children: /* @__PURE__ */ jsx14("img", { src: PLACEHOLDER_SVG3, alt: "" }) });
5504
+ return /* @__PURE__ */ jsx15("div", { className: "ya-embed-placeholder", style: { aspectRatio }, children: /* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }) });
5071
5505
  }
5072
5506
  if (embedType === "spotify" && src) {
5073
5507
  const embedUrl = buildSpotifyEmbedUrl(src);
5074
- return /* @__PURE__ */ jsx14(
5508
+ return /* @__PURE__ */ jsx15(
5075
5509
  "iframe",
5076
5510
  {
5077
5511
  src: embedUrl,
@@ -5089,7 +5523,7 @@ function YaEmbed({
5089
5523
  }
5090
5524
  if (embedType === "soundcloud" && src) {
5091
5525
  const embedUrl = buildSoundCloudEmbedUrl(src);
5092
- return /* @__PURE__ */ jsx14(
5526
+ return /* @__PURE__ */ jsx15(
5093
5527
  "iframe",
5094
5528
  {
5095
5529
  src: embedUrl,
@@ -5106,13 +5540,13 @@ function YaEmbed({
5106
5540
  }
5107
5541
  if (embedType === "twitter" && src) {
5108
5542
  return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-twitter", children: [
5109
- /* @__PURE__ */ jsx14("blockquote", { className: "twitter-tweet", "data-dnt": "true", children: /* @__PURE__ */ jsx14("a", { href: embedData.originalUrl || `https://twitter.com/i/status/${src}`, children: "Loading tweet..." }) }),
5110
- /* @__PURE__ */ jsx14(TwitterWidgetLoader, {})
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, {})
5111
5545
  ] });
5112
5546
  }
5113
5547
  if (embedType === "instagram" && src) {
5114
5548
  const embedUrl = buildInstagramEmbedUrl(src);
5115
- return /* @__PURE__ */ jsx14(
5549
+ return /* @__PURE__ */ jsx15(
5116
5550
  "iframe",
5117
5551
  {
5118
5552
  src: embedUrl,
@@ -5130,7 +5564,7 @@ function YaEmbed({
5130
5564
  );
5131
5565
  }
5132
5566
  if (embedType === "custom" && src) {
5133
- return /* @__PURE__ */ jsx14(
5567
+ return /* @__PURE__ */ jsx15(
5134
5568
  "iframe",
5135
5569
  {
5136
5570
  src,
@@ -5154,7 +5588,7 @@ function YaEmbed({
5154
5588
  maxWidth: maxWidth ? `${maxWidth}px` : void 0
5155
5589
  };
5156
5590
  if (mode === "read-only") {
5157
- return /* @__PURE__ */ jsx14(
5591
+ return /* @__PURE__ */ jsx15(
5158
5592
  "div",
5159
5593
  {
5160
5594
  ref: containerRef,
@@ -5178,8 +5612,8 @@ function YaEmbed({
5178
5612
  strokeLinecap: "round",
5179
5613
  strokeLinejoin: "round",
5180
5614
  children: [
5181
- /* @__PURE__ */ jsx14("polyline", { points: "16 18 22 12 16 6" }),
5182
- /* @__PURE__ */ jsx14("polyline", { points: "8 6 2 12 8 18" })
5615
+ /* @__PURE__ */ jsx15("polyline", { points: "16 18 22 12 16 6" }),
5616
+ /* @__PURE__ */ jsx15("polyline", { points: "8 6 2 12 8 18" })
5183
5617
  ]
5184
5618
  }
5185
5619
  );
@@ -5208,12 +5642,12 @@ function YaEmbed({
5208
5642
  renderEmbed(false),
5209
5643
  isSmallEmbed ? /* @__PURE__ */ jsxs8(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
5210
5644
  embedIcon,
5211
- /* @__PURE__ */ jsx14("span", { children: "Click to edit" })
5645
+ /* @__PURE__ */ jsx15("span", { children: "Click to edit" })
5212
5646
  ] }) : (
5213
5647
  /* For large embeds: show overlay inside the container */
5214
5648
  /* @__PURE__ */ jsxs8("div", { className: "ya-embed-overlay", children: [
5215
- /* @__PURE__ */ jsx14("div", { className: "ya-embed-edit-icon", children: embedIcon }),
5216
- /* @__PURE__ */ jsx14("span", { className: "ya-embed-edit-label", children: "Click to edit" })
5649
+ /* @__PURE__ */ jsx15("div", { className: "ya-embed-edit-icon", children: embedIcon }),
5650
+ /* @__PURE__ */ jsx15("span", { className: "ya-embed-edit-label", children: "Click to edit" })
5217
5651
  ] })
5218
5652
  )
5219
5653
  ]
@@ -5221,7 +5655,7 @@ function YaEmbed({
5221
5655
  );
5222
5656
  }
5223
5657
  function TwitterWidgetLoader() {
5224
- useEffect12(() => {
5658
+ useEffect13(() => {
5225
5659
  if (window.twttr?.widgets) {
5226
5660
  ;
5227
5661
  window.twttr.widgets.load();
@@ -5242,7 +5676,7 @@ function TwitterWidgetLoader() {
5242
5676
  }
5243
5677
 
5244
5678
  // src/components/YaLink.tsx
5245
- import { useEffect as useEffect15, useLayoutEffect as useLayoutEffect3, useRef as useRef16, useState as useState15, useCallback as useCallback17, useId } from "react";
5679
+ import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useRef as useRef17, useState as useState16, useCallback as useCallback18, useId } from "react";
5246
5680
  import { createPortal as createPortal6 } from "react-dom";
5247
5681
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
5248
5682
  import { BubbleMenu } from "@tiptap/react/menus";
@@ -5252,7 +5686,7 @@ import { Extension as Extension2 } from "@tiptap/core";
5252
5686
  import { Link as WouterLink, useLocation } from "wouter";
5253
5687
 
5254
5688
  // src/components/SafeTriangleBelow.tsx
5255
- import { useEffect as useEffect13, useState as useState13, useRef as useRef14, useCallback as useCallback15 } from "react";
5689
+ import { useEffect as useEffect14, useState as useState14, useRef as useRef15, useCallback as useCallback16 } from "react";
5256
5690
  function SafeTriangleBelow({
5257
5691
  triggerRef,
5258
5692
  popoverRef,
@@ -5260,10 +5694,10 @@ function SafeTriangleBelow({
5260
5694
  onLeave,
5261
5695
  onStayInside
5262
5696
  }) {
5263
- const [bounds, setBounds] = useState13(null);
5264
- const boundsRef = useRef14(bounds);
5697
+ const [bounds, setBounds] = useState14(null);
5698
+ const boundsRef = useRef15(bounds);
5265
5699
  boundsRef.current = bounds;
5266
- useEffect13(() => {
5700
+ useEffect14(() => {
5267
5701
  if (!isVisible || !triggerRef.current || !popoverRef.current) {
5268
5702
  setBounds(null);
5269
5703
  return;
@@ -5281,7 +5715,7 @@ function SafeTriangleBelow({
5281
5715
  }, 10);
5282
5716
  return () => clearTimeout(timer);
5283
5717
  }, [isVisible, triggerRef, popoverRef]);
5284
- const checkMousePosition = useCallback15((e) => {
5718
+ const checkMousePosition = useCallback16((e) => {
5285
5719
  const b = boundsRef.current;
5286
5720
  if (!b) return;
5287
5721
  const { clientX: x, clientY: y } = e;
@@ -5293,7 +5727,7 @@ function SafeTriangleBelow({
5293
5727
  onStayInside?.();
5294
5728
  }
5295
5729
  }, [onLeave, onStayInside]);
5296
- useEffect13(() => {
5730
+ useEffect14(() => {
5297
5731
  if (!isVisible || !bounds) return;
5298
5732
  document.addEventListener("mousemove", checkMousePosition);
5299
5733
  return () => document.removeEventListener("mousemove", checkMousePosition);
@@ -5302,22 +5736,22 @@ function SafeTriangleBelow({
5302
5736
  }
5303
5737
 
5304
5738
  // src/hooks/useSafeTriangle.ts
5305
- import { useState as useState14, useRef as useRef15, useCallback as useCallback16, useEffect as useEffect14 } from "react";
5739
+ import { useState as useState15, useRef as useRef16, useCallback as useCallback17, useEffect as useEffect15 } from "react";
5306
5740
  function useSafeTriangle(options = {}) {
5307
5741
  const { showDelay = 0, hideDelay = 150, enabled = true } = options;
5308
- const [isVisible, setIsVisible] = useState14(false);
5309
- const [isHovering, setIsHovering] = useState14(false);
5310
- const triggerRef = useRef15(null);
5311
- const popoverRef = useRef15(null);
5312
- const showTimeoutRef = useRef15(null);
5313
- const hideTimeoutRef = useRef15(null);
5314
- useEffect14(() => {
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(() => {
5315
5749
  return () => {
5316
5750
  if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
5317
5751
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
5318
5752
  };
5319
5753
  }, []);
5320
- const show = useCallback16(() => {
5754
+ const show = useCallback17(() => {
5321
5755
  if (!enabled) return;
5322
5756
  if (hideTimeoutRef.current) {
5323
5757
  clearTimeout(hideTimeoutRef.current);
@@ -5325,7 +5759,7 @@ function useSafeTriangle(options = {}) {
5325
5759
  }
5326
5760
  setIsVisible(true);
5327
5761
  }, [enabled]);
5328
- const hide = useCallback16(() => {
5762
+ const hide = useCallback17(() => {
5329
5763
  if (showTimeoutRef.current) {
5330
5764
  clearTimeout(showTimeoutRef.current);
5331
5765
  showTimeoutRef.current = null;
@@ -5333,7 +5767,7 @@ function useSafeTriangle(options = {}) {
5333
5767
  setIsVisible(false);
5334
5768
  setIsHovering(false);
5335
5769
  }, []);
5336
- const handleMouseEnter = useCallback16(() => {
5770
+ const handleMouseEnter = useCallback17(() => {
5337
5771
  if (!enabled) return;
5338
5772
  setIsHovering(true);
5339
5773
  if (hideTimeoutRef.current) {
@@ -5348,7 +5782,7 @@ function useSafeTriangle(options = {}) {
5348
5782
  setIsVisible(true);
5349
5783
  }
5350
5784
  }, [showDelay, enabled]);
5351
- const handleMouseLeave = useCallback16(() => {
5785
+ const handleMouseLeave = useCallback17(() => {
5352
5786
  setIsHovering(false);
5353
5787
  if (showTimeoutRef.current) {
5354
5788
  clearTimeout(showTimeoutRef.current);
@@ -5358,16 +5792,16 @@ function useSafeTriangle(options = {}) {
5358
5792
  setIsVisible(false);
5359
5793
  }, hideDelay);
5360
5794
  }, [hideDelay]);
5361
- const handleFocus = useCallback16(() => {
5795
+ const handleFocus = useCallback17(() => {
5362
5796
  if (!enabled) return;
5363
5797
  setIsVisible(true);
5364
5798
  }, [enabled]);
5365
- const handleTriangleLeave = useCallback16(() => {
5799
+ const handleTriangleLeave = useCallback17(() => {
5366
5800
  if (!isHovering) {
5367
5801
  setIsVisible(false);
5368
5802
  }
5369
5803
  }, [isHovering]);
5370
- const handleStayInside = useCallback16(() => {
5804
+ const handleStayInside = useCallback17(() => {
5371
5805
  if (hideTimeoutRef.current) {
5372
5806
  clearTimeout(hideTimeoutRef.current);
5373
5807
  hideTimeoutRef.current = null;
@@ -5398,7 +5832,7 @@ function useSafeTriangle(options = {}) {
5398
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');
5399
5833
 
5400
5834
  // src/components/YaLink.tsx
5401
- import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
5835
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5402
5836
  function isInternalPath(path) {
5403
5837
  if (!path) return false;
5404
5838
  if (path.startsWith("#")) return false;
@@ -5496,37 +5930,40 @@ function discoverSectionsFromDOM() {
5496
5930
  return sections;
5497
5931
  }
5498
5932
  function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName, style, as: Component = "a", children, availablePages, onClick, target, rel }) {
5499
- const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
5500
- const [, navigate] = useLocation();
5501
- const pages = availablePages ?? getPages();
5502
- const [sections, setSections] = useState15([]);
5503
- const [sectionsExpanded, setSectionsExpanded] = useState15(false);
5504
5933
  const textFieldId = `${fieldId}.text`;
5505
5934
  const hrefFieldId = `${fieldId}.href`;
5506
- const storeText = getValue(textFieldId);
5507
- const storeHref = getValue(hrefFieldId);
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();
5508
5945
  const isIconMode = children != null && typeof children !== "string";
5509
5946
  const text2 = storeText || (typeof children === "string" ? children : "");
5510
5947
  const href = storeHref || defaultHref;
5511
5948
  const isExternal = isExternalHref(href);
5512
5949
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
5513
5950
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
5514
- const [editingMode, setEditingMode] = useState15(null);
5515
- const [originalText, setOriginalText] = useState15(text2);
5516
- const [originalHref, setOriginalHref] = useState15(href);
5517
- const [currentHref, setCurrentHref] = useState15(href);
5518
- const [isExternalUrl, setIsExternalUrl] = useState15(false);
5519
- const [externalUrl, setExternalUrl] = useState15("");
5520
- const containerRef = useRef16(null);
5521
- const hrefPopoverRef = useRef16(null);
5522
- const [actionButtonsPos, setActionButtonsPos] = useState15(null);
5523
- const [editPopoverPos, setEditPopoverPos] = useState15(null);
5524
- const [editPopoverVisible, setEditPopoverVisible] = useState15(false);
5525
- const [editPopoverMounted, setEditPopoverMounted] = useState15(false);
5526
- const [hrefPopoverPos, setHrefPopoverPos] = useState15(null);
5527
- const handleSaveTextRef = useRef16(() => {
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(() => {
5528
5965
  });
5529
- const handleCancelTextRef = useRef16(() => {
5966
+ const handleCancelTextRef = useRef17(() => {
5530
5967
  });
5531
5968
  const {
5532
5969
  popoverRef: editPopoverRef,
@@ -5540,12 +5977,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5540
5977
  });
5541
5978
  const triggerRef = containerRef;
5542
5979
  const instanceId = useId();
5543
- useEffect15(() => {
5980
+ useEffect16(() => {
5544
5981
  if (showEditPopover && mode === "inline-edit" && !editingMode) {
5545
5982
  window.dispatchEvent(new CustomEvent("yalink:popover-open", { detail: { id: instanceId } }));
5546
5983
  }
5547
5984
  }, [showEditPopover, mode, editingMode, instanceId]);
5548
- useEffect15(() => {
5985
+ useEffect16(() => {
5549
5986
  const handleOtherPopoverOpen = (event) => {
5550
5987
  const customEvent = event;
5551
5988
  if (customEvent.detail.id !== instanceId && showEditPopover) {
@@ -5599,19 +6036,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5599
6036
  }
5600
6037
  }
5601
6038
  });
5602
- useEffect15(() => {
6039
+ useEffect16(() => {
5603
6040
  if (editor && editingMode !== "text") {
5604
6041
  if (editor.getHTML() !== text2) {
5605
6042
  editor.commands.setContent(text2);
5606
6043
  }
5607
6044
  }
5608
6045
  }, [text2, editor, editingMode]);
5609
- useEffect15(() => {
6046
+ useEffect16(() => {
5610
6047
  if (editingMode !== "link") {
5611
6048
  setCurrentHref(href);
5612
6049
  }
5613
6050
  }, [href, editingMode]);
5614
- useEffect15(() => {
6051
+ useEffect16(() => {
5615
6052
  if (editingMode !== "text" || !containerRef.current) {
5616
6053
  setActionButtonsPos(null);
5617
6054
  return;
@@ -5632,7 +6069,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5632
6069
  window.removeEventListener("resize", updatePosition);
5633
6070
  };
5634
6071
  }, [editingMode]);
5635
- useEffect15(() => {
6072
+ useEffect16(() => {
5636
6073
  const shouldShow = showEditPopover && !editingMode && mode === "inline-edit";
5637
6074
  if (shouldShow) {
5638
6075
  setEditPopoverMounted(true);
@@ -5694,7 +6131,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5694
6131
  window.removeEventListener("resize", updatePosition);
5695
6132
  };
5696
6133
  }, [editingMode]);
5697
- useEffect15(() => {
6134
+ useEffect16(() => {
5698
6135
  if (editingMode !== "link") return;
5699
6136
  const handleClickOutside = (event) => {
5700
6137
  const target2 = event.target;
@@ -5708,38 +6145,38 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5708
6145
  document.addEventListener("mousedown", handleClickOutside);
5709
6146
  return () => document.removeEventListener("mousedown", handleClickOutside);
5710
6147
  }, [editingMode, originalHref]);
5711
- const handleSaveText = useCallback17(() => {
6148
+ const handleSaveText = useCallback18(() => {
5712
6149
  if (!editor) return;
5713
6150
  let html = editor.getHTML();
5714
6151
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
5715
- setValue(textFieldId, html, "user");
5716
- saveToWorker?.(textFieldId, html);
6152
+ textContent.set(html, "user");
6153
+ textContent.save();
5717
6154
  setEditingMode(null);
5718
- }, [editor, textFieldId, setValue, saveToWorker]);
5719
- const handleSaveLink = useCallback17(() => {
5720
- setValue(hrefFieldId, currentHref, "user");
5721
- saveToWorker?.(hrefFieldId, currentHref);
6155
+ }, [editor, textContent]);
6156
+ const handleSaveLink = useCallback18(() => {
6157
+ hrefContent.set(currentHref, "user");
6158
+ hrefContent.save();
5722
6159
  setEditingMode(null);
5723
6160
  setIsExternalUrl(false);
5724
6161
  setExternalUrl("");
5725
- }, [hrefFieldId, currentHref, setValue, saveToWorker]);
5726
- const handleCancelText = useCallback17(() => {
6162
+ }, [currentHref, hrefContent]);
6163
+ const handleCancelText = useCallback18(() => {
5727
6164
  if (editor) {
5728
6165
  editor.commands.setContent(originalText);
5729
6166
  }
5730
6167
  setEditingMode(null);
5731
6168
  }, [editor, originalText]);
5732
- const handleCancelLink = useCallback17(() => {
6169
+ const handleCancelLink = useCallback18(() => {
5733
6170
  setCurrentHref(originalHref);
5734
6171
  setEditingMode(null);
5735
6172
  setIsExternalUrl(false);
5736
6173
  setExternalUrl("");
5737
6174
  }, [originalHref]);
5738
- useEffect15(() => {
6175
+ useEffect16(() => {
5739
6176
  handleSaveTextRef.current = handleSaveText;
5740
6177
  handleCancelTextRef.current = handleCancelText;
5741
6178
  }, [handleSaveText, handleCancelText]);
5742
- const handleClick = useCallback17(
6179
+ const handleClick = useCallback18(
5743
6180
  (e) => {
5744
6181
  const selectModeEnabled = window.__builderSelectModeEnabled;
5745
6182
  if (selectModeEnabled) {
@@ -5771,7 +6208,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5771
6208
  },
5772
6209
  [href, navigate, onClick]
5773
6210
  );
5774
- const startEditText = useCallback17(() => {
6211
+ const startEditText = useCallback18(() => {
5775
6212
  hideEditPopover();
5776
6213
  if (isIconMode) {
5777
6214
  window.dispatchEvent(new CustomEvent("yatext:edit-mode", {
@@ -5785,14 +6222,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5785
6222
  }, 20);
5786
6223
  }
5787
6224
  }, [text2, editor, hideEditPopover, isIconMode, fieldId]);
5788
- const startEditLink = useCallback17(() => {
6225
+ const startEditLink = useCallback18(() => {
5789
6226
  hideEditPopover();
5790
6227
  setEditingMode("link");
5791
6228
  setOriginalHref(href);
5792
6229
  setCurrentHref(href);
5793
6230
  setSections(discoverSectionsFromDOM());
5794
6231
  }, [href, hideEditPopover]);
5795
- const handleKeyDown = useCallback17(
6232
+ const handleKeyDown = useCallback18(
5796
6233
  (event) => {
5797
6234
  if (editingMode !== "text") return;
5798
6235
  if (event.key === "Enter" && !event.shiftKey) {
@@ -5813,7 +6250,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5813
6250
  },
5814
6251
  [editingMode, handleSaveText, handleCancelText]
5815
6252
  );
5816
- const handleFontSizeChange = useCallback17(
6253
+ const handleFontSizeChange = useCallback18(
5817
6254
  (e) => {
5818
6255
  if (!editor) return;
5819
6256
  const size = e.target.value;
@@ -5825,7 +6262,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5825
6262
  },
5826
6263
  [editor]
5827
6264
  );
5828
- const handleFontWeightChange = useCallback17(
6265
+ const handleFontWeightChange = useCallback18(
5829
6266
  (e) => {
5830
6267
  if (!editor) return;
5831
6268
  const weight = e.target.value;
@@ -5837,11 +6274,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5837
6274
  },
5838
6275
  [editor]
5839
6276
  );
5840
- const handlePageSelect = useCallback17((path) => {
6277
+ const handlePageSelect = useCallback18((path) => {
5841
6278
  setCurrentHref(path);
5842
6279
  setIsExternalUrl(false);
5843
6280
  }, []);
5844
- const handleExternalUrlApply = useCallback17(() => {
6281
+ const handleExternalUrlApply = useCallback18(() => {
5845
6282
  if (externalUrl) {
5846
6283
  setCurrentHref(externalUrl);
5847
6284
  }
@@ -5857,9 +6294,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5857
6294
  return attrs.fontWeight || "";
5858
6295
  };
5859
6296
  if (mode === "read-only") {
5860
- const content = isIconMode ? children : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode });
6297
+ const content = isIconMode ? children : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode });
5861
6298
  if (isInternalPath(href)) {
5862
- return /* @__PURE__ */ jsx15(
6299
+ return /* @__PURE__ */ jsx16(
5863
6300
  WouterLink,
5864
6301
  {
5865
6302
  href,
@@ -5871,7 +6308,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5871
6308
  }
5872
6309
  );
5873
6310
  }
5874
- return /* @__PURE__ */ jsx15(
6311
+ return /* @__PURE__ */ jsx16(
5875
6312
  Component,
5876
6313
  {
5877
6314
  ref: containerRef,
@@ -5887,7 +6324,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5887
6324
  );
5888
6325
  }
5889
6326
  return /* @__PURE__ */ jsxs9("span", { className: `ya-link-wrapper ${wrapperClassName || ""}`, children: [
5890
- /* @__PURE__ */ jsx15(
6327
+ /* @__PURE__ */ jsx16(
5891
6328
  Component,
5892
6329
  {
5893
6330
  ref: containerRef,
@@ -5916,27 +6353,27 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5916
6353
  options: { offset: 6, placement: "top" },
5917
6354
  className: "ya-bubble-menu",
5918
6355
  children: [
5919
- /* @__PURE__ */ jsx15(
6356
+ /* @__PURE__ */ jsx16(
5920
6357
  "button",
5921
6358
  {
5922
6359
  type: "button",
5923
6360
  onClick: () => editor.chain().focus().toggleBold().run(),
5924
6361
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
5925
6362
  title: "Bold",
5926
- children: /* @__PURE__ */ jsx15("strong", { children: "B" })
6363
+ children: /* @__PURE__ */ jsx16("strong", { children: "B" })
5927
6364
  }
5928
6365
  ),
5929
- /* @__PURE__ */ jsx15(
6366
+ /* @__PURE__ */ jsx16(
5930
6367
  "button",
5931
6368
  {
5932
6369
  type: "button",
5933
6370
  onClick: () => editor.chain().focus().toggleItalic().run(),
5934
6371
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
5935
6372
  title: "Italic",
5936
- children: /* @__PURE__ */ jsx15("em", { children: "I" })
6373
+ children: /* @__PURE__ */ jsx16("em", { children: "I" })
5937
6374
  }
5938
6375
  ),
5939
- /* @__PURE__ */ jsx15("span", { className: "ya-bubble-divider" }),
6376
+ /* @__PURE__ */ jsx16("span", { className: "ya-bubble-divider" }),
5940
6377
  /* @__PURE__ */ jsxs9(
5941
6378
  "select",
5942
6379
  {
@@ -5945,8 +6382,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5945
6382
  className: "ya-bubble-select",
5946
6383
  title: "Font Size",
5947
6384
  children: [
5948
- /* @__PURE__ */ jsx15("option", { value: "", children: "Size" }),
5949
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx15("option", { value: size, children: name }, name))
6385
+ /* @__PURE__ */ jsx16("option", { value: "", children: "Size" }),
6386
+ Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx16("option", { value: size, children: name }, name))
5950
6387
  ]
5951
6388
  }
5952
6389
  ),
@@ -5958,8 +6395,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5958
6395
  className: "ya-bubble-select",
5959
6396
  title: "Font Weight",
5960
6397
  children: [
5961
- /* @__PURE__ */ jsx15("option", { value: "", children: "Weight" }),
5962
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx15("option", { value: weight, children: name }, name))
6398
+ /* @__PURE__ */ jsx16("option", { value: "", children: "Weight" }),
6399
+ Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx16("option", { value: weight, children: name }, name))
5963
6400
  ]
5964
6401
  }
5965
6402
  )
@@ -5969,7 +6406,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5969
6406
  document.body
5970
6407
  ),
5971
6408
  editingMode === "text" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
5972
- /* @__PURE__ */ jsx15(EditorContent2, { editor }),
6409
+ /* @__PURE__ */ jsx16(EditorContent2, { editor }),
5973
6410
  actionButtonsPos && createPortal6(
5974
6411
  /* @__PURE__ */ jsxs9(
5975
6412
  "div",
@@ -5981,15 +6418,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5981
6418
  right: actionButtonsPos.right
5982
6419
  },
5983
6420
  children: [
5984
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
5985
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
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" })
5986
6423
  ]
5987
6424
  }
5988
6425
  ),
5989
6426
  document.body
5990
6427
  )
5991
- ] }) : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode })
5992
- ] }) : /* @__PURE__ */ jsx15(SafeHtml, { content: text2, mode })
6428
+ ] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
6429
+ ] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
5993
6430
  }
5994
6431
  ),
5995
6432
  editPopoverMounted && editPopoverPos && createPortal6(
@@ -6007,14 +6444,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6007
6444
  onMouseEnter: safeTriangleHandlers.onMouseEnter,
6008
6445
  onMouseLeave: safeTriangleHandlers.onMouseLeave,
6009
6446
  children: [
6010
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: startEditText, children: "Edit text" }),
6011
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: startEditLink, children: "Edit link" })
6447
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditText, children: "Edit text" }),
6448
+ /* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditLink, children: "Edit link" })
6012
6449
  ]
6013
6450
  }
6014
6451
  ),
6015
6452
  document.body
6016
6453
  ),
6017
- /* @__PURE__ */ jsx15(
6454
+ /* @__PURE__ */ jsx16(
6018
6455
  SafeTriangleBelow,
6019
6456
  {
6020
6457
  triggerRef,
@@ -6037,7 +6474,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6037
6474
  transform: "translateX(-50%)"
6038
6475
  },
6039
6476
  children: [
6040
- /* @__PURE__ */ jsx15("div", { className: "ya-href-popover-header", children: "Link destination" }),
6477
+ /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-header", children: "Link destination" }),
6041
6478
  !isExternalUrl ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
6042
6479
  sections.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6043
6480
  /* @__PURE__ */ jsxs9(
@@ -6047,14 +6484,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6047
6484
  className: "ya-href-popover-label ya-href-collapsible-header",
6048
6485
  onClick: () => setSectionsExpanded(!sectionsExpanded),
6049
6486
  children: [
6050
- /* @__PURE__ */ jsx15("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
6487
+ /* @__PURE__ */ jsx16("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
6051
6488
  "Scroll to section (",
6052
6489
  sections.length,
6053
6490
  ")"
6054
6491
  ]
6055
6492
  }
6056
6493
  ),
6057
- sectionsExpanded && /* @__PURE__ */ jsx15("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs9(
6494
+ sectionsExpanded && /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs9(
6058
6495
  "button",
6059
6496
  {
6060
6497
  type: "button",
@@ -6062,15 +6499,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6062
6499
  onClick: () => handlePageSelect(section.path),
6063
6500
  children: [
6064
6501
  section.label,
6065
- /* @__PURE__ */ jsx15("span", { className: "ya-href-page-path", children: section.path })
6502
+ /* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: section.path })
6066
6503
  ]
6067
6504
  },
6068
6505
  section.path
6069
6506
  )) })
6070
6507
  ] }),
6071
6508
  pages.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6072
- /* @__PURE__ */ jsx15("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
6073
- /* @__PURE__ */ jsx15("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs9(
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(
6074
6511
  "button",
6075
6512
  {
6076
6513
  type: "button",
@@ -6078,13 +6515,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6078
6515
  onClick: () => handlePageSelect(page.path),
6079
6516
  children: [
6080
6517
  page.label,
6081
- /* @__PURE__ */ jsx15("span", { className: "ya-href-page-path", children: page.path })
6518
+ /* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: page.path })
6082
6519
  ]
6083
6520
  },
6084
6521
  page.path
6085
6522
  )) })
6086
6523
  ] }),
6087
- /* @__PURE__ */ jsx15(
6524
+ /* @__PURE__ */ jsx16(
6088
6525
  "button",
6089
6526
  {
6090
6527
  type: "button",
@@ -6098,8 +6535,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6098
6535
  )
6099
6536
  ] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
6100
6537
  /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6101
- /* @__PURE__ */ jsx15("label", { className: "ya-href-popover-label", children: "External URL" }),
6102
- /* @__PURE__ */ jsx15(
6538
+ /* @__PURE__ */ jsx16("label", { className: "ya-href-popover-label", children: "External URL" }),
6539
+ /* @__PURE__ */ jsx16(
6103
6540
  "input",
6104
6541
  {
6105
6542
  type: "url",
@@ -6111,11 +6548,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6111
6548
  }
6112
6549
  )
6113
6550
  ] }),
6114
- /* @__PURE__ */ jsx15("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
6551
+ /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
6115
6552
  ] }),
6116
6553
  /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-actions", children: [
6117
- /* @__PURE__ */ jsx15("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
6118
- isExternalUrl ? /* @__PURE__ */ jsx15("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx15("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
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" })
6119
6556
  ] })
6120
6557
  ]
6121
6558
  }
@@ -6126,34 +6563,34 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6126
6563
  }
6127
6564
 
6128
6565
  // src/components/YaContainer.tsx
6129
- import { useCallback as useCallback19, useEffect as useEffect17, useRef as useRef18, useState as useState17 } from "react";
6566
+ import { useCallback as useCallback20, useEffect as useEffect18, useRef as useRef19, useState as useState18 } from "react";
6130
6567
  import { createPortal as createPortal8 } from "react-dom";
6131
6568
 
6132
6569
  // src/components/Tooltip.tsx
6133
- import { useState as useState16, useRef as useRef17, useEffect as useEffect16, useLayoutEffect as useLayoutEffect4, useCallback as useCallback18 } from "react";
6570
+ import { useState as useState17, useRef as useRef18, useEffect as useEffect17, useLayoutEffect as useLayoutEffect4, useCallback as useCallback19 } from "react";
6134
6571
  import { createPortal as createPortal7 } from "react-dom";
6135
6572
 
6136
6573
  // src/components/tooltip.css
6137
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');
6138
6575
 
6139
6576
  // src/components/Tooltip.tsx
6140
- import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
6577
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
6141
6578
  function Tooltip({
6142
6579
  content,
6143
6580
  children,
6144
6581
  position = "bottom",
6145
6582
  delay = 0
6146
6583
  }) {
6147
- const [isVisible, setIsVisible] = useState16(false);
6148
- const [tooltipPosition, setTooltipPosition] = useState16(null);
6149
- const [isMounted, setIsMounted] = useState16(false);
6150
- const triggerRef = useRef17(null);
6151
- const tooltipRef = useRef17(null);
6152
- const timeoutRef = useRef17(null);
6153
- useEffect16(() => {
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(() => {
6154
6591
  setIsMounted(true);
6155
6592
  }, []);
6156
- const calculatePosition = useCallback18(() => {
6593
+ const calculatePosition = useCallback19(() => {
6157
6594
  if (!triggerRef.current) return null;
6158
6595
  const triggerRect = triggerRef.current.getBoundingClientRect();
6159
6596
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -6238,7 +6675,7 @@ function Tooltip({
6238
6675
  setIsVisible(false);
6239
6676
  setTooltipPosition(null);
6240
6677
  };
6241
- useEffect16(() => {
6678
+ useEffect17(() => {
6242
6679
  return () => {
6243
6680
  if (timeoutRef.current) {
6244
6681
  clearTimeout(timeoutRef.current);
@@ -6311,7 +6748,7 @@ function Tooltip({
6311
6748
  role: "tooltip",
6312
6749
  children: [
6313
6750
  content,
6314
- /* @__PURE__ */ jsx16(
6751
+ /* @__PURE__ */ jsx17(
6315
6752
  "div",
6316
6753
  {
6317
6754
  className: "ya-tooltip-v2-arrow",
@@ -6324,7 +6761,7 @@ function Tooltip({
6324
6761
  document.body
6325
6762
  ) : null;
6326
6763
  return /* @__PURE__ */ jsxs10(Fragment5, { children: [
6327
- /* @__PURE__ */ jsx16(
6764
+ /* @__PURE__ */ jsx17(
6328
6765
  "div",
6329
6766
  {
6330
6767
  ref: triggerRef,
@@ -6342,7 +6779,7 @@ function Tooltip({
6342
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');
6343
6780
 
6344
6781
  // src/components/YaContainer.tsx
6345
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
6782
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
6346
6783
  function parseBackgroundConfig(value) {
6347
6784
  if (!value) {
6348
6785
  return { type: "none" };
@@ -6384,8 +6821,8 @@ function deriveContainerLabel(element) {
6384
6821
  return tagLabels[tagName] || "Section";
6385
6822
  }
6386
6823
  function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAIClick, onClearClick, hasBackground }) {
6387
- const [position, setPosition] = useState17(null);
6388
- useEffect17(() => {
6824
+ const [position, setPosition] = useState18(null);
6825
+ useEffect18(() => {
6389
6826
  const updatePosition = () => {
6390
6827
  if (containerRef.current) {
6391
6828
  const rect = containerRef.current.getBoundingClientRect();
@@ -6416,40 +6853,40 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAICli
6416
6853
  },
6417
6854
  onClick: (e) => e.stopPropagation(),
6418
6855
  children: [
6419
- /* @__PURE__ */ jsx17(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx17(
6856
+ /* @__PURE__ */ jsx18(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx18(
6420
6857
  "button",
6421
6858
  {
6422
6859
  type: "button",
6423
6860
  onClick: onImageClick,
6424
6861
  "aria-label": "Edit background image",
6425
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: [
6426
- /* @__PURE__ */ jsx17("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
6427
- /* @__PURE__ */ jsx17("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
6428
- /* @__PURE__ */ jsx17("polyline", { points: "21 15 16 10 5 21" })
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" })
6429
6866
  ] })
6430
6867
  }
6431
6868
  ) }),
6432
- /* @__PURE__ */ jsx17(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx17(
6869
+ /* @__PURE__ */ jsx18(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx18(
6433
6870
  "button",
6434
6871
  {
6435
6872
  type: "button",
6436
6873
  onClick: onColorClick,
6437
6874
  "aria-label": "Edit background color",
6438
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: [
6439
- /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "10" }),
6440
- /* @__PURE__ */ jsx17("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
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" })
6441
6878
  ] })
6442
6879
  }
6443
6880
  ) }),
6444
- hasBackground && /* @__PURE__ */ jsx17(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx17(
6881
+ hasBackground && /* @__PURE__ */ jsx18(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx18(
6445
6882
  "button",
6446
6883
  {
6447
6884
  type: "button",
6448
6885
  onClick: onClearClick,
6449
6886
  "aria-label": "Clear background",
6450
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: [
6451
- /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "10" }),
6452
- /* @__PURE__ */ jsx17("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
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" })
6453
6890
  ] })
6454
6891
  }
6455
6892
  ) })
@@ -6468,13 +6905,13 @@ function YaContainer({
6468
6905
  defaultBackground
6469
6906
  }) {
6470
6907
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
6471
- const containerRef = useRef18(null);
6472
- const [isHovered, setIsHovered] = useState17(false);
6473
- const [isSelected, setIsSelected] = useState17(false);
6474
- const [isDropMode, setIsDropMode] = useState17(false);
6475
- const [isDropHover, setIsDropHover] = useState17(false);
6476
- const [previewConfig, setPreviewConfig] = useState17(null);
6477
- useEffect17(() => {
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(() => {
6478
6915
  if (mode !== "inline-edit") return;
6479
6916
  const containerEl = containerRef.current;
6480
6917
  if (!containerEl) return;
@@ -6517,7 +6954,7 @@ function YaContainer({
6517
6954
  overlayCustomProps["--ya-overlay-color"] = displayConfig.overlay.color;
6518
6955
  overlayCustomProps["--ya-overlay-opacity"] = displayConfig.overlay.opacity;
6519
6956
  }
6520
- const handleImageClick = useCallback19(() => {
6957
+ const handleImageClick = useCallback20(() => {
6521
6958
  if (mode !== "inline-edit") return;
6522
6959
  setIsSelected(true);
6523
6960
  const rect = containerRef.current?.getBoundingClientRect();
@@ -6537,7 +6974,7 @@ function YaContainer({
6537
6974
  "*"
6538
6975
  );
6539
6976
  }, [mode, fieldId, backgroundConfig]);
6540
- const handleColorClick = useCallback19(() => {
6977
+ const handleColorClick = useCallback20(() => {
6541
6978
  if (mode !== "inline-edit") return;
6542
6979
  setIsSelected(true);
6543
6980
  const rect = containerRef.current?.getBoundingClientRect();
@@ -6557,7 +6994,7 @@ function YaContainer({
6557
6994
  "*"
6558
6995
  );
6559
6996
  }, [mode, fieldId, backgroundConfig]);
6560
- const handleAIClick = useCallback19(() => {
6997
+ const handleAIClick = useCallback20(() => {
6561
6998
  if (mode !== "inline-edit") return;
6562
6999
  const label = deriveContainerLabel(containerRef.current);
6563
7000
  window.parent.postMessage(
@@ -6570,14 +7007,14 @@ function YaContainer({
6570
7007
  "*"
6571
7008
  );
6572
7009
  }, [mode, fieldId, backgroundConfig]);
6573
- const handleClearClick = useCallback19(() => {
7010
+ const handleClearClick = useCallback20(() => {
6574
7011
  if (mode !== "inline-edit") return;
6575
7012
  const clearedConfig = { type: "none" };
6576
7013
  const serialized = serializeBackgroundConfig(clearedConfig);
6577
7014
  setValue(fieldId, serialized);
6578
7015
  saveToWorker?.(fieldId, serialized);
6579
7016
  }, [mode, fieldId, setValue, saveToWorker]);
6580
- useEffect17(() => {
7017
+ useEffect18(() => {
6581
7018
  if (mode !== "inline-edit") return;
6582
7019
  const handleMessage2 = (event) => {
6583
7020
  if (event.data?.type === "YA_CONTAINER_UPDATE_PREVIEW" && event.data.fieldId === fieldId) {
@@ -6598,7 +7035,7 @@ function YaContainer({
6598
7035
  window.addEventListener("message", handleMessage2);
6599
7036
  return () => window.removeEventListener("message", handleMessage2);
6600
7037
  }, [mode, fieldId]);
6601
- useEffect17(() => {
7038
+ useEffect18(() => {
6602
7039
  if (mode !== "inline-edit") return;
6603
7040
  const handleDropModeMessage = (event) => {
6604
7041
  if (event.data?.type === "DROP_MODE_START") {
@@ -6612,7 +7049,7 @@ function YaContainer({
6612
7049
  window.addEventListener("message", handleDropModeMessage);
6613
7050
  return () => window.removeEventListener("message", handleDropModeMessage);
6614
7051
  }, [mode]);
6615
- const handleDragEnter = useCallback19(
7052
+ const handleDragEnter = useCallback20(
6616
7053
  (e) => {
6617
7054
  if (!isDropMode) return;
6618
7055
  e.preventDefault();
@@ -6636,7 +7073,7 @@ function YaContainer({
6636
7073
  },
6637
7074
  [isDropMode, fieldId]
6638
7075
  );
6639
- const handleDragOver = useCallback19(
7076
+ const handleDragOver = useCallback20(
6640
7077
  (e) => {
6641
7078
  if (!isDropMode) return;
6642
7079
  e.preventDefault();
@@ -6644,7 +7081,7 @@ function YaContainer({
6644
7081
  },
6645
7082
  [isDropMode]
6646
7083
  );
6647
- const handleDragLeave = useCallback19(
7084
+ const handleDragLeave = useCallback20(
6648
7085
  (e) => {
6649
7086
  if (!isDropMode) return;
6650
7087
  e.preventDefault();
@@ -6658,7 +7095,7 @@ function YaContainer({
6658
7095
  },
6659
7096
  [isDropMode]
6660
7097
  );
6661
- const handleDrop = useCallback19(
7098
+ const handleDrop = useCallback20(
6662
7099
  (e) => {
6663
7100
  if (!isDropMode) return;
6664
7101
  e.preventDefault();
@@ -6676,7 +7113,7 @@ function YaContainer({
6676
7113
  },
6677
7114
  [isDropMode, fieldId]
6678
7115
  );
6679
- useEffect17(() => {
7116
+ useEffect18(() => {
6680
7117
  if (!isSelected || mode !== "inline-edit") return;
6681
7118
  let lastRectKey = "";
6682
7119
  let lastTime = 0;
@@ -6711,7 +7148,7 @@ function YaContainer({
6711
7148
  return () => cancelAnimationFrame(rafId);
6712
7149
  }, [isSelected, fieldId, mode]);
6713
7150
  if (mode === "read-only") {
6714
- return /* @__PURE__ */ jsx17(
7151
+ return /* @__PURE__ */ jsx18(
6715
7152
  Tag,
6716
7153
  {
6717
7154
  className: `ya-container ${className || ""}`,
@@ -6754,7 +7191,7 @@ function YaContainer({
6754
7191
  onDrop: handleDrop,
6755
7192
  children: [
6756
7193
  children,
6757
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx17(
7194
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx18(
6758
7195
  Toolbar,
6759
7196
  {
6760
7197
  containerRef,
@@ -6771,10 +7208,10 @@ function YaContainer({
6771
7208
  }
6772
7209
 
6773
7210
  // src/components/StaticText.tsx
6774
- import { jsx as jsx18 } from "react/jsx-runtime";
7211
+ import { jsx as jsx19 } from "react/jsx-runtime";
6775
7212
  function MpText({ fieldId, className, as: Component = "span", children }) {
6776
7213
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
6777
- return /* @__PURE__ */ jsx18(
7214
+ return /* @__PURE__ */ jsx19(
6778
7215
  Component,
6779
7216
  {
6780
7217
  className,
@@ -6785,7 +7222,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
6785
7222
  }
6786
7223
 
6787
7224
  // src/components/StaticImage.tsx
6788
- import { jsx as jsx19 } from "react/jsx-runtime";
7225
+ import { jsx as jsx20 } from "react/jsx-runtime";
6789
7226
  function parseImageValue2(value) {
6790
7227
  if (!value) {
6791
7228
  return { src: "" };
@@ -6821,7 +7258,7 @@ function MpImage({
6821
7258
  const altText = imageData.alt || alt || fallbackAlt || "";
6822
7259
  const objectFit = imageData.objectFit || propObjectFit || "cover";
6823
7260
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
6824
- return /* @__PURE__ */ jsx19(
7261
+ return /* @__PURE__ */ jsx20(
6825
7262
  "img",
6826
7263
  {
6827
7264
  src: resolveAssetUrl(src),
@@ -6839,7 +7276,7 @@ function MpImage({
6839
7276
 
6840
7277
  // src/components/MarkdownText.tsx
6841
7278
  import { Fragment as Fragment6 } from "react";
6842
- import { jsx as jsx20 } from "react/jsx-runtime";
7279
+ import { jsx as jsx21 } from "react/jsx-runtime";
6843
7280
  function tokenize(text2) {
6844
7281
  const tokens = [];
6845
7282
  let remaining = text2;
@@ -6901,13 +7338,13 @@ function tokensToElements(tokens) {
6901
7338
  return tokens.map((token, index) => {
6902
7339
  switch (token.type) {
6903
7340
  case "text":
6904
- return /* @__PURE__ */ jsx20(Fragment6, { children: token.content }, index);
7341
+ return /* @__PURE__ */ jsx21(Fragment6, { children: token.content }, index);
6905
7342
  case "bold":
6906
- return /* @__PURE__ */ jsx20("strong", { children: token.content }, index);
7343
+ return /* @__PURE__ */ jsx21("strong", { children: token.content }, index);
6907
7344
  case "italic":
6908
- return /* @__PURE__ */ jsx20("em", { children: token.content }, index);
7345
+ return /* @__PURE__ */ jsx21("em", { children: token.content }, index);
6909
7346
  case "link":
6910
- return /* @__PURE__ */ jsx20(
7347
+ return /* @__PURE__ */ jsx21(
6911
7348
  "a",
6912
7349
  {
6913
7350
  href: token.url,
@@ -6919,7 +7356,7 @@ function tokensToElements(tokens) {
6919
7356
  index
6920
7357
  );
6921
7358
  case "newline":
6922
- return /* @__PURE__ */ jsx20("br", {}, index);
7359
+ return /* @__PURE__ */ jsx21("br", {}, index);
6923
7360
  default:
6924
7361
  return null;
6925
7362
  }
@@ -6931,15 +7368,480 @@ function parseMarkdownToElements(content) {
6931
7368
  }
6932
7369
  function MarkdownText({ content, className }) {
6933
7370
  const elements = parseMarkdownToElements(content);
6934
- return /* @__PURE__ */ jsx20("span", { className, children: elements });
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
+ );
6935
7837
  }
6936
7838
 
6937
7839
  // src/router/Link.tsx
6938
7840
  import { Link as WouterLink2 } from "wouter";
6939
- import { jsx as jsx21 } from "react/jsx-runtime";
7841
+ import { jsx as jsx24 } from "react/jsx-runtime";
6940
7842
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
6941
7843
  const target = href ?? to ?? "/";
6942
- return /* @__PURE__ */ jsx21(WouterLink2, { href: target, className, onClick, replace, ...props, children });
7844
+ return /* @__PURE__ */ jsx24(WouterLink2, { href: target, className, onClick, replace, ...props, children });
6943
7845
  }
6944
7846
 
6945
7847
  // src/router/useNavigate.ts
@@ -6958,7 +7860,7 @@ function useNavigate() {
6958
7860
 
6959
7861
  // src/router/Router.tsx
6960
7862
  import { Router as WouterRouter } from "wouter";
6961
- import { jsx as jsx22 } from "react/jsx-runtime";
7863
+ import { jsx as jsx25 } from "react/jsx-runtime";
6962
7864
  function detectBasename() {
6963
7865
  if (typeof window === "undefined") return "";
6964
7866
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -6973,11 +7875,11 @@ function detectBasename() {
6973
7875
  }
6974
7876
  function Router({ children, base }) {
6975
7877
  const basename = base ?? detectBasename();
6976
- return /* @__PURE__ */ jsx22(WouterRouter, { base: basename, children });
7878
+ return /* @__PURE__ */ jsx25(WouterRouter, { base: basename, children });
6977
7879
  }
6978
7880
 
6979
7881
  // src/router/ScrollRestoration.tsx
6980
- import { useEffect as useEffect18, useRef as useRef19 } from "react";
7882
+ import { useEffect as useEffect20, useRef as useRef21 } from "react";
6981
7883
  import { useLocation as useLocation3 } from "wouter";
6982
7884
  var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
6983
7885
  var HISTORY_INDEX_KEY = "yoamigo-history-index";
@@ -7013,10 +7915,10 @@ function setHistoryIndex(index) {
7013
7915
  var globalHistoryIndex = 0;
7014
7916
  function ScrollRestoration() {
7015
7917
  const [location] = useLocation3();
7016
- const previousLocation = useRef19(location);
7017
- const isPopState = useRef19(false);
7018
- const scrollPositionsRef = useRef19({});
7019
- useEffect18(() => {
7918
+ const previousLocation = useRef21(location);
7919
+ const isPopState = useRef21(false);
7920
+ const scrollPositionsRef = useRef21({});
7921
+ useEffect20(() => {
7020
7922
  if (typeof history !== "undefined" && "scrollRestoration" in history) {
7021
7923
  history.scrollRestoration = "manual";
7022
7924
  }
@@ -7034,7 +7936,7 @@ function ScrollRestoration() {
7034
7936
  window.addEventListener("popstate", handlePopState);
7035
7937
  return () => window.removeEventListener("popstate", handlePopState);
7036
7938
  }, []);
7037
- useEffect18(() => {
7939
+ useEffect20(() => {
7038
7940
  if (previousLocation.current === location) return;
7039
7941
  const prevHistoryIndex = globalHistoryIndex;
7040
7942
  const currentScrollY = window.scrollY;
@@ -7054,7 +7956,7 @@ function ScrollRestoration() {
7054
7956
  }
7055
7957
  previousLocation.current = location;
7056
7958
  }, [location]);
7057
- useEffect18(() => {
7959
+ useEffect20(() => {
7058
7960
  let timeoutId;
7059
7961
  const handleScroll = () => {
7060
7962
  clearTimeout(timeoutId);
@@ -7073,7 +7975,74 @@ function ScrollRestoration() {
7073
7975
  }
7074
7976
 
7075
7977
  // src/router/index.ts
7076
- 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
+ }
7077
8046
 
7078
8047
  // src/lib/content-helpers.ts
7079
8048
  function text(content) {
@@ -7091,8 +8060,952 @@ function video(config) {
7091
8060
  function embed(config) {
7092
8061
  return JSON.stringify(config);
7093
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
+ }
7094
9000
  export {
7095
9001
  AIEditProvider,
9002
+ CartProvider,
9003
+ CollectionClient,
9004
+ CollectionContentProvider,
9005
+ CollectionDetailPage,
9006
+ CollectionItem,
9007
+ CollectionList,
9008
+ CollectionListPage,
7096
9009
  ContentStoreProvider,
7097
9010
  ContentStoreProvider2 as ContentStoreProviderProd,
7098
9011
  Link2 as Link,
@@ -7115,12 +9028,21 @@ export {
7115
9028
  background,
7116
9029
  buildIntermediateText,
7117
9030
  calculateAnimationTiming,
9031
+ clearSessionId,
7118
9032
  computeTextDiff,
7119
9033
  containsHtml,
7120
9034
  contentRegistry,
9035
+ createRouteDefinition,
7121
9036
  embed,
9037
+ extractRouteParams,
9038
+ filePathToRoutePath,
9039
+ generatePath,
7122
9040
  getAllContent,
9041
+ getCollectionClient,
7123
9042
  getContent,
9043
+ getLocalCartItemCount,
9044
+ getLocalCartItems,
9045
+ getSessionId,
7124
9046
  getTextCursorPosition,
7125
9047
  hasContent,
7126
9048
  image,
@@ -7129,13 +9051,17 @@ export {
7129
9051
  linkTransitionStrategy,
7130
9052
  parseBackgroundConfig,
7131
9053
  parseEmbedUrl,
9054
+ parseFieldValue,
7132
9055
  registerContent,
9056
+ resetCollectionClient,
7133
9057
  resolveAssetUrl,
7134
9058
  serializeBackgroundConfig,
7135
9059
  serializeEmbedValue,
7136
9060
  serializeImageValue,
7137
9061
  serializeVideoValue,
7138
9062
  setAssetResolver,
9063
+ sortRoutesBySpecificity,
9064
+ stringifyFieldValue,
7139
9065
  stripHtml,
7140
9066
  text,
7141
9067
  textTypingStrategy,
@@ -7143,10 +9069,26 @@ export {
7143
9069
  useAIEditContext,
7144
9070
  useAIEditContextOptional,
7145
9071
  useAnimatedText,
9072
+ useCart,
9073
+ useCartContext,
9074
+ useCheckout,
9075
+ useCheckoutStatus,
9076
+ useCollectionContent,
9077
+ useCollectionList,
9078
+ useCollectionRecord,
9079
+ useContent,
7146
9080
  useContentStore,
7147
9081
  useContentStore2 as useContentStoreProd,
9082
+ useCustomerPortal,
9083
+ useLocation4 as useLocation,
7148
9084
  useNavigate,
7149
- useParams,
9085
+ useOptionalCartContext,
9086
+ useParams2 as useParams,
9087
+ useProduct,
9088
+ useProducts,
7150
9089
  useSafeTriangle,
9090
+ useSubscription,
9091
+ useSubscriptionStatus,
9092
+ useSubscriptionTiers,
7151
9093
  video
7152
9094
  };