@yoamigo.com/core 0.2.0 → 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() {
@@ -2032,25 +2553,16 @@ var FontWeight = Extension.create({
2032
2553
  return chain().setMark("textStyle", { fontWeight: null }).removeEmptyTextStyle().run();
2033
2554
  }
2034
2555
  };
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
- };
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: "" };
@@ -2917,18 +3555,20 @@ function YaVideo({
2917
3555
  aspectRatio: propAspectRatio,
2918
3556
  objectFit: propObjectFit,
2919
3557
  loading = "lazy",
3558
+ defaultValue,
2920
3559
  fallbackSrc,
2921
3560
  fallbackPoster
2922
3561
  }) {
2923
3562
  const { getValue, mode } = useContentStore();
2924
- const containerRef = useRef8(null);
2925
- const videoRef = useRef8(null);
2926
- const [isSelected, setIsSelected] = useState7(false);
2927
- const [isHovered, setIsHovered] = useState7(false);
2928
- const [isSmallVideo, setIsSmallVideo] = useState7(false);
2929
- 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");
2930
3569
  const rawValue = getValue(fieldId);
2931
- const videoData = parseVideoValue(rawValue);
3570
+ const parsedValue = parseVideoValue(rawValue);
3571
+ const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
2932
3572
  const src = videoData.src || fallbackSrc || "";
2933
3573
  const poster = videoData.poster || fallbackPoster || "";
2934
3574
  const objectFit = videoData.objectFit || propObjectFit || "cover";
@@ -2939,8 +3579,8 @@ function YaVideo({
2939
3579
  const controls = videoData.controls ?? true;
2940
3580
  const playsinline = videoData.playsinline ?? true;
2941
3581
  const preload = videoData.preload ?? "metadata";
2942
- const [prefersReducedMotion, setPrefersReducedMotion] = useState7(false);
2943
- useEffect7(() => {
3582
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState8(false);
3583
+ useEffect9(() => {
2944
3584
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
2945
3585
  setPrefersReducedMotion(mediaQuery.matches);
2946
3586
  const handleChange = (e) => {
@@ -2950,7 +3590,7 @@ function YaVideo({
2950
3590
  return () => mediaQuery.removeEventListener("change", handleChange);
2951
3591
  }, []);
2952
3592
  const effectiveAutoplay = autoplay && !prefersReducedMotion;
2953
- useEffect7(() => {
3593
+ useEffect9(() => {
2954
3594
  if (loading === "eager" || isInView) return;
2955
3595
  const observer = new IntersectionObserver(
2956
3596
  (entries) => {
@@ -2967,7 +3607,7 @@ function YaVideo({
2967
3607
  }
2968
3608
  return () => observer.disconnect();
2969
3609
  }, [loading, isInView]);
2970
- const handleKeyDown = useCallback8(
3610
+ const handleKeyDown = useCallback10(
2971
3611
  (e) => {
2972
3612
  if ((e.key === " " || e.key === "Enter") && videoData.type === "upload" && controls) {
2973
3613
  e.preventDefault();
@@ -2983,7 +3623,7 @@ function YaVideo({
2983
3623
  },
2984
3624
  [videoData.type, controls]
2985
3625
  );
2986
- const handleClick = useCallback8(() => {
3626
+ const handleClick = useCallback10(() => {
2987
3627
  if (mode !== "inline-edit") return;
2988
3628
  if (document.body.classList.contains("builder-selector-active")) return;
2989
3629
  setIsSelected(true);
@@ -3003,7 +3643,7 @@ function YaVideo({
3003
3643
  "*"
3004
3644
  );
3005
3645
  }, [mode, fieldId, videoData]);
3006
- useEffect7(() => {
3646
+ useEffect9(() => {
3007
3647
  if (mode !== "inline-edit") return;
3008
3648
  const handleMessage2 = (event) => {
3009
3649
  if (event.data?.type === "YA_VIDEO_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -3016,7 +3656,7 @@ function YaVideo({
3016
3656
  window.addEventListener("message", handleMessage2);
3017
3657
  return () => window.removeEventListener("message", handleMessage2);
3018
3658
  }, [mode, fieldId]);
3019
- useEffect7(() => {
3659
+ useEffect9(() => {
3020
3660
  if (mode !== "inline-edit") return;
3021
3661
  const checkSize = () => {
3022
3662
  if (containerRef.current) {
@@ -3028,7 +3668,7 @@ function YaVideo({
3028
3668
  window.addEventListener("resize", checkSize);
3029
3669
  return () => window.removeEventListener("resize", checkSize);
3030
3670
  }, [mode]);
3031
- useEffect7(() => {
3671
+ useEffect9(() => {
3032
3672
  if (!isSelected || mode !== "inline-edit") return;
3033
3673
  let lastRectKey = "";
3034
3674
  let lastTime = 0;
@@ -3064,24 +3704,24 @@ function YaVideo({
3064
3704
  }, [isSelected, fieldId, mode]);
3065
3705
  const renderVideo = (isReadOnly) => {
3066
3706
  if (!src && !isReadOnly) {
3067
- return /* @__PURE__ */ jsxs4("div", { className: "ya-video-placeholder", children: [
3068
- /* @__PURE__ */ jsx8("img", { src: PLACEHOLDER_SVG2, alt: "" }),
3069
- /* @__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" })
3070
3710
  ] });
3071
3711
  }
3072
3712
  if (!isInView && loading === "lazy" && !isReadOnly) {
3073
- return /* @__PURE__ */ jsx8(
3713
+ return /* @__PURE__ */ jsx13(
3074
3714
  "div",
3075
3715
  {
3076
3716
  className: "ya-video-placeholder",
3077
3717
  style: { aspectRatio },
3078
- children: /* @__PURE__ */ jsx8("img", { src: PLACEHOLDER_SVG2, alt: "" })
3718
+ children: /* @__PURE__ */ jsx13("img", { src: PLACEHOLDER_SVG2, alt: "" })
3079
3719
  }
3080
3720
  );
3081
3721
  }
3082
3722
  if (videoData.type === "youtube" && src) {
3083
3723
  const embedUrl = buildYouTubeEmbedUrl(src, videoData);
3084
- return /* @__PURE__ */ jsx8(
3724
+ return /* @__PURE__ */ jsx13(
3085
3725
  "iframe",
3086
3726
  {
3087
3727
  src: embedUrl,
@@ -3101,7 +3741,7 @@ function YaVideo({
3101
3741
  }
3102
3742
  if (videoData.type === "vimeo" && src) {
3103
3743
  const embedUrl = buildVimeoEmbedUrl(src, videoData);
3104
- return /* @__PURE__ */ jsx8(
3744
+ return /* @__PURE__ */ jsx13(
3105
3745
  "iframe",
3106
3746
  {
3107
3747
  src: embedUrl,
@@ -3121,7 +3761,7 @@ function YaVideo({
3121
3761
  }
3122
3762
  const resolvedSrc = resolveAssetUrl(src);
3123
3763
  const resolvedPoster = poster ? resolveAssetUrl(poster) : void 0;
3124
- return /* @__PURE__ */ jsx8(
3764
+ return /* @__PURE__ */ jsx13(
3125
3765
  "video",
3126
3766
  {
3127
3767
  ref: videoRef,
@@ -3156,7 +3796,7 @@ function YaVideo({
3156
3796
  );
3157
3797
  };
3158
3798
  if (mode === "read-only") {
3159
- return /* @__PURE__ */ jsx8(
3799
+ return /* @__PURE__ */ jsx13(
3160
3800
  "div",
3161
3801
  {
3162
3802
  ref: containerRef,
@@ -3172,7 +3812,7 @@ function YaVideo({
3172
3812
  }
3173
3813
  );
3174
3814
  }
3175
- const videoIcon = /* @__PURE__ */ jsxs4(
3815
+ const videoIcon = /* @__PURE__ */ jsxs7(
3176
3816
  "svg",
3177
3817
  {
3178
3818
  width: "24",
@@ -3184,12 +3824,12 @@ function YaVideo({
3184
3824
  strokeLinecap: "round",
3185
3825
  strokeLinejoin: "round",
3186
3826
  children: [
3187
- /* @__PURE__ */ jsx8("rect", { x: "2", y: "4", width: "15", height: "13", rx: "2", ry: "2" }),
3188
- /* @__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" })
3189
3829
  ]
3190
3830
  }
3191
3831
  );
3192
- return /* @__PURE__ */ jsxs4(
3832
+ return /* @__PURE__ */ jsxs7(
3193
3833
  "div",
3194
3834
  {
3195
3835
  ref: containerRef,
@@ -3212,14 +3852,14 @@ function YaVideo({
3212
3852
  style: { aspectRatio },
3213
3853
  children: [
3214
3854
  renderVideo(false),
3215
- isSmallVideo ? /* @__PURE__ */ jsxs4(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3855
+ isSmallVideo ? /* @__PURE__ */ jsxs7(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
3216
3856
  videoIcon,
3217
- /* @__PURE__ */ jsx8("span", { children: "Click to edit" })
3857
+ /* @__PURE__ */ jsx13("span", { children: "Click to edit" })
3218
3858
  ] }) : (
3219
3859
  /* For large videos: show overlay inside the container */
3220
- /* @__PURE__ */ jsxs4("div", { className: "ya-video-overlay", children: [
3221
- /* @__PURE__ */ jsx8("div", { className: "ya-video-edit-icon", children: videoIcon }),
3222
- /* @__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" })
3223
3863
  ] })
3224
3864
  )
3225
3865
  ]
@@ -3228,20 +3868,163 @@ function YaVideo({
3228
3868
  }
3229
3869
 
3230
3870
  // src/components/YaLink.tsx
3231
- import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback9 } from "react";
3232
- import { createPortal as createPortal4 } from "react-dom";
3871
+ import { useEffect as useEffect12, useRef as useRef12, useState as useState11, useCallback as useCallback13, useId } from "react";
3872
+ import { createPortal as createPortal5 } from "react-dom";
3233
3873
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
3234
- import { BubbleMenu as BubbleMenu2 } from "@tiptap/react/menus";
3874
+ import { BubbleMenu } from "@tiptap/react/menus";
3235
3875
  import StarterKit2 from "@tiptap/starter-kit";
3236
3876
  import { TextStyle as TextStyle2 } from "@tiptap/extension-text-style";
3237
3877
  import { Extension as Extension2 } from "@tiptap/core";
3238
3878
  import { Link as WouterLink, useLocation } from "wouter";
3239
3879
 
3880
+ // src/components/SafeTriangleBelow.tsx
3881
+ import { useEffect as useEffect10, useState as useState9, useRef as useRef10, useCallback as useCallback11 } from "react";
3882
+ function SafeTriangleBelow({
3883
+ triggerRef,
3884
+ popoverRef,
3885
+ isVisible,
3886
+ onLeave,
3887
+ onStayInside
3888
+ }) {
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;
3928
+ }
3929
+
3930
+ // src/hooks/useSafeTriangle.ts
3931
+ import { useState as useState10, useRef as useRef11, useCallback as useCallback12, useEffect as useEffect11 } from "react";
3932
+ function useSafeTriangle(options = {}) {
3933
+ const { showDelay = 0, hideDelay = 150, enabled = true } = options;
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(() => {
3941
+ return () => {
3942
+ if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
3943
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
3944
+ };
3945
+ }, []);
3946
+ const show = useCallback12(() => {
3947
+ if (!enabled) return;
3948
+ if (hideTimeoutRef.current) {
3949
+ clearTimeout(hideTimeoutRef.current);
3950
+ hideTimeoutRef.current = null;
3951
+ }
3952
+ setIsVisible(true);
3953
+ }, [enabled]);
3954
+ const hide = useCallback12(() => {
3955
+ if (showTimeoutRef.current) {
3956
+ clearTimeout(showTimeoutRef.current);
3957
+ showTimeoutRef.current = null;
3958
+ }
3959
+ setIsVisible(false);
3960
+ setIsHovering(false);
3961
+ }, []);
3962
+ const handleMouseEnter = useCallback12(() => {
3963
+ if (!enabled) return;
3964
+ setIsHovering(true);
3965
+ if (hideTimeoutRef.current) {
3966
+ clearTimeout(hideTimeoutRef.current);
3967
+ hideTimeoutRef.current = null;
3968
+ }
3969
+ if (showDelay > 0) {
3970
+ showTimeoutRef.current = setTimeout(() => {
3971
+ setIsVisible(true);
3972
+ }, showDelay);
3973
+ } else {
3974
+ setIsVisible(true);
3975
+ }
3976
+ }, [showDelay, enabled]);
3977
+ const handleMouseLeave = useCallback12(() => {
3978
+ setIsHovering(false);
3979
+ if (showTimeoutRef.current) {
3980
+ clearTimeout(showTimeoutRef.current);
3981
+ showTimeoutRef.current = null;
3982
+ }
3983
+ hideTimeoutRef.current = setTimeout(() => {
3984
+ setIsVisible(false);
3985
+ }, hideDelay);
3986
+ }, [hideDelay]);
3987
+ const handleFocus = useCallback12(() => {
3988
+ if (!enabled) return;
3989
+ setIsVisible(true);
3990
+ }, [enabled]);
3991
+ const handleTriangleLeave = useCallback12(() => {
3992
+ if (!isHovering) {
3993
+ setIsVisible(false);
3994
+ }
3995
+ }, [isHovering]);
3996
+ const handleStayInside = useCallback12(() => {
3997
+ if (hideTimeoutRef.current) {
3998
+ clearTimeout(hideTimeoutRef.current);
3999
+ hideTimeoutRef.current = null;
4000
+ }
4001
+ }, []);
4002
+ return {
4003
+ triggerRef,
4004
+ popoverRef,
4005
+ isVisible,
4006
+ handlers: {
4007
+ onMouseEnter: handleMouseEnter,
4008
+ onMouseLeave: handleMouseLeave,
4009
+ onFocus: handleFocus
4010
+ },
4011
+ triangleProps: {
4012
+ triggerRef,
4013
+ popoverRef,
4014
+ isVisible,
4015
+ onLeave: handleTriangleLeave,
4016
+ onStayInside: handleStayInside
4017
+ },
4018
+ show,
4019
+ hide
4020
+ };
4021
+ }
4022
+
3240
4023
  // src/components/ya-link.css
3241
- 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');
3242
4025
 
3243
4026
  // src/components/YaLink.tsx
3244
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
4027
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
3245
4028
  function isInternalPath(path) {
3246
4029
  if (!path) return false;
3247
4030
  if (path.startsWith("#")) return false;
@@ -3342,8 +4125,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3342
4125
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
3343
4126
  const [, navigate] = useLocation();
3344
4127
  const pages = availablePages ?? getPages();
3345
- const [sections, setSections] = useState8([]);
3346
- const [sectionsExpanded, setSectionsExpanded] = useState8(false);
4128
+ const [sections, setSections] = useState11([]);
4129
+ const [sectionsExpanded, setSectionsExpanded] = useState11(false);
3347
4130
  const textFieldId = `${fieldId}.text`;
3348
4131
  const hrefFieldId = `${fieldId}.href`;
3349
4132
  const storeText = getValue(textFieldId);
@@ -3354,16 +4137,47 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3354
4137
  const isExternal = isExternalHref(href);
3355
4138
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
3356
4139
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
3357
- const [editingMode, setEditingMode] = useState8(null);
3358
- const [showEditPopover, setShowEditPopover] = useState8(false);
3359
- const [originalText, setOriginalText] = useState8(text);
3360
- const [originalHref, setOriginalHref] = useState8(href);
3361
- const [currentHref, setCurrentHref] = useState8(href);
3362
- const [isExternalUrl, setIsExternalUrl] = useState8(false);
3363
- const [externalUrl, setExternalUrl] = useState8("");
3364
- const containerRef = useRef9(null);
3365
- const hrefPopoverRef = useRef9(null);
3366
- const hidePopoverTimeoutRef = useRef9(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
+ });
4154
+ const {
4155
+ popoverRef: editPopoverRef,
4156
+ isVisible: showEditPopover,
4157
+ handlers: safeTriangleHandlers,
4158
+ triangleProps,
4159
+ hide: hideEditPopover
4160
+ } = useSafeTriangle({
4161
+ enabled: mode === "inline-edit" && !editingMode,
4162
+ hideDelay: 150
4163
+ });
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]);
3367
4181
  const editor = useEditor2({
3368
4182
  extensions: [
3369
4183
  StarterKit2.configure({
@@ -3383,29 +4197,62 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3383
4197
  editorProps: {
3384
4198
  attributes: {
3385
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;
3386
4219
  }
3387
4220
  }
3388
4221
  });
3389
- useEffect8(() => {
4222
+ useEffect12(() => {
3390
4223
  if (editor && editingMode !== "text") {
3391
4224
  if (editor.getHTML() !== text) {
3392
4225
  editor.commands.setContent(text);
3393
4226
  }
3394
4227
  }
3395
4228
  }, [text, editor, editingMode]);
3396
- useEffect8(() => {
4229
+ useEffect12(() => {
3397
4230
  if (editingMode !== "link") {
3398
4231
  setCurrentHref(href);
3399
4232
  }
3400
4233
  }, [href, editingMode]);
3401
- useEffect8(() => {
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);
3402
4250
  return () => {
3403
- if (hidePopoverTimeoutRef.current) {
3404
- clearTimeout(hidePopoverTimeoutRef.current);
3405
- }
4251
+ window.removeEventListener("scroll", updatePosition, true);
4252
+ window.removeEventListener("resize", updatePosition);
3406
4253
  };
3407
- }, []);
3408
- useEffect8(() => {
4254
+ }, [editingMode]);
4255
+ useEffect12(() => {
3409
4256
  if (editingMode !== "link") return;
3410
4257
  const handleClickOutside = (event) => {
3411
4258
  const target2 = event.target;
@@ -3419,34 +4266,51 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3419
4266
  document.addEventListener("mousedown", handleClickOutside);
3420
4267
  return () => document.removeEventListener("mousedown", handleClickOutside);
3421
4268
  }, [editingMode, originalHref]);
3422
- const handleSaveText = useCallback9(() => {
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(() => {
3423
4283
  if (!editor) return;
3424
4284
  let html = editor.getHTML();
3425
4285
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
3426
- setValue(textFieldId, html);
4286
+ setValue(textFieldId, html, "user");
3427
4287
  saveToWorker?.(textFieldId, html);
3428
4288
  setEditingMode(null);
3429
4289
  }, [editor, textFieldId, setValue, saveToWorker]);
3430
- const handleSaveLink = useCallback9(() => {
3431
- setValue(hrefFieldId, currentHref);
4290
+ const handleSaveLink = useCallback13(() => {
4291
+ setValue(hrefFieldId, currentHref, "user");
3432
4292
  saveToWorker?.(hrefFieldId, currentHref);
3433
4293
  setEditingMode(null);
3434
4294
  setIsExternalUrl(false);
3435
4295
  setExternalUrl("");
3436
4296
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
3437
- const handleCancelText = useCallback9(() => {
4297
+ const handleCancelText = useCallback13(() => {
3438
4298
  if (editor) {
3439
4299
  editor.commands.setContent(originalText);
3440
4300
  }
3441
4301
  setEditingMode(null);
3442
4302
  }, [editor, originalText]);
3443
- const handleCancelLink = useCallback9(() => {
4303
+ const handleCancelLink = useCallback13(() => {
3444
4304
  setCurrentHref(originalHref);
3445
4305
  setEditingMode(null);
3446
4306
  setIsExternalUrl(false);
3447
4307
  setExternalUrl("");
3448
4308
  }, [originalHref]);
3449
- const handleClick = useCallback9(
4309
+ useEffect12(() => {
4310
+ handleSaveTextRef.current = handleSaveText;
4311
+ handleCancelTextRef.current = handleCancelText;
4312
+ }, [handleSaveText, handleCancelText]);
4313
+ const handleClick = useCallback13(
3450
4314
  (e) => {
3451
4315
  const selectModeEnabled = window.__builderSelectModeEnabled;
3452
4316
  if (selectModeEnabled) {
@@ -3478,43 +4342,35 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3478
4342
  },
3479
4343
  [href, navigate, onClick]
3480
4344
  );
3481
- const handleMouseEnter = useCallback9(() => {
3482
- if (hidePopoverTimeoutRef.current) {
3483
- clearTimeout(hidePopoverTimeoutRef.current);
3484
- hidePopoverTimeoutRef.current = null;
3485
- }
3486
- if (mode === "inline-edit" && !editingMode) {
3487
- setShowEditPopover(true);
3488
- }
3489
- }, [mode, editingMode]);
3490
- const handleMouseLeave = useCallback9(() => {
3491
- hidePopoverTimeoutRef.current = window.setTimeout(() => {
3492
- if (!editingMode) {
3493
- setShowEditPopover(false);
3494
- }
3495
- }, 150);
3496
- }, [editingMode]);
3497
- const handleFocus = useCallback9(() => {
3498
- if (mode === "inline-edit" && !editingMode) {
3499
- setShowEditPopover(true);
3500
- }
3501
- }, [mode, editingMode]);
3502
- const startEditText = useCallback9(() => {
3503
- setShowEditPopover(false);
3504
- setEditingMode("text");
3505
- setOriginalText(text);
3506
- setTimeout(() => {
3507
- editor?.chain().focus().selectAll().run();
3508
- }, 20);
3509
- }, [text, editor]);
3510
- const startEditLink = useCallback9(() => {
3511
- setShowEditPopover(false);
4345
+ const startEditText = useCallback13(() => {
4346
+ hideEditPopover();
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(() => {
4360
+ hideEditPopover();
3512
4361
  setEditingMode("link");
3513
4362
  setOriginalHref(href);
3514
4363
  setCurrentHref(href);
3515
4364
  setSections(discoverSectionsFromDOM());
3516
- }, [href]);
3517
- const handleKeyDown = useCallback9(
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
+ }
4372
+ }, [href, hideEditPopover]);
4373
+ const handleKeyDown = useCallback13(
3518
4374
  (event) => {
3519
4375
  if (editingMode !== "text") return;
3520
4376
  if (event.key === "Enter" && !event.shiftKey) {
@@ -3535,7 +4391,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3535
4391
  },
3536
4392
  [editingMode, handleSaveText, handleCancelText]
3537
4393
  );
3538
- const handleFontSizeChange = useCallback9(
4394
+ const handleFontSizeChange = useCallback13(
3539
4395
  (e) => {
3540
4396
  if (!editor) return;
3541
4397
  const size = e.target.value;
@@ -3547,7 +4403,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3547
4403
  },
3548
4404
  [editor]
3549
4405
  );
3550
- const handleFontWeightChange = useCallback9(
4406
+ const handleFontWeightChange = useCallback13(
3551
4407
  (e) => {
3552
4408
  if (!editor) return;
3553
4409
  const weight = e.target.value;
@@ -3559,11 +4415,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3559
4415
  },
3560
4416
  [editor]
3561
4417
  );
3562
- const handlePageSelect = useCallback9((path) => {
4418
+ const handlePageSelect = useCallback13((path) => {
3563
4419
  setCurrentHref(path);
3564
4420
  setIsExternalUrl(false);
3565
4421
  }, []);
3566
- const handleExternalUrlApply = useCallback9(() => {
4422
+ const handleExternalUrlApply = useCallback13(() => {
3567
4423
  if (externalUrl) {
3568
4424
  setCurrentHref(externalUrl);
3569
4425
  }
@@ -3579,9 +4435,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3579
4435
  return attrs.fontWeight || "";
3580
4436
  };
3581
4437
  if (mode === "read-only") {
3582
- const content = isIconMode ? children : /* @__PURE__ */ jsx9(SafeHtml, { content: text, mode });
4438
+ const content = isIconMode ? children : /* @__PURE__ */ jsx14(SafeHtml, { content: text, mode });
3583
4439
  if (isInternalPath(href)) {
3584
- return /* @__PURE__ */ jsx9(
4440
+ return /* @__PURE__ */ jsx14(
3585
4441
  WouterLink,
3586
4442
  {
3587
4443
  href,
@@ -3593,7 +4449,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3593
4449
  }
3594
4450
  );
3595
4451
  }
3596
- return /* @__PURE__ */ jsx9(
4452
+ return /* @__PURE__ */ jsx14(
3597
4453
  Component,
3598
4454
  {
3599
4455
  ref: containerRef,
@@ -3608,8 +4464,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3608
4464
  }
3609
4465
  );
3610
4466
  }
3611
- return /* @__PURE__ */ jsxs5("span", { className: "ya-link-wrapper", children: [
3612
- /* @__PURE__ */ jsx9(
4467
+ return /* @__PURE__ */ jsxs8("span", { className: "ya-link-wrapper", children: [
4468
+ /* @__PURE__ */ jsx14(
3613
4469
  Component,
3614
4470
  {
3615
4471
  ref: containerRef,
@@ -3621,45 +4477,45 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3621
4477
  "data-ya-restricted": "true",
3622
4478
  "data-field-id": fieldId,
3623
4479
  onClick: handleClick,
3624
- onMouseEnter: handleMouseEnter,
3625
- onMouseLeave: handleMouseLeave,
3626
- onFocus: handleFocus,
4480
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
4481
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
4482
+ onFocus: safeTriangleHandlers.onFocus,
3627
4483
  onKeyDown: handleKeyDown,
3628
4484
  children: isIconMode ? (
3629
4485
  // Icon mode: render children directly, no text editing
3630
4486
  children
3631
- ) : editor ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3632
- createPortal4(
3633
- /* @__PURE__ */ jsxs5(
3634
- BubbleMenu2,
4487
+ ) : editor ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
4488
+ createPortal5(
4489
+ /* @__PURE__ */ jsxs8(
4490
+ BubbleMenu,
3635
4491
  {
3636
4492
  editor,
3637
4493
  shouldShow: () => editingMode === "text",
3638
4494
  options: { offset: 6, placement: "top" },
3639
4495
  className: "ya-bubble-menu",
3640
4496
  children: [
3641
- /* @__PURE__ */ jsx9(
4497
+ /* @__PURE__ */ jsx14(
3642
4498
  "button",
3643
4499
  {
3644
4500
  type: "button",
3645
4501
  onClick: () => editor.chain().focus().toggleBold().run(),
3646
4502
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
3647
4503
  title: "Bold",
3648
- children: /* @__PURE__ */ jsx9("strong", { children: "B" })
4504
+ children: /* @__PURE__ */ jsx14("strong", { children: "B" })
3649
4505
  }
3650
4506
  ),
3651
- /* @__PURE__ */ jsx9(
4507
+ /* @__PURE__ */ jsx14(
3652
4508
  "button",
3653
4509
  {
3654
4510
  type: "button",
3655
4511
  onClick: () => editor.chain().focus().toggleItalic().run(),
3656
4512
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
3657
4513
  title: "Italic",
3658
- children: /* @__PURE__ */ jsx9("em", { children: "I" })
4514
+ children: /* @__PURE__ */ jsx14("em", { children: "I" })
3659
4515
  }
3660
4516
  ),
3661
- /* @__PURE__ */ jsx9("span", { className: "ya-bubble-divider" }),
3662
- /* @__PURE__ */ jsxs5(
4517
+ /* @__PURE__ */ jsx14("span", { className: "ya-bubble-divider" }),
4518
+ /* @__PURE__ */ jsxs8(
3663
4519
  "select",
3664
4520
  {
3665
4521
  value: getCurrentFontSize(),
@@ -3667,12 +4523,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3667
4523
  className: "ya-bubble-select",
3668
4524
  title: "Font Size",
3669
4525
  children: [
3670
- /* @__PURE__ */ jsx9("option", { value: "", children: "Size" }),
3671
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx9("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))
3672
4528
  ]
3673
4529
  }
3674
4530
  ),
3675
- /* @__PURE__ */ jsxs5(
4531
+ /* @__PURE__ */ jsxs8(
3676
4532
  "select",
3677
4533
  {
3678
4534
  value: getCurrentFontWeight(),
@@ -3680,8 +4536,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3680
4536
  className: "ya-bubble-select",
3681
4537
  title: "Font Weight",
3682
4538
  children: [
3683
- /* @__PURE__ */ jsx9("option", { value: "", children: "Weight" }),
3684
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx9("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))
3685
4541
  ]
3686
4542
  }
3687
4543
  )
@@ -3690,39 +4546,72 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3690
4546
  ),
3691
4547
  document.body
3692
4548
  ),
3693
- editingMode === "text" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3694
- /* @__PURE__ */ jsx9(EditorContent2, { editor }),
3695
- /* @__PURE__ */ jsxs5("div", { className: "ya-link-actions", children: [
3696
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
3697
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
3698
- ] })
3699
- ] }) : /* @__PURE__ */ jsx9(SafeHtml, { content: text, mode })
3700
- ] }) : /* @__PURE__ */ jsx9(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 })
3701
4571
  }
3702
4572
  ),
3703
- showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs5("div", { className: "ya-link-edit-popover", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [
3704
- !isIconMode && /* @__PURE__ */ jsx9("button", { type: "button", onClick: startEditText, children: "Edit text" }),
3705
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: startEditLink, children: "Edit link" })
3706
- ] }),
3707
- editingMode === "link" && /* @__PURE__ */ jsxs5("div", { ref: hrefPopoverRef, className: "ya-href-popover", children: [
3708
- /* @__PURE__ */ jsx9("div", { className: "ya-href-popover-header", children: "Link destination" }),
3709
- !isExternalUrl ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3710
- sections.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3711
- /* @__PURE__ */ jsxs5(
4573
+ showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs8(
4574
+ "div",
4575
+ {
4576
+ ref: editPopoverRef,
4577
+ className: "ya-link-edit-popover",
4578
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
4579
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
4580
+ children: [
4581
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: startEditText, children: "Edit text" }),
4582
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: startEditLink, children: "Edit link" })
4583
+ ]
4584
+ }
4585
+ ),
4586
+ /* @__PURE__ */ jsx14(
4587
+ SafeTriangleBelow,
4588
+ {
4589
+ triggerRef,
4590
+ popoverRef: editPopoverRef,
4591
+ isVisible: showEditPopover && !editingMode && mode === "inline-edit",
4592
+ onLeave: triangleProps.onLeave,
4593
+ onStayInside: triangleProps.onStayInside
4594
+ }
4595
+ ),
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(
3712
4601
  "button",
3713
4602
  {
3714
4603
  type: "button",
3715
4604
  className: "ya-href-popover-label ya-href-collapsible-header",
3716
4605
  onClick: () => setSectionsExpanded(!sectionsExpanded),
3717
4606
  children: [
3718
- /* @__PURE__ */ jsx9("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
4607
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3719
4608
  "Scroll to section (",
3720
4609
  sections.length,
3721
4610
  ")"
3722
4611
  ]
3723
4612
  }
3724
4613
  ),
3725
- sectionsExpanded && /* @__PURE__ */ jsx9("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(
3726
4615
  "button",
3727
4616
  {
3728
4617
  type: "button",
@@ -3730,15 +4619,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3730
4619
  onClick: () => handlePageSelect(section.path),
3731
4620
  children: [
3732
4621
  section.label,
3733
- /* @__PURE__ */ jsx9("span", { className: "ya-href-page-path", children: section.path })
4622
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-page-path", children: section.path })
3734
4623
  ]
3735
4624
  },
3736
4625
  section.path
3737
4626
  )) })
3738
4627
  ] }),
3739
- pages.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3740
- /* @__PURE__ */ jsx9("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
3741
- /* @__PURE__ */ jsx9("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(
3742
4631
  "button",
3743
4632
  {
3744
4633
  type: "button",
@@ -3746,13 +4635,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3746
4635
  onClick: () => handlePageSelect(page.path),
3747
4636
  children: [
3748
4637
  page.label,
3749
- /* @__PURE__ */ jsx9("span", { className: "ya-href-page-path", children: page.path })
4638
+ /* @__PURE__ */ jsx14("span", { className: "ya-href-page-path", children: page.path })
3750
4639
  ]
3751
4640
  },
3752
4641
  page.path
3753
4642
  )) })
3754
4643
  ] }),
3755
- /* @__PURE__ */ jsx9(
4644
+ /* @__PURE__ */ jsx14(
3756
4645
  "button",
3757
4646
  {
3758
4647
  type: "button",
@@ -3764,10 +4653,10 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3764
4653
  children: "Use external URL instead"
3765
4654
  }
3766
4655
  )
3767
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3768
- /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3769
- /* @__PURE__ */ jsx9("label", { className: "ya-href-popover-label", children: "External URL" }),
3770
- /* @__PURE__ */ jsx9(
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(
3771
4660
  "input",
3772
4661
  {
3773
4662
  type: "url",
@@ -3779,25 +4668,34 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3779
4668
  }
3780
4669
  )
3781
4670
  ] }),
3782
- /* @__PURE__ */ jsx9("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" })
3783
4672
  ] }),
3784
- /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-actions", children: [
3785
- /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
3786
- isExternalUrl ? /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx9("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" })
3787
4676
  ] })
3788
4677
  ] })
3789
4678
  ] });
3790
4679
  }
3791
4680
 
3792
4681
  // src/components/YaContainer.tsx
3793
- import { useCallback as useCallback10, useEffect as useEffect9, useRef as useRef10, useState as useState9 } from "react";
3794
- import { createPortal as createPortal5 } from "react-dom";
4682
+ import { useCallback as useCallback14, useEffect as useEffect13, useRef as useRef13, useState as useState12 } from "react";
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";
3795
4693
 
3796
4694
  // src/components/ya-container.css
3797
- 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');
3798
4696
 
3799
4697
  // src/components/YaContainer.tsx
3800
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
4698
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
3801
4699
  function parseBackgroundConfig(value) {
3802
4700
  if (!value) {
3803
4701
  return { type: "none" };
@@ -3839,8 +4737,60 @@ function deriveContainerLabel(element) {
3839
4737
  return tagLabels[tagName] || "Section";
3840
4738
  }
3841
4739
  function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearClick, hasBackground }) {
3842
- const [position, setPosition] = useState9(null);
3843
- useEffect9(() => {
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(() => {
3844
4794
  const updatePosition = () => {
3845
4795
  if (containerRef.current) {
3846
4796
  const rect = containerRef.current.getBoundingClientRect();
@@ -3859,8 +4809,8 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3859
4809
  };
3860
4810
  }, [containerRef]);
3861
4811
  if (!position) return null;
3862
- return createPortal5(
3863
- /* @__PURE__ */ jsxs6(
4812
+ return createPortal6(
4813
+ /* @__PURE__ */ jsxs9(
3864
4814
  "div",
3865
4815
  {
3866
4816
  className: "ya-container-toolbar",
@@ -3871,60 +4821,106 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3871
4821
  },
3872
4822
  onClick: (e) => e.stopPropagation(),
3873
4823
  children: [
3874
- /* @__PURE__ */ jsx10(
4824
+ /* @__PURE__ */ jsx15(
3875
4825
  "button",
3876
4826
  {
4827
+ ref: imageRefs.setReference,
3877
4828
  type: "button",
3878
4829
  onClick: onImageClick,
3879
4830
  "aria-label": "Edit background image",
3880
- title: "Background Image",
3881
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3882
- /* @__PURE__ */ jsx10("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
3883
- /* @__PURE__ */ jsx10("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
3884
- /* @__PURE__ */ jsx10("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" })
3885
4836
  ] })
3886
4837
  }
3887
4838
  ),
3888
- /* @__PURE__ */ jsx10(
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(
3889
4850
  "button",
3890
4851
  {
4852
+ ref: colorRefs.setReference,
3891
4853
  type: "button",
3892
4854
  onClick: onColorClick,
3893
4855
  "aria-label": "Edit background color",
3894
- title: "Background Color",
3895
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3896
- /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "10" }),
3897
- /* @__PURE__ */ jsx10("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" })
3898
4860
  ] })
3899
4861
  }
3900
4862
  ),
3901
- /* @__PURE__ */ jsx10(
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(
3902
4874
  "button",
3903
4875
  {
4876
+ ref: aiRefs.setReference,
3904
4877
  type: "button",
3905
4878
  onClick: onAIClick,
3906
4879
  "aria-label": "Ask AI for help",
3907
- title: "AI Assist",
3908
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3909
- /* @__PURE__ */ jsx10("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
3910
- /* @__PURE__ */ jsx10("path", { d: "M2 17l10 5 10-5" }),
3911
- /* @__PURE__ */ jsx10("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" })
3912
4885
  ] })
3913
4886
  }
3914
4887
  ),
3915
- hasBackground && /* @__PURE__ */ jsx10(
3916
- "button",
4888
+ aiOpen && /* @__PURE__ */ jsx15(FloatingPortal2, { children: /* @__PURE__ */ jsx15(
4889
+ "div",
3917
4890
  {
3918
- type: "button",
3919
- onClick: onClearClick,
3920
- "aria-label": "Clear background",
3921
- title: "Clear Background",
3922
- children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3923
- /* @__PURE__ */ jsx10("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
3924
- /* @__PURE__ */ jsx10("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
3925
- ] })
4891
+ ref: aiRefs.setFloating,
4892
+ className: "ya-container-tooltip",
4893
+ style: aiStyles,
4894
+ ...getAiFloatProps(),
4895
+ children: "AI Assist"
3926
4896
  }
3927
- )
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
+ ] })
3928
4924
  ]
3929
4925
  }
3930
4926
  ),
@@ -3940,11 +4936,33 @@ function YaContainer({
3940
4936
  defaultBackground
3941
4937
  }) {
3942
4938
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
3943
- const containerRef = useRef10(null);
3944
- const [isHovered, setIsHovered] = useState9(false);
3945
- const [isSelected, setIsSelected] = useState9(false);
3946
- const [isDropMode, setIsDropMode] = useState9(false);
3947
- const [isDropHover, setIsDropHover] = useState9(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]);
3948
4966
  const rawValue = getValue(fieldId);
3949
4967
  const backgroundConfig = rawValue ? parseBackgroundConfig(rawValue) : defaultBackground || { type: "none" };
3950
4968
  const hasBackground = backgroundConfig.type !== "none";
@@ -3965,7 +4983,7 @@ function YaContainer({
3965
4983
  overlayCustomProps["--ya-overlay-color"] = backgroundConfig.overlay.color;
3966
4984
  overlayCustomProps["--ya-overlay-opacity"] = backgroundConfig.overlay.opacity;
3967
4985
  }
3968
- const handleImageClick = useCallback10(() => {
4986
+ const handleImageClick = useCallback14(() => {
3969
4987
  if (mode !== "inline-edit") return;
3970
4988
  setIsSelected(true);
3971
4989
  const rect = containerRef.current?.getBoundingClientRect();
@@ -3985,7 +5003,7 @@ function YaContainer({
3985
5003
  "*"
3986
5004
  );
3987
5005
  }, [mode, fieldId, backgroundConfig]);
3988
- const handleColorClick = useCallback10(() => {
5006
+ const handleColorClick = useCallback14(() => {
3989
5007
  if (mode !== "inline-edit") return;
3990
5008
  setIsSelected(true);
3991
5009
  const rect = containerRef.current?.getBoundingClientRect();
@@ -4005,7 +5023,7 @@ function YaContainer({
4005
5023
  "*"
4006
5024
  );
4007
5025
  }, [mode, fieldId, backgroundConfig]);
4008
- const handleAIClick = useCallback10(() => {
5026
+ const handleAIClick = useCallback14(() => {
4009
5027
  if (mode !== "inline-edit") return;
4010
5028
  const label = deriveContainerLabel(containerRef.current);
4011
5029
  window.parent.postMessage(
@@ -4018,14 +5036,14 @@ function YaContainer({
4018
5036
  "*"
4019
5037
  );
4020
5038
  }, [mode, fieldId, backgroundConfig]);
4021
- const handleClearClick = useCallback10(() => {
5039
+ const handleClearClick = useCallback14(() => {
4022
5040
  if (mode !== "inline-edit") return;
4023
5041
  const clearedConfig = { type: "none" };
4024
5042
  const serialized = serializeBackgroundConfig(clearedConfig);
4025
5043
  setValue(fieldId, serialized);
4026
5044
  saveToWorker?.(fieldId, serialized);
4027
5045
  }, [mode, fieldId, setValue, saveToWorker]);
4028
- useEffect9(() => {
5046
+ useEffect13(() => {
4029
5047
  if (mode !== "inline-edit") return;
4030
5048
  const handleMessage2 = (event) => {
4031
5049
  if (event.data?.type === "YA_CONTAINER_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4038,7 +5056,7 @@ function YaContainer({
4038
5056
  window.addEventListener("message", handleMessage2);
4039
5057
  return () => window.removeEventListener("message", handleMessage2);
4040
5058
  }, [mode, fieldId]);
4041
- useEffect9(() => {
5059
+ useEffect13(() => {
4042
5060
  if (mode !== "inline-edit") return;
4043
5061
  const handleDropModeMessage = (event) => {
4044
5062
  if (event.data?.type === "DROP_MODE_START") {
@@ -4052,7 +5070,7 @@ function YaContainer({
4052
5070
  window.addEventListener("message", handleDropModeMessage);
4053
5071
  return () => window.removeEventListener("message", handleDropModeMessage);
4054
5072
  }, [mode]);
4055
- const handleDragEnter = useCallback10(
5073
+ const handleDragEnter = useCallback14(
4056
5074
  (e) => {
4057
5075
  if (!isDropMode) return;
4058
5076
  e.preventDefault();
@@ -4076,7 +5094,7 @@ function YaContainer({
4076
5094
  },
4077
5095
  [isDropMode, fieldId]
4078
5096
  );
4079
- const handleDragOver = useCallback10(
5097
+ const handleDragOver = useCallback14(
4080
5098
  (e) => {
4081
5099
  if (!isDropMode) return;
4082
5100
  e.preventDefault();
@@ -4084,7 +5102,7 @@ function YaContainer({
4084
5102
  },
4085
5103
  [isDropMode]
4086
5104
  );
4087
- const handleDragLeave = useCallback10(
5105
+ const handleDragLeave = useCallback14(
4088
5106
  (e) => {
4089
5107
  if (!isDropMode) return;
4090
5108
  e.preventDefault();
@@ -4098,7 +5116,7 @@ function YaContainer({
4098
5116
  },
4099
5117
  [isDropMode]
4100
5118
  );
4101
- const handleDrop = useCallback10(
5119
+ const handleDrop = useCallback14(
4102
5120
  (e) => {
4103
5121
  if (!isDropMode) return;
4104
5122
  e.preventDefault();
@@ -4116,7 +5134,7 @@ function YaContainer({
4116
5134
  },
4117
5135
  [isDropMode, fieldId]
4118
5136
  );
4119
- useEffect9(() => {
5137
+ useEffect13(() => {
4120
5138
  if (!isSelected || mode !== "inline-edit") return;
4121
5139
  let lastRectKey = "";
4122
5140
  let lastTime = 0;
@@ -4151,7 +5169,7 @@ function YaContainer({
4151
5169
  return () => cancelAnimationFrame(rafId);
4152
5170
  }, [isSelected, fieldId, mode]);
4153
5171
  if (mode === "read-only") {
4154
- return /* @__PURE__ */ jsx10(
5172
+ return /* @__PURE__ */ jsx15(
4155
5173
  Tag,
4156
5174
  {
4157
5175
  className: `ya-container ${className || ""}`,
@@ -4175,7 +5193,7 @@ function YaContainer({
4175
5193
  isDropHover ? "ya-container-drop-hover" : "",
4176
5194
  className || ""
4177
5195
  ].filter(Boolean).join(" ");
4178
- return /* @__PURE__ */ jsxs6(
5196
+ return /* @__PURE__ */ jsxs9(
4179
5197
  Tag,
4180
5198
  {
4181
5199
  ref: containerRef,
@@ -4188,15 +5206,13 @@ function YaContainer({
4188
5206
  "data-ya-restricted": "true",
4189
5207
  "data-field-id": fieldId,
4190
5208
  "data-ya-container": "true",
4191
- onMouseEnter: () => setIsHovered(true),
4192
- onMouseLeave: () => setIsHovered(false),
4193
5209
  onDragEnter: handleDragEnter,
4194
5210
  onDragOver: handleDragOver,
4195
5211
  onDragLeave: handleDragLeave,
4196
5212
  onDrop: handleDrop,
4197
5213
  children: [
4198
5214
  children,
4199
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx10(
5215
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx15(
4200
5216
  Toolbar,
4201
5217
  {
4202
5218
  containerRef,
@@ -4213,10 +5229,10 @@ function YaContainer({
4213
5229
  }
4214
5230
 
4215
5231
  // src/components/StaticText.tsx
4216
- import { jsx as jsx11 } from "react/jsx-runtime";
5232
+ import { jsx as jsx16 } from "react/jsx-runtime";
4217
5233
  function MpText({ fieldId, className, as: Component = "span", children }) {
4218
5234
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
4219
- return /* @__PURE__ */ jsx11(
5235
+ return /* @__PURE__ */ jsx16(
4220
5236
  Component,
4221
5237
  {
4222
5238
  className,
@@ -4227,7 +5243,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
4227
5243
  }
4228
5244
 
4229
5245
  // src/components/StaticImage.tsx
4230
- import { jsx as jsx12 } from "react/jsx-runtime";
5246
+ import { jsx as jsx17 } from "react/jsx-runtime";
4231
5247
  function parseImageValue2(value) {
4232
5248
  if (!value) {
4233
5249
  return { src: "" };
@@ -4263,7 +5279,7 @@ function MpImage({
4263
5279
  const altText = imageData.alt || alt || fallbackAlt || "";
4264
5280
  const objectFit = imageData.objectFit || propObjectFit || "cover";
4265
5281
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
4266
- return /* @__PURE__ */ jsx12(
5282
+ return /* @__PURE__ */ jsx17(
4267
5283
  "img",
4268
5284
  {
4269
5285
  src: resolveAssetUrl(src),
@@ -4280,8 +5296,8 @@ function MpImage({
4280
5296
  }
4281
5297
 
4282
5298
  // src/components/MarkdownText.tsx
4283
- import { Fragment as Fragment4 } from "react";
4284
- import { jsx as jsx13 } from "react/jsx-runtime";
5299
+ import { Fragment as Fragment6 } from "react";
5300
+ import { jsx as jsx18 } from "react/jsx-runtime";
4285
5301
  function tokenize(text) {
4286
5302
  const tokens = [];
4287
5303
  let remaining = text;
@@ -4343,13 +5359,13 @@ function tokensToElements(tokens) {
4343
5359
  return tokens.map((token, index) => {
4344
5360
  switch (token.type) {
4345
5361
  case "text":
4346
- return /* @__PURE__ */ jsx13(Fragment4, { children: token.content }, index);
5362
+ return /* @__PURE__ */ jsx18(Fragment6, { children: token.content }, index);
4347
5363
  case "bold":
4348
- return /* @__PURE__ */ jsx13("strong", { children: token.content }, index);
5364
+ return /* @__PURE__ */ jsx18("strong", { children: token.content }, index);
4349
5365
  case "italic":
4350
- return /* @__PURE__ */ jsx13("em", { children: token.content }, index);
5366
+ return /* @__PURE__ */ jsx18("em", { children: token.content }, index);
4351
5367
  case "link":
4352
- return /* @__PURE__ */ jsx13(
5368
+ return /* @__PURE__ */ jsx18(
4353
5369
  "a",
4354
5370
  {
4355
5371
  href: token.url,
@@ -4361,7 +5377,7 @@ function tokensToElements(tokens) {
4361
5377
  index
4362
5378
  );
4363
5379
  case "newline":
4364
- return /* @__PURE__ */ jsx13("br", {}, index);
5380
+ return /* @__PURE__ */ jsx18("br", {}, index);
4365
5381
  default:
4366
5382
  return null;
4367
5383
  }
@@ -4373,15 +5389,15 @@ function parseMarkdownToElements(content) {
4373
5389
  }
4374
5390
  function MarkdownText({ content, className }) {
4375
5391
  const elements = parseMarkdownToElements(content);
4376
- return /* @__PURE__ */ jsx13("span", { className, children: elements });
5392
+ return /* @__PURE__ */ jsx18("span", { className, children: elements });
4377
5393
  }
4378
5394
 
4379
5395
  // src/router/Link.tsx
4380
5396
  import { Link as WouterLink2 } from "wouter";
4381
- import { jsx as jsx14 } from "react/jsx-runtime";
5397
+ import { jsx as jsx19 } from "react/jsx-runtime";
4382
5398
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
4383
5399
  const target = href ?? to ?? "/";
4384
- return /* @__PURE__ */ jsx14(WouterLink2, { href: target, className, onClick, replace, ...props, children });
5400
+ return /* @__PURE__ */ jsx19(WouterLink2, { href: target, className, onClick, replace, ...props, children });
4385
5401
  }
4386
5402
 
4387
5403
  // src/router/useNavigate.ts
@@ -4400,7 +5416,7 @@ function useNavigate() {
4400
5416
 
4401
5417
  // src/router/Router.tsx
4402
5418
  import { Router as WouterRouter } from "wouter";
4403
- import { jsx as jsx15 } from "react/jsx-runtime";
5419
+ import { jsx as jsx20 } from "react/jsx-runtime";
4404
5420
  function detectBasename() {
4405
5421
  if (typeof window === "undefined") return "";
4406
5422
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -4415,7 +5431,7 @@ function detectBasename() {
4415
5431
  }
4416
5432
  function Router({ children, base }) {
4417
5433
  const basename = base ?? detectBasename();
4418
- return /* @__PURE__ */ jsx15(WouterRouter, { base: basename, children });
5434
+ return /* @__PURE__ */ jsx20(WouterRouter, { base: basename, children });
4419
5435
  }
4420
5436
 
4421
5437
  // src/router/index.ts
@@ -4429,6 +5445,7 @@ export {
4429
5445
  Route,
4430
5446
  Router,
4431
5447
  SafeHtml,
5448
+ SafeTriangleBelow,
4432
5449
  MpImage as StaticImage,
4433
5450
  MpText as StaticText,
4434
5451
  Switch,
@@ -4465,5 +5482,6 @@ export {
4465
5482
  useContentStore,
4466
5483
  useContentStore2 as useContentStoreProd,
4467
5484
  useNavigate,
4468
- useParams
5485
+ useParams,
5486
+ useSafeTriangle
4469
5487
  };