@yoamigo.com/core 0.2.2 → 0.3.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
@@ -779,6 +779,7 @@ function ContentStoreProvider({
779
779
  );
780
780
  const [mode, setModeState] = useState(defaultMode);
781
781
  const [listeners, setListeners] = useState(/* @__PURE__ */ new Set());
782
+ const [changeSourceMap, setChangeSourceMap] = useState({});
782
783
  const [activeFieldId, setActiveFieldId] = useState(null);
783
784
  useEffect(() => {
784
785
  const handleContentUpdate = () => {
@@ -807,16 +808,21 @@ function ContentStoreProvider({
807
808
  [content]
808
809
  );
809
810
  const setValue = useCallback(
810
- (fieldId, value2) => {
811
+ (fieldId, value2, source = "ai") => {
811
812
  setContent((prev) => {
812
813
  const next = new Map(prev);
813
814
  next.set(fieldId, value2);
814
815
  return next;
815
816
  });
817
+ setChangeSourceMap((prev) => ({ ...prev, [fieldId]: source }));
816
818
  notifyListeners();
817
819
  },
818
820
  [notifyListeners]
819
821
  );
822
+ const getChangeSource = useCallback(
823
+ (fieldId) => changeSourceMap[fieldId] || "initial",
824
+ [changeSourceMap]
825
+ );
820
826
  const setMode = useCallback(
821
827
  (newMode) => {
822
828
  setModeState(newMode);
@@ -904,6 +910,7 @@ function ContentStoreProvider({
904
910
  window.mpContentStore = {
905
911
  getValue,
906
912
  setValue,
913
+ getChangeSource,
907
914
  getMode: () => mode,
908
915
  setMode,
909
916
  subscribe,
@@ -912,11 +919,12 @@ function ContentStoreProvider({
912
919
  return () => {
913
920
  delete window.mpContentStore;
914
921
  };
915
- }, [getValue, setValue, mode, setMode, subscribe, saveToWorker]);
922
+ }, [getValue, setValue, getChangeSource, mode, setMode, subscribe, saveToWorker]);
916
923
  const getPages = useCallback(() => pages, [pages]);
917
924
  const value = {
918
925
  getValue,
919
926
  setValue,
927
+ getChangeSource,
920
928
  mode,
921
929
  setMode,
922
930
  subscribe,
@@ -956,10 +964,60 @@ function ContentStoreProvider2({ children }) {
956
964
  }
957
965
 
958
966
  // src/components/YaText.tsx
959
- import { useEffect as useEffect4, useRef as useRef5, useState as useState4, useCallback as useCallback5 } from "react";
960
- import { createPortal as createPortal2 } from "react-dom";
967
+ import { useEffect as useEffect6, useRef as useRef6, useState as useState5, useCallback as useCallback7 } from "react";
968
+ import { createPortal as createPortal3 } from "react-dom";
961
969
  import { useEditor, EditorContent } from "@tiptap/react";
962
- import { BubbleMenu } from "@tiptap/react/menus";
970
+
971
+ // src/components/ControlledBubbleMenu.tsx
972
+ import { useFloating, autoUpdate, offset, flip, shift } from "@floating-ui/react";
973
+ import { isNodeSelection, posToDOMRect } from "@tiptap/core";
974
+ import { useLayoutEffect } from "react";
975
+ import { createPortal } from "react-dom";
976
+ import { jsx as jsx3 } from "react/jsx-runtime";
977
+ function ControlledBubbleMenu({ editor, open, children, className }) {
978
+ const { floatingStyles, refs, isPositioned } = useFloating({
979
+ open,
980
+ // Required for isPositioned to work
981
+ strategy: "fixed",
982
+ whileElementsMounted: autoUpdate,
983
+ placement: "top",
984
+ middleware: [
985
+ offset({ mainAxis: 8 }),
986
+ flip({
987
+ padding: 8,
988
+ fallbackPlacements: ["bottom", "top-start", "bottom-start", "top-end", "bottom-end"]
989
+ }),
990
+ shift({ padding: 8 })
991
+ ]
992
+ });
993
+ useLayoutEffect(() => {
994
+ if (!open) return;
995
+ const { ranges } = editor.state.selection;
996
+ const from = Math.min(...ranges.map((range) => range.$from.pos));
997
+ const to = Math.max(...ranges.map((range) => range.$to.pos));
998
+ refs.setReference({
999
+ getBoundingClientRect() {
1000
+ if (isNodeSelection(editor.state.selection)) {
1001
+ const node = editor.view.nodeDOM(from);
1002
+ if (node) return node.getBoundingClientRect();
1003
+ }
1004
+ return posToDOMRect(editor.view, from, to);
1005
+ }
1006
+ });
1007
+ }, [refs, editor.view, editor.state.selection, open]);
1008
+ if (!open) return null;
1009
+ const style = {
1010
+ ...floatingStyles,
1011
+ opacity: isPositioned ? 1 : 0,
1012
+ transition: "opacity 0.15s ease"
1013
+ };
1014
+ return createPortal(
1015
+ /* @__PURE__ */ jsx3("div", { ref: refs.setFloating, style, className, children }),
1016
+ document.body
1017
+ );
1018
+ }
1019
+
1020
+ // src/components/YaText.tsx
963
1021
  import StarterKit from "@tiptap/starter-kit";
964
1022
  import Link from "@tiptap/extension-link";
965
1023
  import { TextStyle } from "@tiptap/extension-text-style";
@@ -967,9 +1025,9 @@ import { Extension } from "@tiptap/core";
967
1025
 
968
1026
  // src/components/SafeHtml.tsx
969
1027
  import { useEffect as useEffect2, useRef as useRef2, useState as useState2, useCallback as useCallback2 } from "react";
970
- import { createPortal } from "react-dom";
1028
+ import { createPortal as createPortal2 } from "react-dom";
971
1029
  import DOMPurify from "dompurify";
972
- import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
1030
+ import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
973
1031
  var ALLOWED_TAGS = ["strong", "em", "a", "span", "br", "b", "i", "u"];
974
1032
  var ALLOWED_ATTR = ["href", "style", "class", "target", "rel"];
975
1033
  DOMPurify.addHook("uponSanitizeAttribute", (_node, data) => {
@@ -1015,7 +1073,9 @@ function LinkIcon() {
1015
1073
  return /* @__PURE__ */ jsxs(
1016
1074
  "svg",
1017
1075
  {
1018
- className: "mp-link-popover-icon",
1076
+ className: "ya-link-popover-icon",
1077
+ width: "14",
1078
+ height: "14",
1019
1079
  viewBox: "0 0 24 24",
1020
1080
  fill: "none",
1021
1081
  stroke: "currentColor",
@@ -1023,8 +1083,8 @@ function LinkIcon() {
1023
1083
  strokeLinecap: "round",
1024
1084
  strokeLinejoin: "round",
1025
1085
  children: [
1026
- /* @__PURE__ */ jsx3("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
1027
- /* @__PURE__ */ jsx3("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
1086
+ /* @__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" }),
1087
+ /* @__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" })
1028
1088
  ]
1029
1089
  }
1030
1090
  );
@@ -1039,7 +1099,7 @@ function LinkPopover({
1039
1099
  return /* @__PURE__ */ jsxs(
1040
1100
  "div",
1041
1101
  {
1042
- className: "mp-link-popover",
1102
+ className: "ya-link-popover",
1043
1103
  style: {
1044
1104
  top: position.top,
1045
1105
  left: position.left
@@ -1056,10 +1116,10 @@ function LinkPopover({
1056
1116
  }
1057
1117
  },
1058
1118
  children: [
1059
- /* @__PURE__ */ jsx3(LinkIcon, {}),
1060
- /* @__PURE__ */ jsxs("span", { className: "mp-link-popover-text", children: [
1061
- /* @__PURE__ */ jsx3("span", { className: "mp-link-popover-prefix", children: "Go to " }),
1062
- /* @__PURE__ */ jsx3("span", { className: "mp-link-popover-name", children: displayText })
1119
+ /* @__PURE__ */ jsx4(LinkIcon, {}),
1120
+ /* @__PURE__ */ jsxs("span", { className: "ya-link-popover-text", children: [
1121
+ /* @__PURE__ */ jsx4("span", { className: "ya-link-popover-prefix", children: "Go to " }),
1122
+ /* @__PURE__ */ jsx4("span", { className: "ya-link-popover-name", children: displayText })
1063
1123
  ] })
1064
1124
  ]
1065
1125
  }
@@ -1159,7 +1219,7 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1159
1219
  };
1160
1220
  }, [mode, scheduleHide]);
1161
1221
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1162
- /* @__PURE__ */ jsx3(
1222
+ /* @__PURE__ */ jsx4(
1163
1223
  "span",
1164
1224
  {
1165
1225
  ref: containerRef,
@@ -1167,8 +1227,8 @@ function SafeHtml({ content, className, mode = "read-only" }) {
1167
1227
  dangerouslySetInnerHTML: { __html: sanitized }
1168
1228
  }
1169
1229
  ),
1170
- mode === "inline-edit" && popoverState.isVisible && createPortal(
1171
- /* @__PURE__ */ jsx3(
1230
+ mode === "inline-edit" && popoverState.isVisible && createPortal2(
1231
+ /* @__PURE__ */ jsx4(
1172
1232
  LinkPopover,
1173
1233
  {
1174
1234
  displayText: popoverState.displayText,
@@ -1191,7 +1251,7 @@ import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useC
1191
1251
 
1192
1252
  // src/contexts/AIEditContext.tsx
1193
1253
  import { createContext as createContext3, useContext as useContext3, useCallback as useCallback3, useRef as useRef3, useMemo } from "react";
1194
- import { jsx as jsx4 } from "react/jsx-runtime";
1254
+ import { jsx as jsx5 } from "react/jsx-runtime";
1195
1255
  var AIEditContext = createContext3(null);
1196
1256
  function useAIEditContext() {
1197
1257
  const context = useContext3(AIEditContext);
@@ -1313,13 +1373,14 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
1313
1373
  }),
1314
1374
  [queueAnimation, cancelAnimation, isAnimating, getAnimationState, subscribe, completeAnimation]
1315
1375
  );
1316
- return /* @__PURE__ */ jsx4(AIEditContext.Provider, { value, children });
1376
+ return /* @__PURE__ */ jsx5(AIEditContext.Provider, { value, children });
1317
1377
  }
1318
1378
 
1319
1379
  // src/hooks/useAIEditAnimation.ts
1320
1380
  function useAIEditAnimation(fieldId, value, options) {
1321
1381
  const { enabled = true, strategy, maxDuration = 2e3, onStart, onComplete } = options;
1322
1382
  const context = useAIEditContextOptional();
1383
+ const { getChangeSource } = useContentStore();
1323
1384
  const previousValueRef = useRef4(value);
1324
1385
  const isFirstRender = useRef4(true);
1325
1386
  const [phase, setPhase] = useState3("idle");
@@ -1374,6 +1435,16 @@ function useAIEditAnimation(fieldId, value, options) {
1374
1435
  previousValueRef.current = value;
1375
1436
  return;
1376
1437
  }
1438
+ const source = getChangeSource(fieldId);
1439
+ if (source === "user") {
1440
+ setDisplayValue(value);
1441
+ previousValueRef.current = value;
1442
+ setPhase("complete");
1443
+ setTimeout(() => {
1444
+ setPhase("idle");
1445
+ }, 400);
1446
+ return;
1447
+ }
1377
1448
  const oldValue = previousValueRef.current;
1378
1449
  const newValue = value;
1379
1450
  if (!strategy.canAnimate(oldValue, newValue)) {
@@ -1402,7 +1473,7 @@ function useAIEditAnimation(fieldId, value, options) {
1402
1473
  cancelAnimationFrame(animationFrameRef.current);
1403
1474
  }
1404
1475
  };
1405
- }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation]);
1476
+ }, [value, enabled, strategy, context, fieldId, maxDuration, onStart, runAnimation, getChangeSource]);
1406
1477
  useEffect3(() => {
1407
1478
  return () => {
1408
1479
  if (animationFrameRef.current !== null) {
@@ -1418,7 +1489,8 @@ function useAIEditAnimation(fieldId, value, options) {
1418
1489
  [phase]
1419
1490
  );
1420
1491
  return {
1421
- displayValue,
1492
+ // When idle, return current value directly to avoid flash of stale state
1493
+ displayValue: phase === "idle" ? value : displayValue,
1422
1494
  isAnimating: phase === "animating",
1423
1495
  phase,
1424
1496
  progress,
@@ -1700,6 +1772,373 @@ function useAnimatedText(fieldId, content, options = {}) {
1700
1772
  };
1701
1773
  }
1702
1774
 
1775
+ // src/components/BubbleIcons.tsx
1776
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
1777
+ function BoldIcon({ size = 16, className }) {
1778
+ return /* @__PURE__ */ jsxs2(
1779
+ "svg",
1780
+ {
1781
+ width: size,
1782
+ height: size,
1783
+ viewBox: "0 0 24 24",
1784
+ fill: "none",
1785
+ stroke: "currentColor",
1786
+ strokeWidth: "2.5",
1787
+ strokeLinecap: "round",
1788
+ strokeLinejoin: "round",
1789
+ className,
1790
+ children: [
1791
+ /* @__PURE__ */ jsx6("path", { d: "M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" }),
1792
+ /* @__PURE__ */ jsx6("path", { d: "M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z" })
1793
+ ]
1794
+ }
1795
+ );
1796
+ }
1797
+ function ItalicIcon({ size = 16, className }) {
1798
+ return /* @__PURE__ */ jsxs2(
1799
+ "svg",
1800
+ {
1801
+ width: size,
1802
+ height: size,
1803
+ viewBox: "0 0 24 24",
1804
+ fill: "none",
1805
+ stroke: "currentColor",
1806
+ strokeWidth: "2",
1807
+ strokeLinecap: "round",
1808
+ strokeLinejoin: "round",
1809
+ className,
1810
+ children: [
1811
+ /* @__PURE__ */ jsx6("line", { x1: "19", y1: "4", x2: "10", y2: "4" }),
1812
+ /* @__PURE__ */ jsx6("line", { x1: "14", y1: "20", x2: "5", y2: "20" }),
1813
+ /* @__PURE__ */ jsx6("line", { x1: "15", y1: "4", x2: "9", y2: "20" })
1814
+ ]
1815
+ }
1816
+ );
1817
+ }
1818
+ function LinkIcon2({ size = 16, className }) {
1819
+ return /* @__PURE__ */ jsxs2(
1820
+ "svg",
1821
+ {
1822
+ width: size,
1823
+ height: size,
1824
+ viewBox: "0 0 24 24",
1825
+ fill: "none",
1826
+ stroke: "currentColor",
1827
+ strokeWidth: "2",
1828
+ strokeLinecap: "round",
1829
+ strokeLinejoin: "round",
1830
+ className,
1831
+ children: [
1832
+ /* @__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" }),
1833
+ /* @__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" })
1834
+ ]
1835
+ }
1836
+ );
1837
+ }
1838
+ function ChevronDownIcon({ size = 12, className }) {
1839
+ return /* @__PURE__ */ jsx6(
1840
+ "svg",
1841
+ {
1842
+ width: size,
1843
+ height: size,
1844
+ viewBox: "0 0 24 24",
1845
+ fill: "none",
1846
+ stroke: "currentColor",
1847
+ strokeWidth: "2",
1848
+ strokeLinecap: "round",
1849
+ strokeLinejoin: "round",
1850
+ className,
1851
+ children: /* @__PURE__ */ jsx6("polyline", { points: "6 9 12 15 18 9" })
1852
+ }
1853
+ );
1854
+ }
1855
+
1856
+ // src/components/BubbleDropdown.tsx
1857
+ import { useEffect as useEffect4 } from "react";
1858
+ import { useFloating as useFloating2, autoUpdate as autoUpdate2, offset as offset2, flip as flip2, shift as shift2, useClick, useDismiss, useInteractions, FloatingPortal } from "@floating-ui/react";
1859
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
1860
+ function BubbleDropdown({
1861
+ label,
1862
+ open,
1863
+ onOpenChange,
1864
+ children,
1865
+ triggerClassName = "",
1866
+ panelClassName = ""
1867
+ }) {
1868
+ const { refs, floatingStyles, context, isPositioned } = useFloating2({
1869
+ open,
1870
+ onOpenChange,
1871
+ placement: "bottom-start",
1872
+ strategy: "fixed",
1873
+ whileElementsMounted: autoUpdate2,
1874
+ middleware: [
1875
+ offset2({ mainAxis: 4 }),
1876
+ flip2({
1877
+ padding: 8,
1878
+ fallbackPlacements: ["bottom-end", "top-start", "top-end"]
1879
+ }),
1880
+ shift2({ padding: 8 })
1881
+ ]
1882
+ });
1883
+ const click = useClick(context);
1884
+ const dismiss = useDismiss(context, {
1885
+ // Don't dismiss on ancestor scroll - we're inside a portaled bubble menu
1886
+ ancestorScroll: false
1887
+ });
1888
+ const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
1889
+ useEffect4(() => {
1890
+ if (!open) return;
1891
+ const handleKeyDown = (e) => {
1892
+ if (e.key === "Escape") {
1893
+ e.preventDefault();
1894
+ e.stopPropagation();
1895
+ onOpenChange(false);
1896
+ }
1897
+ };
1898
+ document.addEventListener("keydown", handleKeyDown);
1899
+ return () => document.removeEventListener("keydown", handleKeyDown);
1900
+ }, [open, onOpenChange]);
1901
+ const panelStyle = {
1902
+ ...floatingStyles,
1903
+ opacity: isPositioned ? 1 : 0,
1904
+ transition: "opacity 0.15s ease"
1905
+ };
1906
+ const handleTriggerClick = (e) => {
1907
+ e.stopPropagation();
1908
+ };
1909
+ const handleTriggerMouseDown = (e) => {
1910
+ e.preventDefault();
1911
+ e.stopPropagation();
1912
+ };
1913
+ const handlePanelClick = (e) => {
1914
+ e.stopPropagation();
1915
+ };
1916
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1917
+ /* @__PURE__ */ jsxs3(
1918
+ "button",
1919
+ {
1920
+ ref: refs.setReference,
1921
+ type: "button",
1922
+ className: `ya-bubble-dropdown-trigger ${open ? "is-open" : ""} ${triggerClassName}`,
1923
+ ...getReferenceProps({
1924
+ onClick: handleTriggerClick,
1925
+ onMouseDown: handleTriggerMouseDown
1926
+ }),
1927
+ children: [
1928
+ /* @__PURE__ */ jsx7("span", { className: "ya-bubble-dropdown-label", children: label }),
1929
+ /* @__PURE__ */ jsx7(ChevronDownIcon, { size: 10, className: `ya-bubble-dropdown-arrow ${open ? "is-open" : ""}` })
1930
+ ]
1931
+ }
1932
+ ),
1933
+ open && /* @__PURE__ */ jsx7(FloatingPortal, { children: /* @__PURE__ */ jsx7(
1934
+ "div",
1935
+ {
1936
+ ref: refs.setFloating,
1937
+ style: panelStyle,
1938
+ className: `ya-bubble-dropdown-panel ${panelClassName}`,
1939
+ ...getFloatingProps({
1940
+ onClick: handlePanelClick
1941
+ }),
1942
+ children
1943
+ }
1944
+ ) })
1945
+ ] });
1946
+ }
1947
+
1948
+ // src/components/FontSizePicker.tsx
1949
+ import { useState as useState4, useEffect as useEffect5, useCallback as useCallback5, useRef as useRef5 } from "react";
1950
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1951
+ var SIZE_PRESETS = [
1952
+ { name: "S", value: "0.875rem" },
1953
+ { name: "M", value: "1rem" },
1954
+ { name: "L", value: "1.25rem" },
1955
+ { name: "XL", value: "1.5rem" }
1956
+ ];
1957
+ var UNIT_COMPLETIONS = {
1958
+ r: "rem",
1959
+ re: "rem",
1960
+ rem: "rem",
1961
+ p: "px",
1962
+ px: "px",
1963
+ e: "em",
1964
+ em: "em",
1965
+ v: "vw",
1966
+ vw: "vw",
1967
+ vh: "vh"
1968
+ };
1969
+ function getPresetName(value) {
1970
+ const preset = SIZE_PRESETS.find((p) => p.value === value);
1971
+ return preset?.name ?? null;
1972
+ }
1973
+ function getFontSizeLabel(value) {
1974
+ if (!value) return "Size";
1975
+ const presetName = getPresetName(value);
1976
+ if (presetName) return presetName;
1977
+ return value;
1978
+ }
1979
+ function parseValue(value) {
1980
+ const match = value.match(/^([\d.]+)(rem|px|em|%|vw|vh)?$/);
1981
+ if (!match) return null;
1982
+ const num = parseFloat(match[1]);
1983
+ const unit = match[2] || "rem";
1984
+ return { num, unit };
1985
+ }
1986
+ function autocompleteUnit(input) {
1987
+ const match = input.match(/^([\d.]+)([a-z]*)$/);
1988
+ if (!match) return null;
1989
+ const [, num, partialUnit] = match;
1990
+ if (!partialUnit) return null;
1991
+ const fullUnit = UNIT_COMPLETIONS[partialUnit.toLowerCase()];
1992
+ if (fullUnit && fullUnit !== partialUnit) {
1993
+ return `${num}${fullUnit}`;
1994
+ }
1995
+ return null;
1996
+ }
1997
+ function normalizeValue(input) {
1998
+ if (!input.trim()) return null;
1999
+ const match = input.match(/^([\d.]+)(rem|px|em|%|vw|vh|pt|cm|mm|in)?$/);
2000
+ if (!match) return null;
2001
+ const num = match[1];
2002
+ const unit = match[2] || "rem";
2003
+ if (isNaN(parseFloat(num))) return null;
2004
+ return `${num}${unit}`;
2005
+ }
2006
+ function FontSizePicker({ value, onChange, onClose }) {
2007
+ const [inputValue, setInputValue] = useState4(value || "");
2008
+ const inputRef = useRef5(null);
2009
+ useEffect5(() => {
2010
+ inputRef.current?.focus();
2011
+ inputRef.current?.select();
2012
+ }, []);
2013
+ useEffect5(() => {
2014
+ setInputValue(value || "");
2015
+ }, [value]);
2016
+ const handlePresetClick = useCallback5((e, presetValue) => {
2017
+ e.stopPropagation();
2018
+ onChange(presetValue);
2019
+ onClose();
2020
+ }, [onChange, onClose]);
2021
+ const handlePresetMouseDown = useCallback5((e) => {
2022
+ e.preventDefault();
2023
+ e.stopPropagation();
2024
+ }, []);
2025
+ const handleInputChange = useCallback5((e) => {
2026
+ setInputValue(e.target.value);
2027
+ }, []);
2028
+ const handleInputKeyDown = useCallback5((e) => {
2029
+ if (e.key === "ArrowUp" || e.key === "ArrowDown") {
2030
+ e.preventDefault();
2031
+ e.stopPropagation();
2032
+ let step = 0.1;
2033
+ if (e.shiftKey) step = 0.01;
2034
+ if (e.ctrlKey || e.metaKey) step = 1;
2035
+ const direction = e.key === "ArrowUp" ? 1 : -1;
2036
+ const parsed = parseValue(inputValue || value || "1rem");
2037
+ if (!parsed) return;
2038
+ const newNum = Math.max(0, parsed.num + step * direction);
2039
+ const formatted = `${Number(newNum.toFixed(2))}${parsed.unit}`;
2040
+ setInputValue(formatted);
2041
+ onChange(formatted);
2042
+ setTimeout(() => inputRef.current?.focus(), 0);
2043
+ return;
2044
+ }
2045
+ if (e.key === "Tab") {
2046
+ const completed = autocompleteUnit(inputValue);
2047
+ if (completed) {
2048
+ e.preventDefault();
2049
+ setInputValue(completed);
2050
+ onChange(completed);
2051
+ }
2052
+ return;
2053
+ }
2054
+ if (e.key === "Enter") {
2055
+ e.preventDefault();
2056
+ const completed = autocompleteUnit(inputValue) || normalizeValue(inputValue);
2057
+ if (completed) {
2058
+ onChange(completed);
2059
+ }
2060
+ onClose();
2061
+ return;
2062
+ }
2063
+ if (e.key === "Escape") {
2064
+ e.preventDefault();
2065
+ onClose();
2066
+ }
2067
+ }, [inputValue, value, onChange, onClose]);
2068
+ const activePreset = getPresetName(value);
2069
+ return /* @__PURE__ */ jsxs4("div", { className: "ya-font-size-picker", children: [
2070
+ /* @__PURE__ */ jsx8("div", { className: "ya-size-presets", children: SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs4(
2071
+ "button",
2072
+ {
2073
+ type: "button",
2074
+ className: `ya-size-preset-btn ${activePreset === preset.name ? "is-active" : ""}`,
2075
+ onClick: (e) => handlePresetClick(e, preset.value),
2076
+ onMouseDown: handlePresetMouseDown,
2077
+ children: [
2078
+ /* @__PURE__ */ jsx8("span", { className: "ya-size-preset-name", children: preset.name }),
2079
+ /* @__PURE__ */ jsx8("span", { className: "ya-size-preset-value", children: preset.value })
2080
+ ]
2081
+ },
2082
+ preset.name
2083
+ )) }),
2084
+ /* @__PURE__ */ jsx8("div", { className: "ya-size-combobox", children: /* @__PURE__ */ jsx8(
2085
+ "input",
2086
+ {
2087
+ ref: inputRef,
2088
+ type: "text",
2089
+ value: inputValue,
2090
+ onChange: handleInputChange,
2091
+ onKeyDown: handleInputKeyDown,
2092
+ onClick: (e) => e.stopPropagation(),
2093
+ onMouseDown: (e) => e.stopPropagation(),
2094
+ className: "ya-size-input",
2095
+ placeholder: "1rem",
2096
+ autoComplete: "off",
2097
+ spellCheck: false
2098
+ }
2099
+ ) })
2100
+ ] });
2101
+ }
2102
+
2103
+ // src/components/FontWeightPicker.tsx
2104
+ import { useCallback as useCallback6 } from "react";
2105
+ import { jsx as jsx9 } from "react/jsx-runtime";
2106
+ var WEIGHT_PRESETS = [
2107
+ { name: "Regular", value: "400" },
2108
+ { name: "Semi-bold", value: "600" },
2109
+ { name: "Bold", value: "700" },
2110
+ { name: "Extra-bold", value: "800" }
2111
+ ];
2112
+ function getFontWeightLabel(value) {
2113
+ if (!value) return "Weight";
2114
+ const preset = WEIGHT_PRESETS.find((p) => p.value === value);
2115
+ if (preset) return preset.name;
2116
+ return value;
2117
+ }
2118
+ function FontWeightPicker({ value, onChange, onClose }) {
2119
+ const handleClick = useCallback6((e, weightValue) => {
2120
+ e.stopPropagation();
2121
+ onChange(weightValue);
2122
+ onClose();
2123
+ }, [onChange, onClose]);
2124
+ const handleMouseDown = useCallback6((e) => {
2125
+ e.preventDefault();
2126
+ e.stopPropagation();
2127
+ }, []);
2128
+ return /* @__PURE__ */ jsx9("div", { className: "ya-font-weight-picker", children: WEIGHT_PRESETS.map((preset) => /* @__PURE__ */ jsx9(
2129
+ "button",
2130
+ {
2131
+ type: "button",
2132
+ className: `ya-weight-option ${value === preset.value ? "is-active" : ""}`,
2133
+ style: { fontWeight: preset.value },
2134
+ onClick: (e) => handleClick(e, preset.value),
2135
+ onMouseDown: handleMouseDown,
2136
+ children: preset.name
2137
+ },
2138
+ preset.value
2139
+ )) });
2140
+ }
2141
+
1703
2142
  // #style-inject:#style-inject
1704
2143
  function styleInject(css, { insertAt } = {}) {
1705
2144
  if (!css || typeof document === "undefined") return;
@@ -1742,6 +2181,16 @@ body.builder-selector-active .ya-text-editable:hover {
1742
2181
  border-radius: 4px;
1743
2182
  position: relative;
1744
2183
  }
2184
+ .ya-text-editing .ProseMirror p::selection,
2185
+ .ya-text-editing .ProseMirror::selection {
2186
+ background-color: rgba(212, 165, 116, 0.4);
2187
+ color: inherit;
2188
+ }
2189
+ .ya-text-editing .ProseMirror p::-moz-selection,
2190
+ .ya-text-editing .ProseMirror::-moz-selection {
2191
+ background-color: rgba(212, 165, 116, 0.4);
2192
+ color: inherit;
2193
+ }
1745
2194
  .ya-bubble-menu {
1746
2195
  display: flex;
1747
2196
  gap: 4px;
@@ -1749,30 +2198,20 @@ body.builder-selector-active .ya-text-editable:hover {
1749
2198
  background: #1a1a1a;
1750
2199
  border-radius: 8px;
1751
2200
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
1752
- animation: ya-bubble-fade-in 0.15s ease;
1753
2201
  font-family:
1754
2202
  system-ui,
1755
2203
  -apple-system,
1756
2204
  BlinkMacSystemFont,
1757
2205
  "Segoe UI",
1758
2206
  sans-serif;
1759
- }
1760
- @keyframes ya-bubble-fade-in {
1761
- from {
1762
- opacity: 0;
1763
- transform: translateY(4px);
1764
- }
1765
- to {
1766
- opacity: 1;
1767
- transform: translateY(0);
1768
- }
2207
+ z-index: 9999;
1769
2208
  }
1770
2209
  .ya-bubble-btn {
1771
2210
  display: flex;
1772
2211
  align-items: center;
1773
2212
  justify-content: center;
1774
- width: 32px;
1775
- height: 32px;
2213
+ width: 36px;
2214
+ height: 36px;
1776
2215
  padding: 0;
1777
2216
  border: none;
1778
2217
  background: transparent;
@@ -1796,7 +2235,7 @@ body.builder-selector-active .ya-text-editable:hover {
1796
2235
  }
1797
2236
  .ya-bubble-divider {
1798
2237
  width: 1px;
1799
- height: 20px;
2238
+ height: 24px;
1800
2239
  background: rgba(255, 255, 255, 0.2);
1801
2240
  margin: 6px 4px;
1802
2241
  }
@@ -1845,6 +2284,14 @@ body.builder-selector-active .ya-text-editable:hover {
1845
2284
  background: rgba(212, 165, 116, 0.3) !important;
1846
2285
  color: inherit !important;
1847
2286
  }
2287
+ body.builder-selector-active .ya-text-editable:not(.ya-text-editing)::selection,
2288
+ body.builder-selector-active .ya-text-editable:not(.ya-text-editing) *::selection {
2289
+ color: inherit;
2290
+ }
2291
+ body.builder-selector-active .ya-text-editable:not(.ya-text-editing)::-moz-selection,
2292
+ body.builder-selector-active .ya-text-editable:not(.ya-text-editing) *::-moz-selection {
2293
+ color: inherit;
2294
+ }
1848
2295
  .ProseMirror p.is-editor-empty:first-child::before {
1849
2296
  content: attr(data-placeholder);
1850
2297
  float: left;
@@ -1855,13 +2302,11 @@ body.builder-selector-active .ya-text-editable:hover {
1855
2302
  .ya-text-actions {
1856
2303
  display: flex;
1857
2304
  gap: 8px;
1858
- position: absolute;
1859
- bottom: -48px;
1860
- right: 0;
1861
- z-index: 10;
1862
- background: rgba(26, 26, 26, 0.8);
2305
+ z-index: 9999;
2306
+ background: rgba(26, 26, 26, 0.95);
1863
2307
  padding: 8px 10px;
1864
2308
  border-radius: 8px;
2309
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
1865
2310
  font-family:
1866
2311
  system-ui,
1867
2312
  -apple-system,
@@ -1870,8 +2315,8 @@ body.builder-selector-active .ya-text-editable:hover {
1870
2315
  sans-serif;
1871
2316
  }
1872
2317
  .ya-text-btn {
1873
- padding: 6px 14px;
1874
- font-size: 12px;
2318
+ padding: 8px 18px;
2319
+ font-size: 14px;
1875
2320
  font-weight: 500;
1876
2321
  border-radius: 6px;
1877
2322
  cursor: pointer;
@@ -1895,59 +2340,135 @@ body.builder-selector-active .ya-text-editable:hover {
1895
2340
  .ya-text-btn-save:hover {
1896
2341
  background: #c4956a;
1897
2342
  }
1898
- .ya-link-popover {
1899
- position: fixed;
1900
- z-index: 9999;
2343
+ .ya-bubble-dropdown-trigger {
1901
2344
  display: flex;
1902
2345
  align-items: center;
1903
2346
  gap: 6px;
1904
- padding: 8px 12px;
1905
- background: #1a1a1a;
2347
+ padding: 6px 10px;
2348
+ background: transparent;
2349
+ border: 1px solid rgba(255, 255, 255, 0.2);
2350
+ border-radius: 6px;
1906
2351
  color: #e0e0e0;
2352
+ font-size: 12px;
2353
+ cursor: pointer;
2354
+ transition: all 0.15s ease;
2355
+ min-width: 70px;
2356
+ }
2357
+ .ya-bubble-dropdown-trigger:hover {
2358
+ border-color: rgba(255, 255, 255, 0.4);
2359
+ background: rgba(255, 255, 255, 0.05);
2360
+ }
2361
+ .ya-bubble-dropdown-trigger.is-open {
2362
+ border-color: var(--color-primary, #D4A574);
2363
+ background: rgba(255, 255, 255, 0.05);
2364
+ }
2365
+ .ya-bubble-dropdown-label {
2366
+ flex: 1;
2367
+ text-align: left;
2368
+ }
2369
+ .ya-bubble-dropdown-arrow {
2370
+ transition: transform 0.15s ease;
2371
+ opacity: 0.7;
2372
+ }
2373
+ .ya-bubble-dropdown-arrow.is-open {
2374
+ transform: rotate(180deg);
2375
+ }
2376
+ .ya-bubble-dropdown-panel {
2377
+ background: #1a1a1a;
1907
2378
  border-radius: 8px;
1908
- font-size: 13px;
2379
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
2380
+ padding: 8px;
2381
+ min-width: 160px;
2382
+ z-index: 10000;
2383
+ font-family:
2384
+ system-ui,
2385
+ -apple-system,
2386
+ BlinkMacSystemFont,
2387
+ "Segoe UI",
2388
+ sans-serif;
2389
+ }
2390
+ .ya-font-size-picker {
2391
+ display: flex;
2392
+ flex-direction: column;
2393
+ gap: 8px;
2394
+ }
2395
+ .ya-size-presets {
2396
+ display: flex;
2397
+ gap: 4px;
2398
+ }
2399
+ .ya-size-preset-btn {
2400
+ flex: 1;
2401
+ display: flex;
2402
+ flex-direction: column;
2403
+ align-items: center;
2404
+ gap: 2px;
2405
+ padding: 6px 8px;
2406
+ background: rgba(255, 255, 255, 0.05);
2407
+ border: 1px solid rgba(255, 255, 255, 0.1);
2408
+ border-radius: 4px;
2409
+ color: #e0e0e0;
2410
+ cursor: pointer;
2411
+ transition: all 0.15s ease;
2412
+ }
2413
+ .ya-size-preset-name {
2414
+ font-size: 12px;
1909
2415
  font-weight: 500;
1910
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
2416
+ }
2417
+ .ya-size-preset-value {
2418
+ font-size: 9px;
2419
+ opacity: 0.5;
2420
+ }
2421
+ .ya-size-preset-btn:hover {
2422
+ background: rgba(255, 255, 255, 0.1);
2423
+ border-color: rgba(255, 255, 255, 0.2);
2424
+ }
2425
+ .ya-size-preset-btn.is-active {
2426
+ background: var(--color-primary, #D4A574);
2427
+ color: #1a1a1a;
2428
+ border-color: var(--color-primary, #D4A574);
2429
+ }
2430
+ .ya-size-combobox {
2431
+ position: relative;
2432
+ }
2433
+ .ya-size-input {
2434
+ width: 100%;
2435
+ padding: 6px 8px;
2436
+ background: rgba(255, 255, 255, 0.05);
2437
+ border: 1px solid rgba(255, 255, 255, 0.2);
2438
+ border-radius: 4px;
2439
+ color: #e0e0e0;
2440
+ font-size: 12px;
2441
+ box-sizing: border-box;
2442
+ }
2443
+ .ya-size-input:focus {
2444
+ outline: none;
2445
+ border-color: var(--color-primary, #D4A574);
2446
+ }
2447
+ .ya-size-input::placeholder {
2448
+ color: rgba(224, 224, 224, 0.5);
2449
+ }
2450
+ .ya-font-weight-picker {
2451
+ display: flex;
2452
+ flex-direction: column;
2453
+ gap: 2px;
2454
+ }
2455
+ .ya-weight-option {
2456
+ padding: 8px 12px;
2457
+ background: transparent;
2458
+ border: none;
2459
+ border-radius: 4px;
2460
+ color: #e0e0e0;
2461
+ font-size: 13px;
2462
+ text-align: left;
1911
2463
  cursor: pointer;
1912
- white-space: nowrap;
1913
- transform: translateX(-50%);
1914
- pointer-events: auto;
1915
- animation: ya-link-popover-fade-in 0.1s ease;
1916
- }
1917
- .ya-link-popover:hover {
1918
- background: #2a2a2a;
1919
- }
1920
- @keyframes ya-link-popover-fade-in {
1921
- from {
1922
- opacity: 0;
1923
- transform: translateX(-50%) translateY(-4px);
1924
- }
1925
- to {
1926
- opacity: 1;
1927
- transform: translateX(-50%) translateY(0);
1928
- }
2464
+ transition: all 0.15s ease;
1929
2465
  }
1930
- .ya-link-popover::before {
1931
- content: "";
1932
- position: absolute;
1933
- top: -6px;
1934
- left: 50%;
1935
- transform: translateX(-50%);
1936
- border-left: 6px solid transparent;
1937
- border-right: 6px solid transparent;
1938
- border-bottom: 6px solid #1a1a1a;
1939
- }
1940
- .ya-link-popover-icon {
1941
- width: 14px;
1942
- height: 14px;
1943
- opacity: 0.8;
1944
- flex-shrink: 0;
1945
- }
1946
- .ya-link-popover-prefix {
1947
- opacity: 0.7;
2466
+ .ya-weight-option:hover {
2467
+ background: rgba(255, 255, 255, 0.1);
1948
2468
  }
1949
- .ya-link-popover-name {
1950
- color: var(--color-primary, #D4A574);
2469
+ .ya-weight-option.is-active {
2470
+ background: var(--color-primary, #D4A574);
2471
+ color: #1a1a1a;
1951
2472
  }
1952
2473
  `);
1953
2474
 
@@ -1955,7 +2476,7 @@ body.builder-selector-active .ya-text-editable:hover {
1955
2476
  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');
1956
2477
 
1957
2478
  // src/components/YaText.tsx
1958
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
2479
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1959
2480
  var FontSize = Extension.create({
1960
2481
  name: "fontSize",
1961
2482
  addOptions() {
@@ -2030,27 +2551,18 @@ var FontWeight = Extension.create({
2030
2551
  },
2031
2552
  unsetFontWeight: () => ({ chain }) => {
2032
2553
  return chain().setMark("textStyle", { fontWeight: null }).removeEmptyTextStyle().run();
2033
- }
2034
- };
2035
- }
2036
- });
2037
- var SIZE_PRESETS = {
2038
- S: "14px",
2039
- M: "16px",
2040
- L: "20px",
2041
- XL: "24px"
2042
- };
2043
- var WEIGHT_PRESETS = {
2044
- Regular: "400",
2045
- "Semi-bold": "600",
2046
- Bold: "700",
2047
- "Extra-bold": "800"
2048
- };
2554
+ }
2555
+ };
2556
+ }
2557
+ });
2049
2558
  function YaText({ fieldId, className, as: Component = "span", children }) {
2050
2559
  const { getValue, setValue, mode, saveToWorker, activeFieldId, setActiveField } = useContentStore();
2051
2560
  const storeContent = getValue(fieldId);
2052
2561
  const content = storeContent || (typeof children === "string" ? children : "");
2053
- const [isEditing, setIsEditing] = useState4(false);
2562
+ const [isEditing, setIsEditing] = useState5(false);
2563
+ const [showBubbleMenu, setShowBubbleMenu] = useState5(false);
2564
+ const [fontSizeOpen, setFontSizeOpen] = useState5(false);
2565
+ const [fontWeightOpen, setFontWeightOpen] = useState5(false);
2054
2566
  const {
2055
2567
  displayContent,
2056
2568
  isAnimating,
@@ -2058,9 +2570,16 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2058
2570
  } = useAnimatedText(fieldId, content, {
2059
2571
  enabled: mode === "inline-edit" && !isEditing
2060
2572
  });
2061
- const [originalContent, setOriginalContent] = useState4(content);
2062
- const containerRef = useRef5(null);
2063
- const originalContentRef = useRef5(content);
2573
+ const [originalContent, setOriginalContent] = useState5(content);
2574
+ const containerRef = useRef6(null);
2575
+ const originalContentRef = useRef6(content);
2576
+ const [actionButtonsPos, setActionButtonsPos] = useState5(null);
2577
+ const handleSaveRef = useRef6(() => {
2578
+ });
2579
+ const handleCancelRef = useRef6(() => {
2580
+ });
2581
+ const handleCloseRef = useRef6(() => {
2582
+ });
2064
2583
  const editor = useEditor({
2065
2584
  extensions: [
2066
2585
  StarterKit.configure({
@@ -2090,50 +2609,126 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2090
2609
  editorProps: {
2091
2610
  attributes: {
2092
2611
  class: "outline-none"
2612
+ },
2613
+ // Handle keyboard shortcuts at the editor level to prevent default behavior
2614
+ handleKeyDown: (_view, event) => {
2615
+ if (event.key === "Enter" && !event.shiftKey) {
2616
+ event.preventDefault();
2617
+ handleSaveRef.current();
2618
+ return true;
2619
+ }
2620
+ if (event.key === "Escape") {
2621
+ event.preventDefault();
2622
+ handleCancelRef.current();
2623
+ return true;
2624
+ }
2625
+ if ((event.metaKey || event.ctrlKey) && event.key === "s") {
2626
+ event.preventDefault();
2627
+ handleSaveRef.current();
2628
+ return true;
2629
+ }
2630
+ return false;
2093
2631
  }
2094
2632
  },
2095
2633
  parseOptions: { preserveWhitespace: "full" }
2096
2634
  });
2097
- useEffect4(() => {
2635
+ useEffect6(() => {
2098
2636
  if (editor && !isEditing) {
2099
2637
  if (editor.getHTML() !== content) {
2100
2638
  editor.commands.setContent(content, { parseOptions: { preserveWhitespace: "full" } });
2101
2639
  }
2102
2640
  }
2103
2641
  }, [content, editor, isEditing]);
2104
- useEffect4(() => {
2642
+ useEffect6(() => {
2105
2643
  if (isEditing && activeFieldId !== null && activeFieldId !== fieldId) {
2106
2644
  setIsEditing(false);
2107
2645
  }
2108
2646
  }, [activeFieldId, fieldId, isEditing]);
2109
- const handleSave = useCallback5(() => {
2647
+ useEffect6(() => {
2648
+ if (!isEditing || !containerRef.current || !editor) {
2649
+ setActionButtonsPos(null);
2650
+ return;
2651
+ }
2652
+ const updatePosition = () => {
2653
+ if (!containerRef.current || !editor) return;
2654
+ const rect = containerRef.current.getBoundingClientRect();
2655
+ const { view } = editor;
2656
+ const endPos = view.state.doc.content.size - 1;
2657
+ const endCoords = view.coordsAtPos(Math.max(0, endPos));
2658
+ setActionButtonsPos({
2659
+ top: rect.bottom + 8,
2660
+ left: endCoords.right
2661
+ // Right edge of buttons aligns with text end
2662
+ });
2663
+ };
2664
+ updatePosition();
2665
+ window.addEventListener("scroll", updatePosition, true);
2666
+ window.addEventListener("resize", updatePosition);
2667
+ return () => {
2668
+ window.removeEventListener("scroll", updatePosition, true);
2669
+ window.removeEventListener("resize", updatePosition);
2670
+ };
2671
+ }, [isEditing, editor]);
2672
+ const handleSave = useCallback7(() => {
2110
2673
  if (!editor) return;
2111
2674
  let html = editor.getHTML();
2112
2675
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
2113
- setValue(fieldId, html);
2114
- saveToWorker?.(fieldId, html);
2676
+ if (html !== originalContentRef.current) {
2677
+ setValue(fieldId, html, "user");
2678
+ saveToWorker?.(fieldId, html);
2679
+ }
2680
+ setShowBubbleMenu(false);
2115
2681
  setIsEditing(false);
2116
2682
  }, [editor, fieldId, setValue, saveToWorker]);
2117
- const handleCancel = useCallback5(() => {
2683
+ const handleCancel = useCallback7(() => {
2118
2684
  if (editor) {
2119
2685
  editor.commands.setContent(originalContent, { parseOptions: { preserveWhitespace: "full" } });
2120
2686
  }
2687
+ setShowBubbleMenu(false);
2121
2688
  setIsEditing(false);
2122
2689
  }, [editor, originalContent]);
2123
- const handleClose = useCallback5(() => {
2690
+ useEffect6(() => {
2691
+ handleSaveRef.current = handleSave;
2692
+ handleCancelRef.current = handleCancel;
2693
+ }, [handleSave, handleCancel]);
2694
+ useEffect6(() => {
2695
+ if (mode !== "inline-edit") return;
2696
+ const handleEditRequest = (event) => {
2697
+ const customEvent = event;
2698
+ const parentFieldId = customEvent.detail.fieldId;
2699
+ const parentLink = containerRef.current?.closest(`[data-field-id="${parentFieldId}"]`);
2700
+ if (!parentLink) return;
2701
+ setOriginalContent(content);
2702
+ originalContentRef.current = content;
2703
+ setActiveField(fieldId, { close: handleCloseRef.current });
2704
+ setIsEditing(true);
2705
+ setTimeout(() => {
2706
+ editor?.chain().focus().selectAll().run();
2707
+ setShowBubbleMenu(true);
2708
+ }, 20);
2709
+ };
2710
+ window.addEventListener("yatext:edit-mode", handleEditRequest);
2711
+ return () => window.removeEventListener("yatext:edit-mode", handleEditRequest);
2712
+ }, [mode, fieldId, content, editor, setActiveField]);
2713
+ const handleClose = useCallback7(() => {
2124
2714
  if (!editor) {
2715
+ setShowBubbleMenu(false);
2125
2716
  setIsEditing(false);
2126
2717
  return;
2127
2718
  }
2128
2719
  let currentHtml = editor.getHTML();
2129
2720
  currentHtml = currentHtml.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
2130
2721
  if (currentHtml !== originalContentRef.current) {
2131
- setValue(fieldId, currentHtml);
2722
+ setValue(fieldId, currentHtml, "user");
2132
2723
  saveToWorker?.(fieldId, currentHtml);
2133
2724
  }
2725
+ setShowBubbleMenu(false);
2134
2726
  setIsEditing(false);
2135
2727
  }, [editor, fieldId, setValue, saveToWorker]);
2136
- const handleClick = useCallback5((e) => {
2728
+ useEffect6(() => {
2729
+ handleCloseRef.current = handleClose;
2730
+ }, [handleClose]);
2731
+ const handleClick = useCallback7((e) => {
2137
2732
  if (isEditing) {
2138
2733
  e.preventDefault();
2139
2734
  e.stopPropagation();
@@ -2156,10 +2751,11 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2156
2751
  setIsEditing(true);
2157
2752
  setTimeout(() => {
2158
2753
  editor?.chain().focus().selectAll().run();
2754
+ setShowBubbleMenu(true);
2159
2755
  }, 20);
2160
2756
  }
2161
2757
  }, [mode, isEditing, content, editor, fieldId, setActiveField, handleClose]);
2162
- const handleKeyDown = useCallback5(
2758
+ const handleKeyDown = useCallback7(
2163
2759
  (event) => {
2164
2760
  if (!isEditing) return;
2165
2761
  if (event.key === "Enter" && !event.shiftKey) {
@@ -2180,7 +2776,7 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2180
2776
  },
2181
2777
  [isEditing, handleSave, handleCancel]
2182
2778
  );
2183
- const handleLink = useCallback5(() => {
2779
+ const handleLink = useCallback7(() => {
2184
2780
  if (!editor) return;
2185
2781
  const previousUrl = editor.getAttributes("link").href;
2186
2782
  const url = window.prompt("Enter URL:", previousUrl || "https://");
@@ -2191,10 +2787,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2191
2787
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
2192
2788
  }
2193
2789
  }, [editor]);
2194
- const handleFontSizeChange = useCallback5(
2195
- (e) => {
2790
+ const handleFontSizeChange = useCallback7(
2791
+ (size) => {
2196
2792
  if (!editor) return;
2197
- const size = e.target.value;
2198
2793
  if (size === "") {
2199
2794
  editor.chain().focus().unsetFontSize().run();
2200
2795
  } else {
@@ -2203,10 +2798,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2203
2798
  },
2204
2799
  [editor]
2205
2800
  );
2206
- const handleFontWeightChange = useCallback5(
2207
- (e) => {
2801
+ const handleFontWeightChange = useCallback7(
2802
+ (weight) => {
2208
2803
  if (!editor) return;
2209
- const weight = e.target.value;
2210
2804
  if (weight === "") {
2211
2805
  editor.chain().focus().unsetFontWeight().run();
2212
2806
  } else {
@@ -2218,22 +2812,45 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2218
2812
  const getCurrentFontSize = () => {
2219
2813
  if (!editor) return "";
2220
2814
  const attrs = editor.getAttributes("textStyle");
2221
- return attrs.fontSize || "";
2815
+ if (attrs.fontSize) return attrs.fontSize;
2816
+ try {
2817
+ const { from } = editor.state.selection;
2818
+ const domAtPos = editor.view.domAtPos(from);
2819
+ const element = domAtPos.node instanceof Element ? domAtPos.node : domAtPos.node.parentElement;
2820
+ if (element) {
2821
+ const computed = window.getComputedStyle(element);
2822
+ return computed.fontSize || "";
2823
+ }
2824
+ } catch {
2825
+ }
2826
+ return "";
2222
2827
  };
2223
2828
  const getCurrentFontWeight = () => {
2224
2829
  if (!editor) return "";
2830
+ if (editor.isActive("bold")) return "700";
2225
2831
  const attrs = editor.getAttributes("textStyle");
2226
- return attrs.fontWeight || "";
2832
+ if (attrs.fontWeight) return attrs.fontWeight;
2833
+ try {
2834
+ const { from } = editor.state.selection;
2835
+ const domAtPos = editor.view.domAtPos(from);
2836
+ const element = domAtPos.node instanceof Element ? domAtPos.node : domAtPos.node.parentElement;
2837
+ if (element) {
2838
+ const computed = window.getComputedStyle(element);
2839
+ return computed.fontWeight || "";
2840
+ }
2841
+ } catch {
2842
+ }
2843
+ return "";
2227
2844
  };
2228
2845
  if (mode === "read-only") {
2229
- return /* @__PURE__ */ jsx5(
2846
+ return /* @__PURE__ */ jsx10(
2230
2847
  Component,
2231
2848
  {
2232
2849
  ref: containerRef,
2233
2850
  className,
2234
2851
  "data-ya-restricted": "true",
2235
2852
  "data-field-id": fieldId,
2236
- children: /* @__PURE__ */ jsx5(SafeHtml, { content, mode })
2853
+ children: /* @__PURE__ */ jsx10(SafeHtml, { content, mode })
2237
2854
  }
2238
2855
  );
2239
2856
  }
@@ -2242,8 +2859,9 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2242
2859
  isEditing ? "ya-text-editing" : "ya-text-editable",
2243
2860
  wrapperClassName
2244
2861
  ].filter(Boolean).join(" ");
2245
- return /* @__PURE__ */ jsx5(
2246
- Component,
2862
+ const EditSafeComponent = isEditing && Component === "p" ? "div" : Component;
2863
+ return /* @__PURE__ */ jsx10(
2864
+ EditSafeComponent,
2247
2865
  {
2248
2866
  ref: containerRef,
2249
2867
  className: combinedClassName,
@@ -2252,114 +2870,135 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
2252
2870
  "data-ai-editing": isAnimating || void 0,
2253
2871
  onClick: handleClick,
2254
2872
  onKeyDown: handleKeyDown,
2255
- children: editor ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
2256
- createPortal2(
2257
- /* @__PURE__ */ jsxs2(
2258
- BubbleMenu,
2259
- {
2260
- editor,
2261
- shouldShow: () => isEditing,
2262
- options: { offset: 6, placement: "top" },
2263
- className: "ya-bubble-menu",
2264
- children: [
2265
- /* @__PURE__ */ jsx5(
2266
- "button",
2267
- {
2268
- type: "button",
2269
- onClick: () => editor.chain().focus().toggleBold().run(),
2270
- className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
2271
- title: "Bold",
2272
- children: /* @__PURE__ */ jsx5("strong", { children: "B" })
2273
- }
2274
- ),
2275
- /* @__PURE__ */ jsx5(
2276
- "button",
2277
- {
2278
- type: "button",
2279
- onClick: () => editor.chain().focus().toggleItalic().run(),
2280
- className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
2281
- title: "Italic",
2282
- children: /* @__PURE__ */ jsx5("em", { children: "I" })
2283
- }
2284
- ),
2285
- /* @__PURE__ */ jsx5(
2286
- "button",
2287
- {
2288
- type: "button",
2289
- onClick: handleLink,
2290
- className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
2291
- title: "Link",
2292
- children: /* @__PURE__ */ jsx5("span", { children: "\u{1F517}" })
2293
- }
2294
- ),
2295
- /* @__PURE__ */ jsx5("span", { className: "ya-bubble-divider" }),
2296
- /* @__PURE__ */ jsxs2(
2297
- "select",
2298
- {
2299
- value: getCurrentFontSize(),
2300
- onChange: handleFontSizeChange,
2301
- className: "ya-bubble-select",
2302
- title: "Font Size",
2303
- children: [
2304
- /* @__PURE__ */ jsx5("option", { value: "", children: "Size" }),
2305
- Object.entries(SIZE_PRESETS).map(([name, size]) => /* @__PURE__ */ jsx5("option", { value: size, children: name }, name))
2306
- ]
2307
- }
2308
- ),
2309
- /* @__PURE__ */ jsxs2(
2310
- "select",
2311
- {
2312
- value: getCurrentFontWeight(),
2313
- onChange: handleFontWeightChange,
2314
- className: "ya-bubble-select",
2315
- title: "Font Weight",
2316
- children: [
2317
- /* @__PURE__ */ jsx5("option", { value: "", children: "Weight" }),
2318
- Object.entries(WEIGHT_PRESETS).map(([name, weight]) => /* @__PURE__ */ jsx5("option", { value: weight, children: name }, name))
2319
- ]
2320
- }
2321
- )
2322
- ]
2323
- }
2324
- ),
2325
- document.body
2873
+ children: editor ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2874
+ /* @__PURE__ */ jsxs5(
2875
+ ControlledBubbleMenu,
2876
+ {
2877
+ editor,
2878
+ open: showBubbleMenu,
2879
+ className: "ya-bubble-menu",
2880
+ children: [
2881
+ /* @__PURE__ */ jsx10(
2882
+ "button",
2883
+ {
2884
+ type: "button",
2885
+ onClick: () => editor.chain().focus().toggleBold().run(),
2886
+ onMouseDown: (e) => e.preventDefault(),
2887
+ className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
2888
+ title: "Bold",
2889
+ children: /* @__PURE__ */ jsx10(BoldIcon, { size: 16 })
2890
+ }
2891
+ ),
2892
+ /* @__PURE__ */ jsx10(
2893
+ "button",
2894
+ {
2895
+ type: "button",
2896
+ onClick: () => editor.chain().focus().toggleItalic().run(),
2897
+ onMouseDown: (e) => e.preventDefault(),
2898
+ className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
2899
+ title: "Italic",
2900
+ children: /* @__PURE__ */ jsx10(ItalicIcon, { size: 16 })
2901
+ }
2902
+ ),
2903
+ /* @__PURE__ */ jsx10(
2904
+ "button",
2905
+ {
2906
+ type: "button",
2907
+ onClick: handleLink,
2908
+ onMouseDown: (e) => e.preventDefault(),
2909
+ className: `ya-bubble-btn ${editor.isActive("link") ? "is-active" : ""}`,
2910
+ title: "Link",
2911
+ children: /* @__PURE__ */ jsx10(LinkIcon2, { size: 16 })
2912
+ }
2913
+ ),
2914
+ /* @__PURE__ */ jsx10("span", { className: "ya-bubble-divider" }),
2915
+ /* @__PURE__ */ jsx10(
2916
+ BubbleDropdown,
2917
+ {
2918
+ label: getFontSizeLabel(getCurrentFontSize()),
2919
+ open: fontSizeOpen,
2920
+ onOpenChange: setFontSizeOpen,
2921
+ children: /* @__PURE__ */ jsx10(
2922
+ FontSizePicker,
2923
+ {
2924
+ value: getCurrentFontSize(),
2925
+ onChange: handleFontSizeChange,
2926
+ onClose: () => setFontSizeOpen(false)
2927
+ }
2928
+ )
2929
+ }
2930
+ ),
2931
+ /* @__PURE__ */ jsx10(
2932
+ BubbleDropdown,
2933
+ {
2934
+ label: getFontWeightLabel(getCurrentFontWeight()),
2935
+ open: fontWeightOpen,
2936
+ onOpenChange: setFontWeightOpen,
2937
+ children: /* @__PURE__ */ jsx10(
2938
+ FontWeightPicker,
2939
+ {
2940
+ value: getCurrentFontWeight(),
2941
+ onChange: handleFontWeightChange,
2942
+ onClose: () => setFontWeightOpen(false)
2943
+ }
2944
+ )
2945
+ }
2946
+ )
2947
+ ]
2948
+ }
2326
2949
  ),
2327
- isEditing ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
2328
- /* @__PURE__ */ jsx5(EditorContent, { editor }),
2329
- /* @__PURE__ */ jsxs2("div", { className: "ya-text-actions", children: [
2330
- /* @__PURE__ */ jsx5(
2331
- "button",
2950
+ isEditing ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2951
+ /* @__PURE__ */ jsx10(EditorContent, { editor }),
2952
+ actionButtonsPos && createPortal3(
2953
+ /* @__PURE__ */ jsxs5(
2954
+ "div",
2332
2955
  {
2333
- type: "button",
2334
- onClick: handleCancel,
2335
- className: "ya-text-btn ya-text-btn-cancel",
2336
- children: "Cancel"
2956
+ className: "ya-text-actions",
2957
+ style: {
2958
+ position: "fixed",
2959
+ top: actionButtonsPos.top,
2960
+ left: actionButtonsPos.left,
2961
+ transform: "translateX(-100%)"
2962
+ // Right edge aligns with text end
2963
+ },
2964
+ children: [
2965
+ /* @__PURE__ */ jsx10(
2966
+ "button",
2967
+ {
2968
+ type: "button",
2969
+ onClick: handleCancel,
2970
+ className: "ya-text-btn ya-text-btn-cancel",
2971
+ children: "Cancel"
2972
+ }
2973
+ ),
2974
+ /* @__PURE__ */ jsx10(
2975
+ "button",
2976
+ {
2977
+ type: "button",
2978
+ onClick: handleSave,
2979
+ className: "ya-text-btn ya-text-btn-save",
2980
+ children: "Save"
2981
+ }
2982
+ )
2983
+ ]
2337
2984
  }
2338
2985
  ),
2339
- /* @__PURE__ */ jsx5(
2340
- "button",
2341
- {
2342
- type: "button",
2343
- onClick: handleSave,
2344
- className: "ya-text-btn ya-text-btn-save",
2345
- children: "Save"
2346
- }
2347
- )
2348
- ] })
2349
- ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
2350
- /* @__PURE__ */ jsx5(SafeHtml, { content: displayContent, mode }),
2351
- isAnimating && /* @__PURE__ */ jsx5("span", { className: "ya-typing-cursor" })
2986
+ document.body
2987
+ )
2988
+ ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
2989
+ /* @__PURE__ */ jsx10(SafeHtml, { content: displayContent, mode }),
2990
+ isAnimating && /* @__PURE__ */ jsx10("span", { className: "ya-typing-cursor" })
2352
2991
  ] })
2353
- ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
2354
- /* @__PURE__ */ jsx5(SafeHtml, { content: displayContent, mode }),
2355
- isAnimating && /* @__PURE__ */ jsx5("span", { className: "ya-typing-cursor" })
2992
+ ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
2993
+ /* @__PURE__ */ jsx10(SafeHtml, { content: displayContent, mode }),
2994
+ isAnimating && /* @__PURE__ */ jsx10("span", { className: "ya-typing-cursor" })
2356
2995
  ] })
2357
2996
  }
2358
2997
  );
2359
2998
  }
2360
2999
 
2361
3000
  // src/components/YaImage.tsx
2362
- import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef7, useState as useState6 } from "react";
3001
+ import { useCallback as useCallback9, useEffect as useEffect8, useRef as useRef8, useState as useState7 } from "react";
2363
3002
 
2364
3003
  // src/lib/asset-resolver.ts
2365
3004
  var assetResolver = (path) => path;
@@ -2375,25 +3014,25 @@ function resolveAssetUrl(path) {
2375
3014
  }
2376
3015
 
2377
3016
  // src/components/YaTooltip.tsx
2378
- import { useEffect as useEffect5, useRef as useRef6, useState as useState5, useCallback as useCallback6 } from "react";
2379
- import { createPortal as createPortal3 } from "react-dom";
3017
+ import { useEffect as useEffect7, useRef as useRef7, useState as useState6, useCallback as useCallback8 } from "react";
3018
+ import { createPortal as createPortal4 } from "react-dom";
2380
3019
 
2381
3020
  // src/components/ya-tooltip.css
2382
- styleInject('.ya-tooltip {\n position: fixed;\n z-index: 9999;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n animation: ya-tooltip-fade-in 0.15s ease;\n pointer-events: none;\n}\n@keyframes ya-tooltip-fade-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n.ya-tooltip svg {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n}\n.ya-tooltip-bottom {\n transform: translateX(-50%);\n}\n.ya-tooltip-bottom::before {\n content: "";\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-bottom-color: #1a1a1a;\n}\n.ya-tooltip-top {\n transform: translateX(-50%);\n}\n.ya-tooltip-top::before {\n content: "";\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 6px solid transparent;\n border-top-color: #1a1a1a;\n}\n.ya-tooltip-right {\n transform: translateY(-50%);\n}\n.ya-tooltip-right::before {\n content: "";\n position: absolute;\n right: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-right-color: #1a1a1a;\n}\n.ya-tooltip-left {\n transform: translateY(-50%);\n}\n.ya-tooltip-left::before {\n content: "";\n position: absolute;\n left: 100%;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: #1a1a1a;\n}\n');
3021
+ 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');
2383
3022
 
2384
3023
  // src/components/YaTooltip.tsx
2385
- import { jsx as jsx6 } from "react/jsx-runtime";
3024
+ import { jsx as jsx11 } from "react/jsx-runtime";
2386
3025
  function YaTooltip({
2387
3026
  anchorRef,
2388
3027
  children,
2389
3028
  show,
2390
3029
  preferredPosition = "bottom"
2391
3030
  }) {
2392
- const [position, setPosition] = useState5(preferredPosition);
2393
- const [coords, setCoords] = useState5({ top: 0, left: 0 });
2394
- const [isPositioned, setIsPositioned] = useState5(false);
2395
- const tooltipRef = useRef6(null);
2396
- const calculatePosition = useCallback6(() => {
3031
+ const [position, setPosition] = useState6(preferredPosition);
3032
+ const [coords, setCoords] = useState6({ top: 0, left: 0 });
3033
+ const [isPositioned, setIsPositioned] = useState6(false);
3034
+ const tooltipRef = useRef7(null);
3035
+ const calculatePosition = useCallback8(() => {
2397
3036
  if (!anchorRef.current) return;
2398
3037
  const anchor = anchorRef.current.getBoundingClientRect();
2399
3038
  const tooltip = tooltipRef.current?.getBoundingClientRect();
@@ -2468,7 +3107,7 @@ function YaTooltip({
2468
3107
  setCoords({ top, left });
2469
3108
  setIsPositioned(true);
2470
3109
  }, [anchorRef, preferredPosition]);
2471
- useEffect5(() => {
3110
+ useEffect7(() => {
2472
3111
  if (!show) {
2473
3112
  setIsPositioned(false);
2474
3113
  return;
@@ -2481,14 +3120,14 @@ function YaTooltip({
2481
3120
  window.removeEventListener("resize", calculatePosition);
2482
3121
  };
2483
3122
  }, [show, calculatePosition]);
2484
- useEffect5(() => {
3123
+ useEffect7(() => {
2485
3124
  if (show && tooltipRef.current) {
2486
3125
  calculatePosition();
2487
3126
  }
2488
3127
  }, [show, children, calculatePosition]);
2489
3128
  if (!show) return null;
2490
- return createPortal3(
2491
- /* @__PURE__ */ jsx6(
3129
+ return createPortal4(
3130
+ /* @__PURE__ */ jsx11(
2492
3131
  "div",
2493
3132
  {
2494
3133
  ref: tooltipRef,
@@ -2496,8 +3135,7 @@ function YaTooltip({
2496
3135
  style: {
2497
3136
  top: coords.top,
2498
3137
  left: coords.left,
2499
- opacity: isPositioned ? 1 : 0,
2500
- pointerEvents: isPositioned ? "auto" : "none"
3138
+ visibility: isPositioned ? "visible" : "hidden"
2501
3139
  },
2502
3140
  role: "tooltip",
2503
3141
  children
@@ -2511,7 +3149,7 @@ function YaTooltip({
2511
3149
  styleInject('.ya-image-container {\n position: relative;\n display: inline-block;\n min-width: 45px;\n min-height: 45px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-image-container img {\n display: block;\n}\n.ya-image-editable {\n cursor: pointer;\n}\n.ya-image-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-image-editable:hover .ya-image-overlay {\n opacity: 1;\n}\n.ya-image-selected .ya-image-overlay {\n opacity: 0;\n}\n.ya-image-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-image-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-image-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n@keyframes ya-image-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #D4A574);\n outline-width: 2px;\n }\n}\n.ya-image-success {\n animation: ya-image-success 0.4s ease;\n}\n.ya-image-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-image-shimmer 1.5s infinite;\n}\n@keyframes ya-image-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-image-container:focus {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-image-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n}\n.ya-image-small .ya-image-overlay {\n display: none;\n}\n.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');
2512
3150
 
2513
3151
  // src/components/YaImage.tsx
2514
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
3152
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
2515
3153
  function parseImageValue(value) {
2516
3154
  if (!value) {
2517
3155
  return { src: "" };
@@ -2556,20 +3194,20 @@ function YaImage({
2556
3194
  fallbackAlt
2557
3195
  }) {
2558
3196
  const { getValue, mode } = useContentStore();
2559
- const containerRef = useRef7(null);
2560
- const imgRef = useRef7(null);
2561
- const [isSelected, setIsSelected] = useState6(false);
2562
- const [isHovered, setIsHovered] = useState6(false);
2563
- const [isSmallImage, setIsSmallImage] = useState6(false);
2564
- const [isDropMode, setIsDropMode] = useState6(false);
2565
- const [isDropHover, setIsDropHover] = useState6(false);
3197
+ const containerRef = useRef8(null);
3198
+ const imgRef = useRef8(null);
3199
+ const [isSelected, setIsSelected] = useState7(false);
3200
+ const [isHovered, setIsHovered] = useState7(false);
3201
+ const [isSmallImage, setIsSmallImage] = useState7(false);
3202
+ const [isDropMode, setIsDropMode] = useState7(false);
3203
+ const [isDropHover, setIsDropHover] = useState7(false);
2566
3204
  const rawValue = getValue(fieldId);
2567
3205
  const imageData = parseImageValue(rawValue);
2568
3206
  const src = imageData.src || fallbackSrc || PLACEHOLDER_SVG;
2569
3207
  const altText = imageData.alt || alt || fallbackAlt || "";
2570
3208
  const objectFit = imageData.objectFit || propObjectFit || "cover";
2571
3209
  const objectPosition = getObjectPosition(imageData) || propObjectPosition || "50% 50%";
2572
- const handleClick = useCallback7(() => {
3210
+ const handleClick = useCallback9(() => {
2573
3211
  if (mode !== "inline-edit") return;
2574
3212
  if (document.body.classList.contains("builder-selector-active")) return;
2575
3213
  setIsSelected(true);
@@ -2597,7 +3235,7 @@ function YaImage({
2597
3235
  "*"
2598
3236
  );
2599
3237
  }, [mode, fieldId, imageData, src, altText, objectFit, objectPosition]);
2600
- useEffect6(() => {
3238
+ useEffect8(() => {
2601
3239
  if (mode !== "inline-edit") return;
2602
3240
  const handleMessage2 = (event) => {
2603
3241
  if (event.data?.type === "YA_IMAGE_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -2612,7 +3250,7 @@ function YaImage({
2612
3250
  window.addEventListener("message", handleMessage2);
2613
3251
  return () => window.removeEventListener("message", handleMessage2);
2614
3252
  }, [mode, fieldId]);
2615
- useEffect6(() => {
3253
+ useEffect8(() => {
2616
3254
  if (mode !== "inline-edit") return;
2617
3255
  const handleDropModeMessage = (event) => {
2618
3256
  if (event.data?.type === "DROP_MODE_START") {
@@ -2626,7 +3264,7 @@ function YaImage({
2626
3264
  window.addEventListener("message", handleDropModeMessage);
2627
3265
  return () => window.removeEventListener("message", handleDropModeMessage);
2628
3266
  }, [mode]);
2629
- const handleDragEnter = useCallback7(
3267
+ const handleDragEnter = useCallback9(
2630
3268
  (e) => {
2631
3269
  if (!isDropMode) return;
2632
3270
  e.preventDefault();
@@ -2650,7 +3288,7 @@ function YaImage({
2650
3288
  },
2651
3289
  [isDropMode, fieldId]
2652
3290
  );
2653
- const handleDragOver = useCallback7(
3291
+ const handleDragOver = useCallback9(
2654
3292
  (e) => {
2655
3293
  if (!isDropMode) return;
2656
3294
  e.preventDefault();
@@ -2658,7 +3296,7 @@ function YaImage({
2658
3296
  },
2659
3297
  [isDropMode]
2660
3298
  );
2661
- const handleDragLeave = useCallback7(
3299
+ const handleDragLeave = useCallback9(
2662
3300
  (e) => {
2663
3301
  if (!isDropMode) return;
2664
3302
  e.preventDefault();
@@ -2672,7 +3310,7 @@ function YaImage({
2672
3310
  },
2673
3311
  [isDropMode]
2674
3312
  );
2675
- const handleDrop = useCallback7(
3313
+ const handleDrop = useCallback9(
2676
3314
  (e) => {
2677
3315
  if (!isDropMode) return;
2678
3316
  e.preventDefault();
@@ -2690,7 +3328,7 @@ function YaImage({
2690
3328
  },
2691
3329
  [isDropMode, fieldId]
2692
3330
  );
2693
- useEffect6(() => {
3331
+ useEffect8(() => {
2694
3332
  if (mode !== "inline-edit") return;
2695
3333
  const checkSize = () => {
2696
3334
  if (imgRef.current) {
@@ -2712,7 +3350,7 @@ function YaImage({
2712
3350
  window.removeEventListener("resize", checkSize);
2713
3351
  };
2714
3352
  }, [mode]);
2715
- useEffect6(() => {
3353
+ useEffect8(() => {
2716
3354
  if (!isSelected || mode !== "inline-edit") return;
2717
3355
  let lastRectKey = "";
2718
3356
  let lastTime = 0;
@@ -2747,7 +3385,7 @@ function YaImage({
2747
3385
  return () => cancelAnimationFrame(rafId);
2748
3386
  }, [isSelected, fieldId, mode]);
2749
3387
  if (mode === "read-only") {
2750
- return /* @__PURE__ */ jsx7(
3388
+ return /* @__PURE__ */ jsx12(
2751
3389
  "img",
2752
3390
  {
2753
3391
  src: resolveAssetUrl(src),
@@ -2763,7 +3401,7 @@ function YaImage({
2763
3401
  }
2764
3402
  );
2765
3403
  }
2766
- const editIcon = /* @__PURE__ */ jsxs3(
3404
+ const editIcon = /* @__PURE__ */ jsxs6(
2767
3405
  "svg",
2768
3406
  {
2769
3407
  width: "24",
@@ -2775,9 +3413,9 @@ function YaImage({
2775
3413
  strokeLinecap: "round",
2776
3414
  strokeLinejoin: "round",
2777
3415
  children: [
2778
- /* @__PURE__ */ jsx7("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
2779
- /* @__PURE__ */ jsx7("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2780
- /* @__PURE__ */ jsx7("polyline", { points: "21 15 16 10 5 21" })
3416
+ /* @__PURE__ */ jsx12("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
3417
+ /* @__PURE__ */ jsx12("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
3418
+ /* @__PURE__ */ jsx12("polyline", { points: "21 15 16 10 5 21" })
2781
3419
  ]
2782
3420
  }
2783
3421
  );
@@ -2788,7 +3426,7 @@ function YaImage({
2788
3426
  isDropMode ? "ya-image-drop-target" : "",
2789
3427
  isDropHover ? "ya-image-drop-hover" : ""
2790
3428
  ].filter(Boolean).join(" ");
2791
- return /* @__PURE__ */ jsxs3(
3429
+ return /* @__PURE__ */ jsxs6(
2792
3430
  "div",
2793
3431
  {
2794
3432
  ref: containerRef,
@@ -2813,7 +3451,7 @@ function YaImage({
2813
3451
  }
2814
3452
  },
2815
3453
  children: [
2816
- /* @__PURE__ */ jsx7(
3454
+ /* @__PURE__ */ jsx12(
2817
3455
  "img",
2818
3456
  {
2819
3457
  ref: imgRef,
@@ -2827,14 +3465,14 @@ function YaImage({
2827
3465
  loading
2828
3466
  }
2829
3467
  ),
2830
- isSmallImage ? /* @__PURE__ */ jsxs3(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3468
+ isSmallImage ? /* @__PURE__ */ jsxs6(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
2831
3469
  editIcon,
2832
- /* @__PURE__ */ jsx7("span", { children: "Click to edit" })
3470
+ /* @__PURE__ */ jsx12("span", { children: "Click to edit" })
2833
3471
  ] }) : (
2834
3472
  /* For large images: show overlay inside the image */
2835
- /* @__PURE__ */ jsxs3("div", { className: "ya-image-overlay", children: [
2836
- /* @__PURE__ */ jsx7("div", { className: "ya-image-edit-icon", children: editIcon }),
2837
- /* @__PURE__ */ jsx7("span", { className: "ya-image-edit-label", children: "Click to edit" })
3473
+ /* @__PURE__ */ jsxs6("div", { className: "ya-image-overlay", children: [
3474
+ /* @__PURE__ */ jsx12("div", { className: "ya-image-edit-icon", children: editIcon }),
3475
+ /* @__PURE__ */ jsx12("span", { className: "ya-image-edit-label", children: "Click to edit" })
2838
3476
  ] })
2839
3477
  )
2840
3478
  ]
@@ -2843,13 +3481,13 @@ function YaImage({
2843
3481
  }
2844
3482
 
2845
3483
  // src/components/YaVideo.tsx
2846
- import { useCallback as useCallback8, useEffect as useEffect7, useRef as useRef8, useState as useState7 } from "react";
3484
+ import { useCallback as useCallback10, useEffect as useEffect9, useRef as useRef9, useState as useState8 } from "react";
2847
3485
 
2848
3486
  // src/components/ya-video.css
2849
3487
  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');
2850
3488
 
2851
3489
  // src/components/YaVideo.tsx
2852
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
3490
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
2853
3491
  function parseVideoValue(value) {
2854
3492
  if (!value) {
2855
3493
  return { type: "upload", src: "" };
@@ -2922,12 +3560,12 @@ function YaVideo({
2922
3560
  fallbackPoster
2923
3561
  }) {
2924
3562
  const { getValue, mode } = useContentStore();
2925
- const containerRef = useRef8(null);
2926
- const videoRef = useRef8(null);
2927
- const [isSelected, setIsSelected] = useState7(false);
2928
- const [isHovered, setIsHovered] = useState7(false);
2929
- const [isSmallVideo, setIsSmallVideo] = useState7(false);
2930
- const [isInView, setIsInView] = useState7(loading === "eager");
3563
+ const containerRef = useRef9(null);
3564
+ const videoRef = useRef9(null);
3565
+ const [isSelected, setIsSelected] = useState8(false);
3566
+ const [isHovered, setIsHovered] = useState8(false);
3567
+ const [isSmallVideo, setIsSmallVideo] = useState8(false);
3568
+ const [isInView, setIsInView] = useState8(loading === "eager");
2931
3569
  const rawValue = getValue(fieldId);
2932
3570
  const parsedValue = parseVideoValue(rawValue);
2933
3571
  const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
@@ -2941,8 +3579,8 @@ function YaVideo({
2941
3579
  const controls = videoData.controls ?? true;
2942
3580
  const playsinline = videoData.playsinline ?? true;
2943
3581
  const preload = videoData.preload ?? "metadata";
2944
- const [prefersReducedMotion, setPrefersReducedMotion] = useState7(false);
2945
- useEffect7(() => {
3582
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState8(false);
3583
+ useEffect9(() => {
2946
3584
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
2947
3585
  setPrefersReducedMotion(mediaQuery.matches);
2948
3586
  const handleChange = (e) => {
@@ -2952,7 +3590,7 @@ function YaVideo({
2952
3590
  return () => mediaQuery.removeEventListener("change", handleChange);
2953
3591
  }, []);
2954
3592
  const effectiveAutoplay = autoplay && !prefersReducedMotion;
2955
- useEffect7(() => {
3593
+ useEffect9(() => {
2956
3594
  if (loading === "eager" || isInView) return;
2957
3595
  const observer = new IntersectionObserver(
2958
3596
  (entries) => {
@@ -2969,7 +3607,7 @@ function YaVideo({
2969
3607
  }
2970
3608
  return () => observer.disconnect();
2971
3609
  }, [loading, isInView]);
2972
- const handleKeyDown = useCallback8(
3610
+ const handleKeyDown = useCallback10(
2973
3611
  (e) => {
2974
3612
  if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
2975
3613
  e.preventDefault();
@@ -2985,7 +3623,7 @@ function YaVideo({
2985
3623
  },
2986
3624
  [videoData.type, controls]
2987
3625
  );
2988
- const handleClick = useCallback8(() => {
3626
+ const handleClick = useCallback10(() => {
2989
3627
  if (mode !== "inline-edit") return;
2990
3628
  if (document.body.classList.contains("builder-selector-active")) return;
2991
3629
  setIsSelected(true);
@@ -3005,7 +3643,7 @@ function YaVideo({
3005
3643
  "*"
3006
3644
  );
3007
3645
  }, [mode, fieldId, videoData]);
3008
- useEffect7(() => {
3646
+ useEffect9(() => {
3009
3647
  if (mode !== "inline-edit") return;
3010
3648
  const handleMessage2 = (event) => {
3011
3649
  if (event.data?.type === "YA_VIDEO_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -3018,7 +3656,7 @@ function YaVideo({
3018
3656
  window.addEventListener("message", handleMessage2);
3019
3657
  return () => window.removeEventListener("message", handleMessage2);
3020
3658
  }, [mode, fieldId]);
3021
- useEffect7(() => {
3659
+ useEffect9(() => {
3022
3660
  if (mode !== "inline-edit") return;
3023
3661
  const checkSize = () => {
3024
3662
  if (containerRef.current) {
@@ -3030,7 +3668,7 @@ function YaVideo({
3030
3668
  window.addEventListener("resize", checkSize);
3031
3669
  return () => window.removeEventListener("resize", checkSize);
3032
3670
  }, [mode]);
3033
- useEffect7(() => {
3671
+ useEffect9(() => {
3034
3672
  if (!isSelected || mode !== "inline-edit") return;
3035
3673
  let lastRectKey = "";
3036
3674
  let lastTime = 0;
@@ -3066,24 +3704,24 @@ function YaVideo({
3066
3704
  }, [isSelected, fieldId, mode]);
3067
3705
  const renderVideo = (isReadOnly) => {
3068
3706
  if (!src && !isReadOnly) {
3069
- return /* @__PURE__ */ jsxs4("div", { className: "ya-video-placeholder", children: [
3070
- /* @__PURE__ */ jsx8("img", { src: PLACEHOLDER_SVG2, alt: "" }),
3071
- /* @__PURE__ */ jsx8("span", { children: "No video selected" })
3707
+ return /* @__PURE__ */ jsxs7("div", { className: "ya-video-placeholder", children: [
3708
+ /* @__PURE__ */ jsx13("img", { src: PLACEHOLDER_SVG2, alt: "" }),
3709
+ /* @__PURE__ */ jsx13("span", { children: "No video selected" })
3072
3710
  ] });
3073
3711
  }
3074
3712
  if (!isInView && loading === "lazy" && !isReadOnly) {
3075
- return /* @__PURE__ */ jsx8(
3713
+ return /* @__PURE__ */ jsx13(
3076
3714
  "div",
3077
3715
  {
3078
3716
  className: "ya-video-placeholder",
3079
3717
  style: { aspectRatio },
3080
- children: /* @__PURE__ */ jsx8("img", { src: PLACEHOLDER_SVG2, alt: "" })
3718
+ children: /* @__PURE__ */ jsx13("img", { src: PLACEHOLDER_SVG2, alt: "" })
3081
3719
  }
3082
3720
  );
3083
3721
  }
3084
3722
  if (videoData.type === "youtube" && src) {
3085
3723
  const embedUrl = buildYouTubeEmbedUrl(src, videoData);
3086
- return /* @__PURE__ */ jsx8(
3724
+ return /* @__PURE__ */ jsx13(
3087
3725
  "iframe",
3088
3726
  {
3089
3727
  src: embedUrl,
@@ -3103,7 +3741,7 @@ function YaVideo({
3103
3741
  }
3104
3742
  if (videoData.type === "vimeo" && src) {
3105
3743
  const embedUrl = buildVimeoEmbedUrl(src, videoData);
3106
- return /* @__PURE__ */ jsx8(
3744
+ return /* @__PURE__ */ jsx13(
3107
3745
  "iframe",
3108
3746
  {
3109
3747
  src: embedUrl,
@@ -3123,7 +3761,7 @@ function YaVideo({
3123
3761
  }
3124
3762
  const resolvedSrc = resolveAssetUrl(src);
3125
3763
  const resolvedPoster = poster ? resolveAssetUrl(poster) : void 0;
3126
- return /* @__PURE__ */ jsx8(
3764
+ return /* @__PURE__ */ jsx13(
3127
3765
  "video",
3128
3766
  {
3129
3767
  ref: videoRef,
@@ -3158,7 +3796,7 @@ function YaVideo({
3158
3796
  );
3159
3797
  };
3160
3798
  if (mode === "read-only") {
3161
- return /* @__PURE__ */ jsx8(
3799
+ return /* @__PURE__ */ jsx13(
3162
3800
  "div",
3163
3801
  {
3164
3802
  ref: containerRef,
@@ -3174,7 +3812,7 @@ function YaVideo({
3174
3812
  }
3175
3813
  );
3176
3814
  }
3177
- const videoIcon = /* @__PURE__ */ jsxs4(
3815
+ const videoIcon = /* @__PURE__ */ jsxs7(
3178
3816
  "svg",
3179
3817
  {
3180
3818
  width: "24",
@@ -3186,12 +3824,12 @@ function YaVideo({
3186
3824
  strokeLinecap: "round",
3187
3825
  strokeLinejoin: "round",
3188
3826
  children: [
3189
- /* @__PURE__ */ jsx8("rect", { x: "2", y: "4", width: "15", height: "13", rx: "2", ry: "2" }),
3190
- /* @__PURE__ */ jsx8("polygon", { points: "22 7 15 12 22 17 22 7", fill: "currentColor" })
3827
+ /* @__PURE__ */ jsx13("rect", { x: "2", y: "4", width: "15", height: "13", rx: "2", ry: "2" }),
3828
+ /* @__PURE__ */ jsx13("polygon", { points: "22 7 15 12 22 17 22 7", fill: "currentColor" })
3191
3829
  ]
3192
3830
  }
3193
3831
  );
3194
- return /* @__PURE__ */ jsxs4(
3832
+ return /* @__PURE__ */ jsxs7(
3195
3833
  "div",
3196
3834
  {
3197
3835
  ref: containerRef,
@@ -3214,14 +3852,14 @@ function YaVideo({
3214
3852
  style: { aspectRatio },
3215
3853
  children: [
3216
3854
  renderVideo(false),
3217
- isSmallVideo ? /* @__PURE__ */ jsxs4(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3855
+ isSmallVideo ? /* @__PURE__ */ jsxs7(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3218
3856
  videoIcon,
3219
- /* @__PURE__ */ jsx8("span", { children: "Click to edit" })
3857
+ /* @__PURE__ */ jsx13("span", { children: "Click to edit" })
3220
3858
  ] }) : (
3221
3859
  /* For large videos: show overlay inside the container */
3222
- /* @__PURE__ */ jsxs4("div", { className: "ya-video-overlay", children: [
3223
- /* @__PURE__ */ jsx8("div", { className: "ya-video-edit-icon", children: videoIcon }),
3224
- /* @__PURE__ */ jsx8("span", { className: "ya-video-edit-label", children: "Click to edit" })
3860
+ /* @__PURE__ */ jsxs7("div", { className: "ya-video-overlay", children: [
3861
+ /* @__PURE__ */ jsx13("div", { className: "ya-video-edit-icon", children: videoIcon }),
3862
+ /* @__PURE__ */ jsx13("span", { className: "ya-video-edit-label", children: "Click to edit" })
3225
3863
  ] })
3226
3864
  )
3227
3865
  ]
@@ -3230,104 +3868,82 @@ function YaVideo({
3230
3868
  }
3231
3869
 
3232
3870
  // src/components/YaLink.tsx
3233
- import { useEffect as useEffect10, useRef as useRef10, useState as useState10, useCallback as useCallback10 } from "react";
3871
+ import { useEffect as useEffect12, useRef as useRef12, useState as useState11, useCallback as useCallback13, useId } from "react";
3234
3872
  import { createPortal as createPortal5 } from "react-dom";
3235
3873
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
3236
- import { BubbleMenu as BubbleMenu2 } from "@tiptap/react/menus";
3874
+ import { BubbleMenu } from "@tiptap/react/menus";
3237
3875
  import StarterKit2 from "@tiptap/starter-kit";
3238
3876
  import { TextStyle as TextStyle2 } from "@tiptap/extension-text-style";
3239
3877
  import { Extension as Extension2 } from "@tiptap/core";
3240
3878
  import { Link as WouterLink, useLocation } from "wouter";
3241
3879
 
3242
3880
  // src/components/SafeTriangleBelow.tsx
3243
- import { useEffect as useEffect8, useState as useState8 } from "react";
3244
- import { createPortal as createPortal4 } from "react-dom";
3245
- import { jsx as jsx9 } from "react/jsx-runtime";
3881
+ import { useEffect as useEffect10, useState as useState9, useRef as useRef10, useCallback as useCallback11 } from "react";
3246
3882
  function SafeTriangleBelow({
3247
3883
  triggerRef,
3248
3884
  popoverRef,
3249
3885
  isVisible,
3250
- onLeave
3886
+ onLeave,
3887
+ onStayInside
3251
3888
  }) {
3252
- const [mousePos, setMousePos] = useState8({ x: 0, y: 0 });
3253
- const [mounted, setMounted] = useState8(false);
3254
- useEffect8(() => {
3255
- setMounted(true);
3256
- }, []);
3257
- useEffect8(() => {
3258
- if (!isVisible) return;
3259
- const handleMouseMove = (e) => {
3260
- setMousePos({ x: e.clientX, y: e.clientY });
3261
- };
3262
- document.addEventListener("mousemove", handleMouseMove);
3263
- return () => document.removeEventListener("mousemove", handleMouseMove);
3264
- }, [isVisible]);
3265
- if (!mounted || !isVisible || !triggerRef.current || !popoverRef.current) {
3266
- return null;
3267
- }
3268
- const popoverRect = popoverRef.current.getBoundingClientRect();
3269
- const triggerRect = triggerRef.current.getBoundingClientRect();
3270
- if (mousePos.y >= popoverRect.top) {
3271
- return null;
3272
- }
3273
- const leftBound = Math.min(triggerRect.left, popoverRect.left) - 20;
3274
- const rightBound = Math.max(triggerRect.right, popoverRect.right) + 20;
3275
- if (mousePos.x < leftBound || mousePos.x > rightBound) {
3276
- return null;
3277
- }
3278
- const svgTop = mousePos.y;
3279
- const svgHeight = Math.max(popoverRect.top - mousePos.y, 1);
3280
- const svgLeft = Math.min(mousePos.x, popoverRect.left);
3281
- const svgWidth = Math.max(popoverRect.right - svgLeft, mousePos.x - svgLeft, 1);
3282
- const cursorX = mousePos.x - svgLeft;
3283
- const popoverLeftX = popoverRect.left - svgLeft;
3284
- const popoverRightX = popoverRect.right - svgLeft;
3285
- const path = `M ${cursorX},0 L ${popoverLeftX},${svgHeight} L ${popoverRightX},${svgHeight} z`;
3286
- return createPortal4(
3287
- /* @__PURE__ */ jsx9(
3288
- "svg",
3289
- {
3290
- style: {
3291
- position: "fixed",
3292
- width: svgWidth,
3293
- height: svgHeight,
3294
- top: svgTop,
3295
- left: svgLeft,
3296
- pointerEvents: "none",
3297
- zIndex: 9998
3298
- },
3299
- children: /* @__PURE__ */ jsx9(
3300
- "path",
3301
- {
3302
- d: path,
3303
- fill: "transparent",
3304
- style: { pointerEvents: "auto" },
3305
- onMouseLeave: onLeave
3306
- }
3307
- )
3308
- }
3309
- ),
3310
- document.body
3311
- );
3889
+ const [bounds, setBounds] = useState9(null);
3890
+ const boundsRef = useRef10(bounds);
3891
+ boundsRef.current = bounds;
3892
+ useEffect10(() => {
3893
+ if (!isVisible || !triggerRef.current || !popoverRef.current) {
3894
+ setBounds(null);
3895
+ return;
3896
+ }
3897
+ const timer = setTimeout(() => {
3898
+ if (!triggerRef.current || !popoverRef.current) return;
3899
+ const triggerRect = triggerRef.current.getBoundingClientRect();
3900
+ const popoverRect = popoverRef.current.getBoundingClientRect();
3901
+ setBounds({
3902
+ top: triggerRect.top,
3903
+ bottom: popoverRect.bottom,
3904
+ left: Math.min(triggerRect.left, popoverRect.left),
3905
+ right: Math.max(triggerRect.right, popoverRect.right)
3906
+ });
3907
+ }, 10);
3908
+ return () => clearTimeout(timer);
3909
+ }, [isVisible, triggerRef, popoverRef]);
3910
+ const checkMousePosition = useCallback11((e) => {
3911
+ const b = boundsRef.current;
3912
+ if (!b) return;
3913
+ const { clientX: x, clientY: y } = e;
3914
+ const padding = 5;
3915
+ const isOutside = x < b.left - padding || x > b.right + padding || y < b.top - padding || y > b.bottom + padding;
3916
+ if (isOutside) {
3917
+ onLeave?.();
3918
+ } else {
3919
+ onStayInside?.();
3920
+ }
3921
+ }, [onLeave, onStayInside]);
3922
+ useEffect10(() => {
3923
+ if (!isVisible || !bounds) return;
3924
+ document.addEventListener("mousemove", checkMousePosition);
3925
+ return () => document.removeEventListener("mousemove", checkMousePosition);
3926
+ }, [isVisible, bounds, checkMousePosition]);
3927
+ return null;
3312
3928
  }
3313
3929
 
3314
3930
  // src/hooks/useSafeTriangle.ts
3315
- import { useState as useState9, useRef as useRef9, useCallback as useCallback9, useEffect as useEffect9 } from "react";
3931
+ import { useState as useState10, useRef as useRef11, useCallback as useCallback12, useEffect as useEffect11 } from "react";
3316
3932
  function useSafeTriangle(options = {}) {
3317
3933
  const { showDelay = 0, hideDelay = 150, enabled = true } = options;
3318
- const [isVisible, setIsVisible] = useState9(false);
3319
- const [isHovering, setIsHovering] = useState9(false);
3320
- const triggerRef = useRef9(null);
3321
- const popoverRef = useRef9(null);
3322
- const showTimeoutRef = useRef9(null);
3323
- const hideTimeoutRef = useRef9(null);
3324
- useEffect9(() => {
3934
+ const [isVisible, setIsVisible] = useState10(false);
3935
+ const [isHovering, setIsHovering] = useState10(false);
3936
+ const triggerRef = useRef11(null);
3937
+ const popoverRef = useRef11(null);
3938
+ const showTimeoutRef = useRef11(null);
3939
+ const hideTimeoutRef = useRef11(null);
3940
+ useEffect11(() => {
3325
3941
  return () => {
3326
3942
  if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
3327
3943
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
3328
3944
  };
3329
3945
  }, []);
3330
- const show = useCallback9(() => {
3946
+ const show = useCallback12(() => {
3331
3947
  if (!enabled) return;
3332
3948
  if (hideTimeoutRef.current) {
3333
3949
  clearTimeout(hideTimeoutRef.current);
@@ -3335,7 +3951,7 @@ function useSafeTriangle(options = {}) {
3335
3951
  }
3336
3952
  setIsVisible(true);
3337
3953
  }, [enabled]);
3338
- const hide = useCallback9(() => {
3954
+ const hide = useCallback12(() => {
3339
3955
  if (showTimeoutRef.current) {
3340
3956
  clearTimeout(showTimeoutRef.current);
3341
3957
  showTimeoutRef.current = null;
@@ -3343,7 +3959,7 @@ function useSafeTriangle(options = {}) {
3343
3959
  setIsVisible(false);
3344
3960
  setIsHovering(false);
3345
3961
  }, []);
3346
- const handleMouseEnter = useCallback9(() => {
3962
+ const handleMouseEnter = useCallback12(() => {
3347
3963
  if (!enabled) return;
3348
3964
  setIsHovering(true);
3349
3965
  if (hideTimeoutRef.current) {
@@ -3358,7 +3974,7 @@ function useSafeTriangle(options = {}) {
3358
3974
  setIsVisible(true);
3359
3975
  }
3360
3976
  }, [showDelay, enabled]);
3361
- const handleMouseLeave = useCallback9(() => {
3977
+ const handleMouseLeave = useCallback12(() => {
3362
3978
  setIsHovering(false);
3363
3979
  if (showTimeoutRef.current) {
3364
3980
  clearTimeout(showTimeoutRef.current);
@@ -3368,15 +3984,21 @@ function useSafeTriangle(options = {}) {
3368
3984
  setIsVisible(false);
3369
3985
  }, hideDelay);
3370
3986
  }, [hideDelay]);
3371
- const handleFocus = useCallback9(() => {
3987
+ const handleFocus = useCallback12(() => {
3372
3988
  if (!enabled) return;
3373
3989
  setIsVisible(true);
3374
3990
  }, [enabled]);
3375
- const handleTriangleLeave = useCallback9(() => {
3991
+ const handleTriangleLeave = useCallback12(() => {
3376
3992
  if (!isHovering) {
3377
3993
  setIsVisible(false);
3378
3994
  }
3379
3995
  }, [isHovering]);
3996
+ const handleStayInside = useCallback12(() => {
3997
+ if (hideTimeoutRef.current) {
3998
+ clearTimeout(hideTimeoutRef.current);
3999
+ hideTimeoutRef.current = null;
4000
+ }
4001
+ }, []);
3380
4002
  return {
3381
4003
  triggerRef,
3382
4004
  popoverRef,
@@ -3390,7 +4012,8 @@ function useSafeTriangle(options = {}) {
3390
4012
  triggerRef,
3391
4013
  popoverRef,
3392
4014
  isVisible,
3393
- onLeave: handleTriangleLeave
4015
+ onLeave: handleTriangleLeave,
4016
+ onStayInside: handleStayInside
3394
4017
  },
3395
4018
  show,
3396
4019
  hide
@@ -3398,10 +4021,10 @@ function useSafeTriangle(options = {}) {
3398
4021
  }
3399
4022
 
3400
4023
  // src/components/ya-link.css
3401
- styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n position: absolute;\n bottom: -60px;\n right: 0;\n z-index: 10;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 10;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n transform: translateX(-50%);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-link-edit-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 10;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transform: translateX(-50%);\n animation: ya-edit-popover-fade-in 0.1s ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n@keyframes ya-edit-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
4024
+ 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}\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: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n transform: translateX(-50%);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 8px;\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 transform: translateX(-50%) translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\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: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 100;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transform: translateX(-50%);\n animation: ya-edit-popover-fade-in 0.1s ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n@keyframes ya-edit-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
3402
4025
 
3403
4026
  // src/components/YaLink.tsx
3404
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
4027
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
3405
4028
  function isInternalPath(path) {
3406
4029
  if (!path) return false;
3407
4030
  if (path.startsWith("#")) return false;
@@ -3502,8 +4125,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3502
4125
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
3503
4126
  const [, navigate] = useLocation();
3504
4127
  const pages = availablePages ?? getPages();
3505
- const [sections, setSections] = useState10([]);
3506
- const [sectionsExpanded, setSectionsExpanded] = useState10(false);
4128
+ const [sections, setSections] = useState11([]);
4129
+ const [sectionsExpanded, setSectionsExpanded] = useState11(false);
3507
4130
  const textFieldId = `${fieldId}.text`;
3508
4131
  const hrefFieldId = `${fieldId}.href`;
3509
4132
  const storeText = getValue(textFieldId);
@@ -3514,14 +4137,20 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3514
4137
  const isExternal = isExternalHref(href);
3515
4138
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
3516
4139
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
3517
- const [editingMode, setEditingMode] = useState10(null);
3518
- const [originalText, setOriginalText] = useState10(text);
3519
- const [originalHref, setOriginalHref] = useState10(href);
3520
- const [currentHref, setCurrentHref] = useState10(href);
3521
- const [isExternalUrl, setIsExternalUrl] = useState10(false);
3522
- const [externalUrl, setExternalUrl] = useState10("");
3523
- const containerRef = useRef10(null);
3524
- const hrefPopoverRef = useRef10(null);
4140
+ const [editingMode, setEditingMode] = useState11(null);
4141
+ const [originalText, setOriginalText] = useState11(text);
4142
+ const [originalHref, setOriginalHref] = useState11(href);
4143
+ const [currentHref, setCurrentHref] = useState11(href);
4144
+ const [isExternalUrl, setIsExternalUrl] = useState11(false);
4145
+ const [externalUrl, setExternalUrl] = useState11("");
4146
+ const [popoverPosition, setPopoverPosition] = useState11("below");
4147
+ const containerRef = useRef12(null);
4148
+ const hrefPopoverRef = useRef12(null);
4149
+ const [actionButtonsPos, setActionButtonsPos] = useState11(null);
4150
+ const handleSaveTextRef = useRef12(() => {
4151
+ });
4152
+ const handleCancelTextRef = useRef12(() => {
4153
+ });
3525
4154
  const {
3526
4155
  popoverRef: editPopoverRef,
3527
4156
  isVisible: showEditPopover,
@@ -3533,6 +4162,22 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3533
4162
  hideDelay: 150
3534
4163
  });
3535
4164
  const triggerRef = containerRef;
4165
+ const instanceId = useId();
4166
+ useEffect12(() => {
4167
+ if (showEditPopover && mode === "inline-edit" && !editingMode) {
4168
+ window.dispatchEvent(new CustomEvent("yalink:popover-open", { detail: { id: instanceId } }));
4169
+ }
4170
+ }, [showEditPopover, mode, editingMode, instanceId]);
4171
+ useEffect12(() => {
4172
+ const handleOtherPopoverOpen = (event) => {
4173
+ const customEvent = event;
4174
+ if (customEvent.detail.id !== instanceId && showEditPopover) {
4175
+ hideEditPopover();
4176
+ }
4177
+ };
4178
+ window.addEventListener("yalink:popover-open", handleOtherPopoverOpen);
4179
+ return () => window.removeEventListener("yalink:popover-open", handleOtherPopoverOpen);
4180
+ }, [instanceId, showEditPopover, hideEditPopover]);
3536
4181
  const editor = useEditor2({
3537
4182
  extensions: [
3538
4183
  StarterKit2.configure({
@@ -3552,22 +4197,62 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3552
4197
  editorProps: {
3553
4198
  attributes: {
3554
4199
  class: "outline-none"
4200
+ },
4201
+ // Handle keyboard shortcuts at the editor level to prevent default behavior
4202
+ handleKeyDown: (_view, event) => {
4203
+ if (event.key === "Enter" && !event.shiftKey) {
4204
+ event.preventDefault();
4205
+ handleSaveTextRef.current();
4206
+ return true;
4207
+ }
4208
+ if (event.key === "Escape") {
4209
+ event.preventDefault();
4210
+ handleCancelTextRef.current();
4211
+ return true;
4212
+ }
4213
+ if ((event.metaKey || event.ctrlKey) && event.key === "s") {
4214
+ event.preventDefault();
4215
+ handleSaveTextRef.current();
4216
+ return true;
4217
+ }
4218
+ return false;
3555
4219
  }
3556
4220
  }
3557
4221
  });
3558
- useEffect10(() => {
4222
+ useEffect12(() => {
3559
4223
  if (editor && editingMode !== "text") {
3560
4224
  if (editor.getHTML() !== text) {
3561
4225
  editor.commands.setContent(text);
3562
4226
  }
3563
4227
  }
3564
4228
  }, [text, editor, editingMode]);
3565
- useEffect10(() => {
4229
+ useEffect12(() => {
3566
4230
  if (editingMode !== "link") {
3567
4231
  setCurrentHref(href);
3568
4232
  }
3569
4233
  }, [href, editingMode]);
3570
- useEffect10(() => {
4234
+ useEffect12(() => {
4235
+ if (editingMode !== "text" || !containerRef.current) {
4236
+ setActionButtonsPos(null);
4237
+ return;
4238
+ }
4239
+ const updatePosition = () => {
4240
+ if (!containerRef.current) return;
4241
+ const rect = containerRef.current.getBoundingClientRect();
4242
+ setActionButtonsPos({
4243
+ top: rect.bottom + 8,
4244
+ right: window.innerWidth - rect.right
4245
+ });
4246
+ };
4247
+ updatePosition();
4248
+ window.addEventListener("scroll", updatePosition, true);
4249
+ window.addEventListener("resize", updatePosition);
4250
+ return () => {
4251
+ window.removeEventListener("scroll", updatePosition, true);
4252
+ window.removeEventListener("resize", updatePosition);
4253
+ };
4254
+ }, [editingMode]);
4255
+ useEffect12(() => {
3571
4256
  if (editingMode !== "link") return;
3572
4257
  const handleClickOutside = (event) => {
3573
4258
  const target2 = event.target;
@@ -3581,34 +4266,51 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3581
4266
  document.addEventListener("mousedown", handleClickOutside);
3582
4267
  return () => document.removeEventListener("mousedown", handleClickOutside);
3583
4268
  }, [editingMode, originalHref]);
3584
- const handleSaveText = useCallback10(() => {
4269
+ useEffect12(() => {
4270
+ if (editingMode !== "link" || !containerRef.current) return;
4271
+ const updatePosition = () => {
4272
+ if (!containerRef.current) return;
4273
+ const rect = containerRef.current.getBoundingClientRect();
4274
+ const popoverHeight = 350;
4275
+ const spaceBelow = window.innerHeight - rect.bottom;
4276
+ const spaceAbove = rect.top;
4277
+ setPopoverPosition(spaceBelow < popoverHeight && spaceAbove > spaceBelow ? "above" : "below");
4278
+ };
4279
+ window.addEventListener("resize", updatePosition);
4280
+ return () => window.removeEventListener("resize", updatePosition);
4281
+ }, [editingMode]);
4282
+ const handleSaveText = useCallback13(() => {
3585
4283
  if (!editor) return;
3586
4284
  let html = editor.getHTML();
3587
4285
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
3588
- setValue(textFieldId, html);
4286
+ setValue(textFieldId, html, "user");
3589
4287
  saveToWorker?.(textFieldId, html);
3590
4288
  setEditingMode(null);
3591
4289
  }, [editor, textFieldId, setValue, saveToWorker]);
3592
- const handleSaveLink = useCallback10(() => {
3593
- setValue(hrefFieldId, currentHref);
4290
+ const handleSaveLink = useCallback13(() => {
4291
+ setValue(hrefFieldId, currentHref, "user");
3594
4292
  saveToWorker?.(hrefFieldId, currentHref);
3595
4293
  setEditingMode(null);
3596
4294
  setIsExternalUrl(false);
3597
4295
  setExternalUrl("");
3598
4296
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
3599
- const handleCancelText = useCallback10(() => {
4297
+ const handleCancelText = useCallback13(() => {
3600
4298
  if (editor) {
3601
4299
  editor.commands.setContent(originalText);
3602
4300
  }
3603
4301
  setEditingMode(null);
3604
4302
  }, [editor, originalText]);
3605
- const handleCancelLink = useCallback10(() => {
4303
+ const handleCancelLink = useCallback13(() => {
3606
4304
  setCurrentHref(originalHref);
3607
4305
  setEditingMode(null);
3608
4306
  setIsExternalUrl(false);
3609
4307
  setExternalUrl("");
3610
4308
  }, [originalHref]);
3611
- const handleClick = useCallback10(
4309
+ useEffect12(() => {
4310
+ handleSaveTextRef.current = handleSaveText;
4311
+ handleCancelTextRef.current = handleCancelText;
4312
+ }, [handleSaveText, handleCancelText]);
4313
+ const handleClick = useCallback13(
3612
4314
  (e) => {
3613
4315
  const selectModeEnabled = window.__builderSelectModeEnabled;
3614
4316
  if (selectModeEnabled) {
@@ -3640,22 +4342,35 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3640
4342
  },
3641
4343
  [href, navigate, onClick]
3642
4344
  );
3643
- const startEditText = useCallback10(() => {
4345
+ const startEditText = useCallback13(() => {
3644
4346
  hideEditPopover();
3645
- setEditingMode("text");
3646
- setOriginalText(text);
3647
- setTimeout(() => {
3648
- editor?.chain().focus().selectAll().run();
3649
- }, 20);
3650
- }, [text, editor, hideEditPopover]);
3651
- const startEditLink = useCallback10(() => {
4347
+ if (isIconMode) {
4348
+ window.dispatchEvent(new CustomEvent("yatext:edit-mode", {
4349
+ detail: { fieldId }
4350
+ }));
4351
+ } else {
4352
+ setEditingMode("text");
4353
+ setOriginalText(text);
4354
+ setTimeout(() => {
4355
+ editor?.chain().focus().selectAll().run();
4356
+ }, 20);
4357
+ }
4358
+ }, [text, editor, hideEditPopover, isIconMode, fieldId]);
4359
+ const startEditLink = useCallback13(() => {
3652
4360
  hideEditPopover();
3653
4361
  setEditingMode("link");
3654
4362
  setOriginalHref(href);
3655
4363
  setCurrentHref(href);
3656
4364
  setSections(discoverSectionsFromDOM());
4365
+ if (containerRef.current) {
4366
+ const rect = containerRef.current.getBoundingClientRect();
4367
+ const popoverHeight = 350;
4368
+ const spaceBelow = window.innerHeight - rect.bottom;
4369
+ const spaceAbove = rect.top;
4370
+ setPopoverPosition(spaceBelow < popoverHeight && spaceAbove > spaceBelow ? "above" : "below");
4371
+ }
3657
4372
  }, [href, hideEditPopover]);
3658
- const handleKeyDown = useCallback10(
4373
+ const handleKeyDown = useCallback13(
3659
4374
  (event) => {
3660
4375
  if (editingMode !== "text") return;
3661
4376
  if (event.key === "Enter" && !event.shiftKey) {
@@ -3676,7 +4391,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3676
4391
  },
3677
4392
  [editingMode, handleSaveText, handleCancelText]
3678
4393
  );
3679
- const handleFontSizeChange = useCallback10(
4394
+ const handleFontSizeChange = useCallback13(
3680
4395
  (e) => {
3681
4396
  if (!editor) return;
3682
4397
  const size = e.target.value;
@@ -3688,7 +4403,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3688
4403
  },
3689
4404
  [editor]
3690
4405
  );
3691
- const handleFontWeightChange = useCallback10(
4406
+ const handleFontWeightChange = useCallback13(
3692
4407
  (e) => {
3693
4408
  if (!editor) return;
3694
4409
  const weight = e.target.value;
@@ -3700,11 +4415,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3700
4415
  },
3701
4416
  [editor]
3702
4417
  );
3703
- const handlePageSelect = useCallback10((path) => {
4418
+ const handlePageSelect = useCallback13((path) => {
3704
4419
  setCurrentHref(path);
3705
4420
  setIsExternalUrl(false);
3706
4421
  }, []);
3707
- const handleExternalUrlApply = useCallback10(() => {
4422
+ const handleExternalUrlApply = useCallback13(() => {
3708
4423
  if (externalUrl) {
3709
4424
  setCurrentHref(externalUrl);
3710
4425
  }
@@ -3720,9 +4435,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3720
4435
  return attrs.fontWeight || "";
3721
4436
  };
3722
4437
  if (mode === "read-only") {
3723
- const content = isIconMode ? children : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode });
4438
+ const content = isIconMode ? children : /* @__PURE__ */ jsx14(SafeHtml, { content: text, mode });
3724
4439
  if (isInternalPath(href)) {
3725
- return /* @__PURE__ */ jsx10(
4440
+ return /* @__PURE__ */ jsx14(
3726
4441
  WouterLink,
3727
4442
  {
3728
4443
  href,
@@ -3734,7 +4449,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3734
4449
  }
3735
4450
  );
3736
4451
  }
3737
- return /* @__PURE__ */ jsx10(
4452
+ return /* @__PURE__ */ jsx14(
3738
4453
  Component,
3739
4454
  {
3740
4455
  ref: containerRef,
@@ -3749,8 +4464,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3749
4464
  }
3750
4465
  );
3751
4466
  }
3752
- return /* @__PURE__ */ jsxs5("span", { className: "ya-link-wrapper", children: [
3753
- /* @__PURE__ */ jsx10(
4467
+ return /* @__PURE__ */ jsxs8("span", { className: "ya-link-wrapper", children: [
4468
+ /* @__PURE__ */ jsx14(
3754
4469
  Component,
3755
4470
  {
3756
4471
  ref: containerRef,
@@ -3769,38 +4484,38 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3769
4484
  children: isIconMode ? (
3770
4485
  // Icon mode: render children directly, no text editing
3771
4486
  children
3772
- ) : editor ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
4487
+ ) : editor ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
3773
4488
  createPortal5(
3774
- /* @__PURE__ */ jsxs5(
3775
- BubbleMenu2,
4489
+ /* @__PURE__ */ jsxs8(
4490
+ BubbleMenu,
3776
4491
  {
3777
4492
  editor,
3778
4493
  shouldShow: () => editingMode === "text",
3779
4494
  options: { offset: 6, placement: "top" },
3780
4495
  className: "ya-bubble-menu",
3781
4496
  children: [
3782
- /* @__PURE__ */ jsx10(
4497
+ /* @__PURE__ */ jsx14(
3783
4498
  "button",
3784
4499
  {
3785
4500
  type: "button",
3786
4501
  onClick: () => editor.chain().focus().toggleBold().run(),
3787
4502
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
3788
4503
  title: "Bold",
3789
- children: /* @__PURE__ */ jsx10("strong", { children: "B" })
4504
+ children: /* @__PURE__ */ jsx14("strong", { children: "B" })
3790
4505
  }
3791
4506
  ),
3792
- /* @__PURE__ */ jsx10(
4507
+ /* @__PURE__ */ jsx14(
3793
4508
  "button",
3794
4509
  {
3795
4510
  type: "button",
3796
4511
  onClick: () => editor.chain().focus().toggleItalic().run(),
3797
4512
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
3798
4513
  title: "Italic",
3799
- children: /* @__PURE__ */ jsx10("em", { children: "I" })
4514
+ children: /* @__PURE__ */ jsx14("em", { children: "I" })
3800
4515
  }
3801
4516
  ),
3802
- /* @__PURE__ */ jsx10("span", { className: "ya-bubble-divider" }),
3803
- /* @__PURE__ */ jsxs5(
4517
+ /* @__PURE__ */ jsx14("span", { className: "ya-bubble-divider" }),
4518
+ /* @__PURE__ */ jsxs8(
3804
4519
  "select",
3805
4520
  {
3806
4521
  value: getCurrentFontSize(),
@@ -3808,12 +4523,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3808
4523
  className: "ya-bubble-select",
3809
4524
  title: "Font Size",
3810
4525
  children: [
3811
- /* @__PURE__ */ jsx10("option", { value: "", children: "Size" }),
3812
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx10("option", { value: size, children: name }, name))
4526
+ /* @__PURE__ */ jsx14("option", { value: "", children: "Size" }),
4527
+ Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx14("option", { value: size, children: name }, name))
3813
4528
  ]
3814
4529
  }
3815
4530
  ),
3816
- /* @__PURE__ */ jsxs5(
4531
+ /* @__PURE__ */ jsxs8(
3817
4532
  "select",
3818
4533
  {
3819
4534
  value: getCurrentFontWeight(),
@@ -3821,8 +4536,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3821
4536
  className: "ya-bubble-select",
3822
4537
  title: "Font Weight",
3823
4538
  children: [
3824
- /* @__PURE__ */ jsx10("option", { value: "", children: "Weight" }),
3825
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx10("option", { value: weight, children: name }, name))
4539
+ /* @__PURE__ */ jsx14("option", { value: "", children: "Weight" }),
4540
+ Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx14("option", { value: weight, children: name }, name))
3826
4541
  ]
3827
4542
  }
3828
4543
  )
@@ -3831,17 +4546,31 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3831
4546
  ),
3832
4547
  document.body
3833
4548
  ),
3834
- editingMode === "text" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3835
- /* @__PURE__ */ jsx10(EditorContent2, { editor }),
3836
- /* @__PURE__ */ jsxs5("div", { className: "ya-link-actions", children: [
3837
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
3838
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
3839
- ] })
3840
- ] }) : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode })
3841
- ] }) : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode })
4549
+ editingMode === "text" ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
4550
+ /* @__PURE__ */ jsx14(EditorContent2, { editor }),
4551
+ actionButtonsPos && createPortal5(
4552
+ /* @__PURE__ */ jsxs8(
4553
+ "div",
4554
+ {
4555
+ className: "ya-link-actions",
4556
+ style: {
4557
+ position: "fixed",
4558
+ top: actionButtonsPos.top,
4559
+ right: actionButtonsPos.right
4560
+ },
4561
+ children: [
4562
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
4563
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
4564
+ ]
4565
+ }
4566
+ ),
4567
+ document.body
4568
+ )
4569
+ ] }) : /* @__PURE__ */ jsx14(SafeHtml, { content: text, mode })
4570
+ ] }) : /* @__PURE__ */ jsx14(SafeHtml, { content: text, mode })
3842
4571
  }
3843
4572
  ),
3844
- showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs5(
4573
+ showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs8(
3845
4574
  "div",
3846
4575
  {
3847
4576
  ref: editPopoverRef,
@@ -3849,39 +4578,40 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3849
4578
  onMouseEnter: safeTriangleHandlers.onMouseEnter,
3850
4579
  onMouseLeave: safeTriangleHandlers.onMouseLeave,
3851
4580
  children: [
3852
- !isIconMode && /* @__PURE__ */ jsx10("button", { type: "button", onClick: startEditText, children: "Edit text" }),
3853
- /* @__PURE__ */ jsx10("button", { type: "button", onClick: startEditLink, children: "Edit link" })
4581
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: startEditText, children: "Edit text" }),
4582
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: startEditLink, children: "Edit link" })
3854
4583
  ]
3855
4584
  }
3856
4585
  ),
3857
- /* @__PURE__ */ jsx10(
4586
+ /* @__PURE__ */ jsx14(
3858
4587
  SafeTriangleBelow,
3859
4588
  {
3860
4589
  triggerRef,
3861
4590
  popoverRef: editPopoverRef,
3862
4591
  isVisible: showEditPopover && !editingMode && mode === "inline-edit",
3863
- onLeave: triangleProps.onLeave
4592
+ onLeave: triangleProps.onLeave,
4593
+ onStayInside: triangleProps.onStayInside
3864
4594
  }
3865
4595
  ),
3866
- editingMode === "link" && /* @__PURE__ */ jsxs5("div", { ref: hrefPopoverRef, className: "ya-href-popover", children: [
3867
- /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-header", children: "Link destination" }),
3868
- !isExternalUrl ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3869
- sections.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3870
- /* @__PURE__ */ jsxs5(
4596
+ editingMode === "link" && /* @__PURE__ */ jsxs8("div", { ref: hrefPopoverRef, className: `ya-href-popover ${popoverPosition === "above" ? "ya-href-popover--above" : ""}`, children: [
4597
+ /* @__PURE__ */ jsx14("div", { className: "ya-href-popover-header", children: "Link destination" }),
4598
+ !isExternalUrl ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
4599
+ sections.length > 0 && /* @__PURE__ */ jsxs8("div", { className: "ya-href-popover-section", children: [
4600
+ /* @__PURE__ */ jsxs8(
3871
4601
  "button",
3872
4602
  {
3873
4603
  type: "button",
3874
4604
  className: "ya-href-popover-label ya-href-collapsible-header",
3875
4605
  onClick: () => setSectionsExpanded(!sectionsExpanded),
3876
4606
  children: [
3877
- /* @__PURE__ */ jsx10("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
4607
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3878
4608
  "Scroll to section (",
3879
4609
  sections.length,
3880
4610
  ")"
3881
4611
  ]
3882
4612
  }
3883
4613
  ),
3884
- sectionsExpanded && /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs5(
4614
+ sectionsExpanded && /* @__PURE__ */ jsx14("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs8(
3885
4615
  "button",
3886
4616
  {
3887
4617
  type: "button",
@@ -3889,15 +4619,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3889
4619
  onClick: () => handlePageSelect(section.path),
3890
4620
  children: [
3891
4621
  section.label,
3892
- /* @__PURE__ */ jsx10("span", { className: "ya-href-page-path", children: section.path })
4622
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-page-path", children: section.path })
3893
4623
  ]
3894
4624
  },
3895
4625
  section.path
3896
4626
  )) })
3897
4627
  ] }),
3898
- pages.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3899
- /* @__PURE__ */ jsx10("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
3900
- /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs5(
4628
+ pages.length > 0 && /* @__PURE__ */ jsxs8("div", { className: "ya-href-popover-section", children: [
4629
+ /* @__PURE__ */ jsx14("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
4630
+ /* @__PURE__ */ jsx14("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs8(
3901
4631
  "button",
3902
4632
  {
3903
4633
  type: "button",
@@ -3905,13 +4635,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3905
4635
  onClick: () => handlePageSelect(page.path),
3906
4636
  children: [
3907
4637
  page.label,
3908
- /* @__PURE__ */ jsx10("span", { className: "ya-href-page-path", children: page.path })
4638
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-page-path", children: page.path })
3909
4639
  ]
3910
4640
  },
3911
4641
  page.path
3912
4642
  )) })
3913
4643
  ] }),
3914
- /* @__PURE__ */ jsx10(
4644
+ /* @__PURE__ */ jsx14(
3915
4645
  "button",
3916
4646
  {
3917
4647
  type: "button",
@@ -3923,10 +4653,10 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3923
4653
  children: "Use external URL instead"
3924
4654
  }
3925
4655
  )
3926
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3927
- /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3928
- /* @__PURE__ */ jsx10("label", { className: "ya-href-popover-label", children: "External URL" }),
3929
- /* @__PURE__ */ jsx10(
4656
+ ] }) : /* @__PURE__ */ jsxs8(Fragment4, { children: [
4657
+ /* @__PURE__ */ jsxs8("div", { className: "ya-href-popover-section", children: [
4658
+ /* @__PURE__ */ jsx14("label", { className: "ya-href-popover-label", children: "External URL" }),
4659
+ /* @__PURE__ */ jsx14(
3930
4660
  "input",
3931
4661
  {
3932
4662
  type: "url",
@@ -3938,25 +4668,34 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3938
4668
  }
3939
4669
  )
3940
4670
  ] }),
3941
- /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
4671
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
3942
4672
  ] }),
3943
- /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-actions", children: [
3944
- /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
3945
- isExternalUrl ? /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
4673
+ /* @__PURE__ */ jsxs8("div", { className: "ya-href-popover-actions", children: [
4674
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
4675
+ isExternalUrl ? /* @__PURE__ */ jsx14("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx14("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
3946
4676
  ] })
3947
4677
  ] })
3948
4678
  ] });
3949
4679
  }
3950
4680
 
3951
4681
  // src/components/YaContainer.tsx
3952
- import { useCallback as useCallback11, useEffect as useEffect11, useRef as useRef11, useState as useState11 } from "react";
4682
+ import { useCallback as useCallback14, useEffect as useEffect13, useRef as useRef13, useState as useState12 } from "react";
3953
4683
  import { createPortal as createPortal6 } from "react-dom";
4684
+ import {
4685
+ useFloating as useFloating3,
4686
+ useHover,
4687
+ useInteractions as useInteractions2,
4688
+ offset as offset3,
4689
+ flip as flip3,
4690
+ shift as shift3,
4691
+ FloatingPortal as FloatingPortal2
4692
+ } from "@floating-ui/react";
3954
4693
 
3955
4694
  // src/components/ya-container.css
3956
- 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}\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: 32px;\n height: 32px;\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: 16px;\n height: 16px;\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}\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');
4695
+ 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');
3957
4696
 
3958
4697
  // src/components/YaContainer.tsx
3959
- import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
4698
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
3960
4699
  function parseBackgroundConfig(value) {
3961
4700
  if (!value) {
3962
4701
  return { type: "none" };
@@ -3998,8 +4737,60 @@ function deriveContainerLabel(element) {
3998
4737
  return tagLabels[tagName] || "Section";
3999
4738
  }
4000
4739
  function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearClick, hasBackground }) {
4001
- const [position, setPosition] = useState11(null);
4002
- useEffect11(() => {
4740
+ const [position, setPosition] = useState12(null);
4741
+ const [imageOpen, setImageOpen] = useState12(false);
4742
+ const [colorOpen, setColorOpen] = useState12(false);
4743
+ const [aiOpen, setAiOpen] = useState12(false);
4744
+ const [clearOpen, setClearOpen] = useState12(false);
4745
+ const {
4746
+ refs: imageRefs,
4747
+ floatingStyles: imageStyles,
4748
+ context: imageContext
4749
+ } = useFloating3({
4750
+ open: imageOpen,
4751
+ onOpenChange: setImageOpen,
4752
+ middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
4753
+ placement: "bottom"
4754
+ });
4755
+ const imageHover = useHover(imageContext, { delay: { open: 0, close: 0 } });
4756
+ const { getReferenceProps: getImageRefProps, getFloatingProps: getImageFloatProps } = useInteractions2([imageHover]);
4757
+ const {
4758
+ refs: colorRefs,
4759
+ floatingStyles: colorStyles,
4760
+ context: colorContext
4761
+ } = useFloating3({
4762
+ open: colorOpen,
4763
+ onOpenChange: setColorOpen,
4764
+ middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
4765
+ placement: "bottom"
4766
+ });
4767
+ const colorHover = useHover(colorContext, { delay: { open: 0, close: 0 } });
4768
+ const { getReferenceProps: getColorRefProps, getFloatingProps: getColorFloatProps } = useInteractions2([colorHover]);
4769
+ const {
4770
+ refs: aiRefs,
4771
+ floatingStyles: aiStyles,
4772
+ context: aiContext
4773
+ } = useFloating3({
4774
+ open: aiOpen,
4775
+ onOpenChange: setAiOpen,
4776
+ middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
4777
+ placement: "bottom"
4778
+ });
4779
+ const aiHover = useHover(aiContext, { delay: { open: 0, close: 0 } });
4780
+ const { getReferenceProps: getAiRefProps, getFloatingProps: getAiFloatProps } = useInteractions2([aiHover]);
4781
+ const {
4782
+ refs: clearRefs,
4783
+ floatingStyles: clearStyles,
4784
+ context: clearContext
4785
+ } = useFloating3({
4786
+ open: clearOpen,
4787
+ onOpenChange: setClearOpen,
4788
+ middleware: [offset3(8), flip3(), shift3({ padding: 10 })],
4789
+ placement: "bottom"
4790
+ });
4791
+ const clearHover = useHover(clearContext, { delay: { open: 0, close: 0 } });
4792
+ const { getReferenceProps: getClearRefProps, getFloatingProps: getClearFloatProps } = useInteractions2([clearHover]);
4793
+ useEffect13(() => {
4003
4794
  const updatePosition = () => {
4004
4795
  if (containerRef.current) {
4005
4796
  const rect = containerRef.current.getBoundingClientRect();
@@ -4019,7 +4810,7 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
4019
4810
  }, [containerRef]);
4020
4811
  if (!position) return null;
4021
4812
  return createPortal6(
4022
- /* @__PURE__ */ jsxs6(
4813
+ /* @__PURE__ */ jsxs9(
4023
4814
  "div",
4024
4815
  {
4025
4816
  className: "ya-container-toolbar",
@@ -4030,60 +4821,106 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
4030
4821
  },
4031
4822
  onClick: (e) => e.stopPropagation(),
4032
4823
  children: [
4033
- /* @__PURE__ */ jsx11(
4824
+ /* @__PURE__ */ jsx15(
4034
4825
  "button",
4035
4826
  {
4827
+ ref: imageRefs.setReference,
4036
4828
  type: "button",
4037
4829
  onClick: onImageClick,
4038
4830
  "aria-label": "Edit background image",
4039
- title: "Background Image",
4040
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4041
- /* @__PURE__ */ jsx11("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
4042
- /* @__PURE__ */ jsx11("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
4043
- /* @__PURE__ */ jsx11("polyline", { points: "21 15 16 10 5 21" })
4831
+ ...getImageRefProps(),
4832
+ children: /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4833
+ /* @__PURE__ */ jsx15("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
4834
+ /* @__PURE__ */ jsx15("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
4835
+ /* @__PURE__ */ jsx15("polyline", { points: "21 15 16 10 5 21" })
4044
4836
  ] })
4045
4837
  }
4046
4838
  ),
4047
- /* @__PURE__ */ jsx11(
4839
+ imageOpen && /* @__PURE__ */ jsx15(FloatingPortal2, { children: /* @__PURE__ */ jsx15(
4840
+ "div",
4841
+ {
4842
+ ref: imageRefs.setFloating,
4843
+ className: "ya-container-tooltip",
4844
+ style: imageStyles,
4845
+ ...getImageFloatProps(),
4846
+ children: "Background Image"
4847
+ }
4848
+ ) }),
4849
+ /* @__PURE__ */ jsx15(
4048
4850
  "button",
4049
4851
  {
4852
+ ref: colorRefs.setReference,
4050
4853
  type: "button",
4051
4854
  onClick: onColorClick,
4052
4855
  "aria-label": "Edit background color",
4053
- title: "Background Color",
4054
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4055
- /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "10" }),
4056
- /* @__PURE__ */ jsx11("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
4856
+ ...getColorRefProps(),
4857
+ children: /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4858
+ /* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "10" }),
4859
+ /* @__PURE__ */ jsx15("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
4057
4860
  ] })
4058
4861
  }
4059
4862
  ),
4060
- /* @__PURE__ */ jsx11(
4863
+ colorOpen && /* @__PURE__ */ jsx15(FloatingPortal2, { children: /* @__PURE__ */ jsx15(
4864
+ "div",
4865
+ {
4866
+ ref: colorRefs.setFloating,
4867
+ className: "ya-container-tooltip",
4868
+ style: colorStyles,
4869
+ ...getColorFloatProps(),
4870
+ children: "Background Color"
4871
+ }
4872
+ ) }),
4873
+ /* @__PURE__ */ jsx15(
4061
4874
  "button",
4062
4875
  {
4876
+ ref: aiRefs.setReference,
4063
4877
  type: "button",
4064
4878
  onClick: onAIClick,
4065
4879
  "aria-label": "Ask AI for help",
4066
- title: "AI Assist",
4067
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4068
- /* @__PURE__ */ jsx11("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
4069
- /* @__PURE__ */ jsx11("path", { d: "M2 17l10 5 10-5" }),
4070
- /* @__PURE__ */ jsx11("path", { d: "M2 12l10 5 10-5" })
4880
+ ...getAiRefProps(),
4881
+ children: /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4882
+ /* @__PURE__ */ jsx15("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
4883
+ /* @__PURE__ */ jsx15("path", { d: "M2 17l10 5 10-5" }),
4884
+ /* @__PURE__ */ jsx15("path", { d: "M2 12l10 5 10-5" })
4071
4885
  ] })
4072
4886
  }
4073
4887
  ),
4074
- hasBackground && /* @__PURE__ */ jsx11(
4075
- "button",
4888
+ aiOpen && /* @__PURE__ */ jsx15(FloatingPortal2, { children: /* @__PURE__ */ jsx15(
4889
+ "div",
4076
4890
  {
4077
- type: "button",
4078
- onClick: onClearClick,
4079
- "aria-label": "Clear background",
4080
- title: "Clear Background",
4081
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4082
- /* @__PURE__ */ jsx11("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4083
- /* @__PURE__ */ jsx11("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4084
- ] })
4891
+ ref: aiRefs.setFloating,
4892
+ className: "ya-container-tooltip",
4893
+ style: aiStyles,
4894
+ ...getAiFloatProps(),
4895
+ children: "AI Assist"
4085
4896
  }
4086
- )
4897
+ ) }),
4898
+ hasBackground && /* @__PURE__ */ jsxs9(Fragment5, { children: [
4899
+ /* @__PURE__ */ jsx15(
4900
+ "button",
4901
+ {
4902
+ ref: clearRefs.setReference,
4903
+ type: "button",
4904
+ onClick: onClearClick,
4905
+ "aria-label": "Clear background",
4906
+ ...getClearRefProps(),
4907
+ children: /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
4908
+ /* @__PURE__ */ jsx15("circle", { cx: "12", cy: "12", r: "10" }),
4909
+ /* @__PURE__ */ jsx15("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
4910
+ ] })
4911
+ }
4912
+ ),
4913
+ clearOpen && /* @__PURE__ */ jsx15(FloatingPortal2, { children: /* @__PURE__ */ jsx15(
4914
+ "div",
4915
+ {
4916
+ ref: clearRefs.setFloating,
4917
+ className: "ya-container-tooltip",
4918
+ style: clearStyles,
4919
+ ...getClearFloatProps(),
4920
+ children: "Remove Background"
4921
+ }
4922
+ ) })
4923
+ ] })
4087
4924
  ]
4088
4925
  }
4089
4926
  ),
@@ -4099,11 +4936,33 @@ function YaContainer({
4099
4936
  defaultBackground
4100
4937
  }) {
4101
4938
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
4102
- const containerRef = useRef11(null);
4103
- const [isHovered, setIsHovered] = useState11(false);
4104
- const [isSelected, setIsSelected] = useState11(false);
4105
- const [isDropMode, setIsDropMode] = useState11(false);
4106
- const [isDropHover, setIsDropHover] = useState11(false);
4939
+ const containerRef = useRef13(null);
4940
+ const [isHovered, setIsHovered] = useState12(false);
4941
+ const [isSelected, setIsSelected] = useState12(false);
4942
+ const [isDropMode, setIsDropMode] = useState12(false);
4943
+ const [isDropHover, setIsDropHover] = useState12(false);
4944
+ useEffect13(() => {
4945
+ if (mode !== "inline-edit") return;
4946
+ const containerEl = containerRef.current;
4947
+ if (!containerEl) return;
4948
+ let lastHovered = false;
4949
+ let lastCheckTime = 0;
4950
+ const THROTTLE_MS = 16;
4951
+ const checkMousePosition = (e) => {
4952
+ const now = performance.now();
4953
+ if (now - lastCheckTime < THROTTLE_MS) return;
4954
+ lastCheckTime = now;
4955
+ const rect = containerEl.getBoundingClientRect();
4956
+ const { clientX: x, clientY: y } = e;
4957
+ const isInside = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
4958
+ if (isInside !== lastHovered) {
4959
+ lastHovered = isInside;
4960
+ setIsHovered(isInside);
4961
+ }
4962
+ };
4963
+ window.addEventListener("mousemove", checkMousePosition, { passive: true });
4964
+ return () => window.removeEventListener("mousemove", checkMousePosition);
4965
+ }, [mode]);
4107
4966
  const rawValue = getValue(fieldId);
4108
4967
  const backgroundConfig = rawValue ? parseBackgroundConfig(rawValue) : defaultBackground || { type: "none" };
4109
4968
  const hasBackground = backgroundConfig.type !== "none";
@@ -4124,7 +4983,7 @@ function YaContainer({
4124
4983
  overlayCustomProps["--ya-overlay-color"] = backgroundConfig.overlay.color;
4125
4984
  overlayCustomProps["--ya-overlay-opacity"] = backgroundConfig.overlay.opacity;
4126
4985
  }
4127
- const handleImageClick = useCallback11(() => {
4986
+ const handleImageClick = useCallback14(() => {
4128
4987
  if (mode !== "inline-edit") return;
4129
4988
  setIsSelected(true);
4130
4989
  const rect = containerRef.current?.getBoundingClientRect();
@@ -4144,7 +5003,7 @@ function YaContainer({
4144
5003
  "*"
4145
5004
  );
4146
5005
  }, [mode, fieldId, backgroundConfig]);
4147
- const handleColorClick = useCallback11(() => {
5006
+ const handleColorClick = useCallback14(() => {
4148
5007
  if (mode !== "inline-edit") return;
4149
5008
  setIsSelected(true);
4150
5009
  const rect = containerRef.current?.getBoundingClientRect();
@@ -4164,7 +5023,7 @@ function YaContainer({
4164
5023
  "*"
4165
5024
  );
4166
5025
  }, [mode, fieldId, backgroundConfig]);
4167
- const handleAIClick = useCallback11(() => {
5026
+ const handleAIClick = useCallback14(() => {
4168
5027
  if (mode !== "inline-edit") return;
4169
5028
  const label = deriveContainerLabel(containerRef.current);
4170
5029
  window.parent.postMessage(
@@ -4177,14 +5036,14 @@ function YaContainer({
4177
5036
  "*"
4178
5037
  );
4179
5038
  }, [mode, fieldId, backgroundConfig]);
4180
- const handleClearClick = useCallback11(() => {
5039
+ const handleClearClick = useCallback14(() => {
4181
5040
  if (mode !== "inline-edit") return;
4182
5041
  const clearedConfig = { type: "none" };
4183
5042
  const serialized = serializeBackgroundConfig(clearedConfig);
4184
5043
  setValue(fieldId, serialized);
4185
5044
  saveToWorker?.(fieldId, serialized);
4186
5045
  }, [mode, fieldId, setValue, saveToWorker]);
4187
- useEffect11(() => {
5046
+ useEffect13(() => {
4188
5047
  if (mode !== "inline-edit") return;
4189
5048
  const handleMessage2 = (event) => {
4190
5049
  if (event.data?.type === "YA_CONTAINER_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4197,7 +5056,7 @@ function YaContainer({
4197
5056
  window.addEventListener("message", handleMessage2);
4198
5057
  return () => window.removeEventListener("message", handleMessage2);
4199
5058
  }, [mode, fieldId]);
4200
- useEffect11(() => {
5059
+ useEffect13(() => {
4201
5060
  if (mode !== "inline-edit") return;
4202
5061
  const handleDropModeMessage = (event) => {
4203
5062
  if (event.data?.type === "DROP_MODE_START") {
@@ -4211,7 +5070,7 @@ function YaContainer({
4211
5070
  window.addEventListener("message", handleDropModeMessage);
4212
5071
  return () => window.removeEventListener("message", handleDropModeMessage);
4213
5072
  }, [mode]);
4214
- const handleDragEnter = useCallback11(
5073
+ const handleDragEnter = useCallback14(
4215
5074
  (e) => {
4216
5075
  if (!isDropMode) return;
4217
5076
  e.preventDefault();
@@ -4235,7 +5094,7 @@ function YaContainer({
4235
5094
  },
4236
5095
  [isDropMode, fieldId]
4237
5096
  );
4238
- const handleDragOver = useCallback11(
5097
+ const handleDragOver = useCallback14(
4239
5098
  (e) => {
4240
5099
  if (!isDropMode) return;
4241
5100
  e.preventDefault();
@@ -4243,7 +5102,7 @@ function YaContainer({
4243
5102
  },
4244
5103
  [isDropMode]
4245
5104
  );
4246
- const handleDragLeave = useCallback11(
5105
+ const handleDragLeave = useCallback14(
4247
5106
  (e) => {
4248
5107
  if (!isDropMode) return;
4249
5108
  e.preventDefault();
@@ -4257,7 +5116,7 @@ function YaContainer({
4257
5116
  },
4258
5117
  [isDropMode]
4259
5118
  );
4260
- const handleDrop = useCallback11(
5119
+ const handleDrop = useCallback14(
4261
5120
  (e) => {
4262
5121
  if (!isDropMode) return;
4263
5122
  e.preventDefault();
@@ -4275,7 +5134,7 @@ function YaContainer({
4275
5134
  },
4276
5135
  [isDropMode, fieldId]
4277
5136
  );
4278
- useEffect11(() => {
5137
+ useEffect13(() => {
4279
5138
  if (!isSelected || mode !== "inline-edit") return;
4280
5139
  let lastRectKey = "";
4281
5140
  let lastTime = 0;
@@ -4310,7 +5169,7 @@ function YaContainer({
4310
5169
  return () => cancelAnimationFrame(rafId);
4311
5170
  }, [isSelected, fieldId, mode]);
4312
5171
  if (mode === "read-only") {
4313
- return /* @__PURE__ */ jsx11(
5172
+ return /* @__PURE__ */ jsx15(
4314
5173
  Tag,
4315
5174
  {
4316
5175
  className: `ya-container ${className || ""}`,
@@ -4334,7 +5193,7 @@ function YaContainer({
4334
5193
  isDropHover ? "ya-container-drop-hover" : "",
4335
5194
  className || ""
4336
5195
  ].filter(Boolean).join(" ");
4337
- return /* @__PURE__ */ jsxs6(
5196
+ return /* @__PURE__ */ jsxs9(
4338
5197
  Tag,
4339
5198
  {
4340
5199
  ref: containerRef,
@@ -4347,15 +5206,13 @@ function YaContainer({
4347
5206
  "data-ya-restricted": "true",
4348
5207
  "data-field-id": fieldId,
4349
5208
  "data-ya-container": "true",
4350
- onMouseEnter: () => setIsHovered(true),
4351
- onMouseLeave: () => setIsHovered(false),
4352
5209
  onDragEnter: handleDragEnter,
4353
5210
  onDragOver: handleDragOver,
4354
5211
  onDragLeave: handleDragLeave,
4355
5212
  onDrop: handleDrop,
4356
5213
  children: [
4357
5214
  children,
4358
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx11(
5215
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx15(
4359
5216
  Toolbar,
4360
5217
  {
4361
5218
  containerRef,
@@ -4372,10 +5229,10 @@ function YaContainer({
4372
5229
  }
4373
5230
 
4374
5231
  // src/components/StaticText.tsx
4375
- import { jsx as jsx12 } from "react/jsx-runtime";
5232
+ import { jsx as jsx16 } from "react/jsx-runtime";
4376
5233
  function MpText({ fieldId, className, as: Component = "span", children }) {
4377
5234
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
4378
- return /* @__PURE__ */ jsx12(
5235
+ return /* @__PURE__ */ jsx16(
4379
5236
  Component,
4380
5237
  {
4381
5238
  className,
@@ -4386,7 +5243,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
4386
5243
  }
4387
5244
 
4388
5245
  // src/components/StaticImage.tsx
4389
- import { jsx as jsx13 } from "react/jsx-runtime";
5246
+ import { jsx as jsx17 } from "react/jsx-runtime";
4390
5247
  function parseImageValue2(value) {
4391
5248
  if (!value) {
4392
5249
  return { src: "" };
@@ -4422,7 +5279,7 @@ function MpImage({
4422
5279
  const altText = imageData.alt || alt || fallbackAlt || "";
4423
5280
  const objectFit = imageData.objectFit || propObjectFit || "cover";
4424
5281
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
4425
- return /* @__PURE__ */ jsx13(
5282
+ return /* @__PURE__ */ jsx17(
4426
5283
  "img",
4427
5284
  {
4428
5285
  src: resolveAssetUrl(src),
@@ -4439,8 +5296,8 @@ function MpImage({
4439
5296
  }
4440
5297
 
4441
5298
  // src/components/MarkdownText.tsx
4442
- import { Fragment as Fragment4 } from "react";
4443
- import { jsx as jsx14 } from "react/jsx-runtime";
5299
+ import { Fragment as Fragment6 } from "react";
5300
+ import { jsx as jsx18 } from "react/jsx-runtime";
4444
5301
  function tokenize(text) {
4445
5302
  const tokens = [];
4446
5303
  let remaining = text;
@@ -4502,13 +5359,13 @@ function tokensToElements(tokens) {
4502
5359
  return tokens.map((token, index) => {
4503
5360
  switch (token.type) {
4504
5361
  case "text":
4505
- return /* @__PURE__ */ jsx14(Fragment4, { children: token.content }, index);
5362
+ return /* @__PURE__ */ jsx18(Fragment6, { children: token.content }, index);
4506
5363
  case "bold":
4507
- return /* @__PURE__ */ jsx14("strong", { children: token.content }, index);
5364
+ return /* @__PURE__ */ jsx18("strong", { children: token.content }, index);
4508
5365
  case "italic":
4509
- return /* @__PURE__ */ jsx14("em", { children: token.content }, index);
5366
+ return /* @__PURE__ */ jsx18("em", { children: token.content }, index);
4510
5367
  case "link":
4511
- return /* @__PURE__ */ jsx14(
5368
+ return /* @__PURE__ */ jsx18(
4512
5369
  "a",
4513
5370
  {
4514
5371
  href: token.url,
@@ -4520,7 +5377,7 @@ function tokensToElements(tokens) {
4520
5377
  index
4521
5378
  );
4522
5379
  case "newline":
4523
- return /* @__PURE__ */ jsx14("br", {}, index);
5380
+ return /* @__PURE__ */ jsx18("br", {}, index);
4524
5381
  default:
4525
5382
  return null;
4526
5383
  }
@@ -4532,15 +5389,15 @@ function parseMarkdownToElements(content) {
4532
5389
  }
4533
5390
  function MarkdownText({ content, className }) {
4534
5391
  const elements = parseMarkdownToElements(content);
4535
- return /* @__PURE__ */ jsx14("span", { className, children: elements });
5392
+ return /* @__PURE__ */ jsx18("span", { className, children: elements });
4536
5393
  }
4537
5394
 
4538
5395
  // src/router/Link.tsx
4539
5396
  import { Link as WouterLink2 } from "wouter";
4540
- import { jsx as jsx15 } from "react/jsx-runtime";
5397
+ import { jsx as jsx19 } from "react/jsx-runtime";
4541
5398
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
4542
5399
  const target = href ?? to ?? "/";
4543
- return /* @__PURE__ */ jsx15(WouterLink2, { href: target, className, onClick, replace, ...props, children });
5400
+ return /* @__PURE__ */ jsx19(WouterLink2, { href: target, className, onClick, replace, ...props, children });
4544
5401
  }
4545
5402
 
4546
5403
  // src/router/useNavigate.ts
@@ -4559,7 +5416,7 @@ function useNavigate() {
4559
5416
 
4560
5417
  // src/router/Router.tsx
4561
5418
  import { Router as WouterRouter } from "wouter";
4562
- import { jsx as jsx16 } from "react/jsx-runtime";
5419
+ import { jsx as jsx20 } from "react/jsx-runtime";
4563
5420
  function detectBasename() {
4564
5421
  if (typeof window === "undefined") return "";
4565
5422
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -4574,7 +5431,7 @@ function detectBasename() {
4574
5431
  }
4575
5432
  function Router({ children, base }) {
4576
5433
  const basename = base ?? detectBasename();
4577
- return /* @__PURE__ */ jsx16(WouterRouter, { base: basename, children });
5434
+ return /* @__PURE__ */ jsx20(WouterRouter, { base: basename, children });
4578
5435
  }
4579
5436
 
4580
5437
  // src/router/index.ts