@yoamigo.com/core 1.0.0 → 1.1.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
@@ -1,3 +1,57 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/icons/custom-icons.tsx
12
+ var custom_icons_exports = {};
13
+ __export(custom_icons_exports, {
14
+ CUSTOM_ICON_NAMES: () => CUSTOM_ICON_NAMES,
15
+ IconBrandAppleMusic: () => IconBrandAppleMusic
16
+ });
17
+ import { forwardRef, createElement } from "react";
18
+ var appleMusicIconNode, IconBrandAppleMusic, CUSTOM_ICON_NAMES;
19
+ var init_custom_icons = __esm({
20
+ "src/icons/custom-icons.tsx"() {
21
+ "use strict";
22
+ appleMusicIconNode = [
23
+ [
24
+ "path",
25
+ {
26
+ d: "M23.994 6.124a9.23 9.23 0 00-.24-2.19c-.317-1.31-1.062-2.31-2.18-3.043a5.022 5.022 0 00-1.877-.726 10.496 10.496 0 00-1.564-.15c-.04-.003-.083-.01-.124-.013H5.986c-.152.01-.303.017-.455.026-.747.043-1.49.123-2.193.4-1.336.53-2.3 1.452-2.865 2.78-.192.448-.292.925-.363 1.408-.056.392-.088.785-.1 1.18 0 .032-.007.062-.01.093v12.223c.01.14.017.283.027.424.05.815.154 1.624.497 2.373.65 1.42 1.738 2.353 3.234 2.801.42.127.856.187 1.293.228.555.053 1.11.06 1.667.06h11.03a12.5 12.5 0 001.57-.1c.822-.106 1.596-.35 2.295-.81a5.046 5.046 0 001.88-2.207c.186-.42.293-.87.37-1.324.113-.675.138-1.358.137-2.04-.002-3.8 0-7.595-.003-11.393zm-6.423 3.99v5.712c0 .417-.058.827-.244 1.206-.29.59-.76.962-1.388 1.14-.35.1-.706.157-1.07.173-.95.045-1.773-.6-1.943-1.536a1.88 1.88 0 011.038-2.022c.323-.16.67-.25 1.018-.324.378-.082.758-.153 1.134-.24.274-.063.457-.23.51-.516a.904.904 0 00.02-.193c0-1.815 0-3.63-.002-5.443a.725.725 0 00-.026-.185c-.04-.15-.15-.243-.304-.234-.16.01-.318.035-.475.066-.76.15-1.52.303-2.28.456l-2.325.47-1.374.278c-.016.003-.032.01-.048.013-.277.077-.377.203-.39.49-.002.042 0 .086 0 .13-.002 2.602 0 5.204-.003 7.805 0 .42-.047.836-.215 1.227-.278.64-.77 1.04-1.434 1.233-.35.1-.71.16-1.075.172-.96.036-1.755-.6-1.92-1.544-.14-.812.23-1.685 1.154-2.075.357-.15.73-.232 1.108-.31.287-.06.575-.116.86-.177.383-.083.583-.323.6-.714v-.15c0-2.96 0-5.922.002-8.882 0-.123.013-.25.042-.37.07-.285.273-.448.546-.518.255-.066.515-.112.774-.165.733-.15 1.466-.296 2.2-.444l2.27-.46c.67-.134 1.34-.27 2.01-.403.22-.043.442-.088.663-.106.31-.025.523.17.554.482.008.073.012.148.012.223.002 1.91.002 3.822 0 5.732z",
27
+ key: "svg-0"
28
+ }
29
+ ]
30
+ ];
31
+ IconBrandAppleMusic = forwardRef(
32
+ ({ color = "currentColor", size = 24, className, style, title, ...rest }, ref) => createElement(
33
+ "svg",
34
+ {
35
+ ref,
36
+ xmlns: "http://www.w3.org/2000/svg",
37
+ width: size,
38
+ height: size,
39
+ viewBox: "0 0 24 24",
40
+ fill: color,
41
+ className,
42
+ style,
43
+ ...rest
44
+ },
45
+ // Title element provides native browser tooltip on hover
46
+ title && createElement("title", { key: "title" }, title),
47
+ ...appleMusicIconNode.map(([tag, attrs]) => createElement(tag, attrs))
48
+ )
49
+ );
50
+ IconBrandAppleMusic.displayName = "IconBrandAppleMusic";
51
+ CUSTOM_ICON_NAMES = ["IconBrandAppleMusic"];
52
+ }
53
+ });
54
+
1
55
  // src/lib/content-registry.ts
2
56
  var contentMap = /* @__PURE__ */ new Map();
3
57
  function registerContent(content) {
@@ -234,6 +288,9 @@ var BuilderSelectionManager = class {
234
288
  case "GET_CURRENT_PAGE":
235
289
  this.sendToParent({ type: "CURRENT_PAGE", pagePath: window.location.pathname });
236
290
  break;
291
+ case "CHECK_BLANK_STATE":
292
+ this.checkBlankState();
293
+ break;
237
294
  }
238
295
  });
239
296
  }
@@ -885,16 +942,16 @@ var BuilderSelectionManager = class {
885
942
  }
886
943
  const links = document.querySelectorAll('a[href^="/"]');
887
944
  const routes = /* @__PURE__ */ new Set(["/"]);
888
- links.forEach((link) => {
889
- const href = link.getAttribute("href");
945
+ links.forEach((link2) => {
946
+ const href = link2.getAttribute("href");
890
947
  if (href && href.startsWith("/") && !href.includes("http")) {
891
948
  const path = href.split("?")[0].replace(/\/$/, "") || "/";
892
949
  routes.add(path);
893
950
  }
894
951
  });
895
952
  const navLinks = document.querySelectorAll("nav a[href]");
896
- navLinks.forEach((link) => {
897
- const href = link.getAttribute("href");
953
+ navLinks.forEach((link2) => {
954
+ const href = link2.getAttribute("href");
898
955
  if (href?.startsWith("/")) {
899
956
  const path = href.split("?")[0].replace(/\/$/, "") || "/";
900
957
  routes.add(path);
@@ -1082,6 +1139,66 @@ var BuilderSelectionManager = class {
1082
1139
  return null;
1083
1140
  }
1084
1141
  }
1142
+ /**
1143
+ * Check if the page is visually blank (all white/uniform color)
1144
+ * Uses canvas pixel sampling for accuracy.
1145
+ * Triggered after AI edits to detect if preview went white and needs refresh.
1146
+ */
1147
+ async checkBlankState() {
1148
+ try {
1149
+ const html2canvas = (await import("html2canvas-pro")).default;
1150
+ const canvas = await html2canvas(document.body, {
1151
+ scale: 0.1,
1152
+ // Small scale for speed
1153
+ logging: false,
1154
+ width: window.innerWidth,
1155
+ height: window.innerHeight,
1156
+ backgroundColor: null
1157
+ // Preserve actual background
1158
+ });
1159
+ const sampleCanvas = document.createElement("canvas");
1160
+ const size = 100;
1161
+ sampleCanvas.width = size;
1162
+ sampleCanvas.height = size;
1163
+ const ctx = sampleCanvas.getContext("2d");
1164
+ if (!ctx) {
1165
+ this.sendToParent({ type: "BLANK_STATE_RESULT", isBlank: false });
1166
+ return;
1167
+ }
1168
+ ctx.drawImage(canvas, 0, 0, size, size);
1169
+ const samplePoints = [
1170
+ [25, 25],
1171
+ [75, 25],
1172
+ [50, 50],
1173
+ [25, 75],
1174
+ [75, 75],
1175
+ [10, 10],
1176
+ [90, 90],
1177
+ [50, 25],
1178
+ [50, 75],
1179
+ [25, 50]
1180
+ ];
1181
+ const pixels = samplePoints.map(([x, y]) => {
1182
+ const data = ctx.getImageData(x, y, 1, 1).data;
1183
+ return { r: data[0], g: data[1], b: data[2] };
1184
+ });
1185
+ const firstPixel = pixels[0];
1186
+ const tolerance = 10;
1187
+ const allSame = pixels.every(
1188
+ (p) => Math.abs(p.r - firstPixel.r) < tolerance && Math.abs(p.g - firstPixel.g) < tolerance && Math.abs(p.b - firstPixel.b) < tolerance
1189
+ );
1190
+ const isWhitish = firstPixel.r > 240 && firstPixel.g > 240 && firstPixel.b > 240;
1191
+ const isBlank = allSame && isWhitish;
1192
+ this.sendToParent({
1193
+ type: "BLANK_STATE_RESULT",
1194
+ isBlank,
1195
+ sampleColor: `rgb(${firstPixel.r},${firstPixel.g},${firstPixel.b})`
1196
+ });
1197
+ } catch (error) {
1198
+ console.error("[BuilderSelection] Blank check failed:", error);
1199
+ this.sendToParent({ type: "BLANK_STATE_RESULT", isBlank: false });
1200
+ }
1201
+ }
1085
1202
  };
1086
1203
  var instance = null;
1087
1204
  function initBuilderSelection() {
@@ -2041,16 +2158,16 @@ function SafeHtml({ content, className, mode = "read-only" }) {
2041
2158
  if (mode !== "inline-edit" || !containerRef.current) return;
2042
2159
  const container = containerRef.current;
2043
2160
  const handleMouseOver = (e) => {
2044
- const link = e.target.closest("a");
2045
- if (!link) return;
2161
+ const link2 = e.target.closest("a");
2162
+ if (!link2) return;
2046
2163
  if (e.target.closest(".mp-text-editing, .mp-text-editable")) return;
2047
2164
  const selectModeEnabled = window.__builderSelectModeEnabled;
2048
2165
  if (selectModeEnabled) return;
2049
2166
  clearTimeout(hideTimerRef.current);
2050
2167
  showTimerRef.current = window.setTimeout(() => {
2051
- const href = link.getAttribute("href") || "";
2168
+ const href = link2.getAttribute("href") || "";
2052
2169
  const { text: text2, isExternal } = extractLinkDisplayText(href);
2053
- const rect = link.getBoundingClientRect();
2170
+ const rect = link2.getBoundingClientRect();
2054
2171
  const top = rect.bottom + window.scrollY + 8;
2055
2172
  const left = rect.left + rect.width / 2 + window.scrollX;
2056
2173
  setPopoverState({
@@ -2063,8 +2180,8 @@ function SafeHtml({ content, className, mode = "read-only" }) {
2063
2180
  }, 150);
2064
2181
  };
2065
2182
  const handleMouseOut = (e) => {
2066
- const link = e.target.closest("a");
2067
- if (!link) return;
2183
+ const link2 = e.target.closest("a");
2184
+ if (!link2) return;
2068
2185
  scheduleHide();
2069
2186
  };
2070
2187
  const handleClick = (e) => {
@@ -2077,8 +2194,8 @@ function SafeHtml({ content, className, mode = "read-only" }) {
2077
2194
  }
2078
2195
  return;
2079
2196
  }
2080
- const link = e.target.closest("a");
2081
- if (link) {
2197
+ const link2 = e.target.closest("a");
2198
+ if (link2) {
2082
2199
  e.preventDefault();
2083
2200
  e.stopPropagation();
2084
2201
  }
@@ -2653,6 +2770,71 @@ function useAnimatedText(fieldId, content, options = {}) {
2653
2770
  };
2654
2771
  }
2655
2772
 
2773
+ // src/lib/contrast-detection.ts
2774
+ function parseColor(color) {
2775
+ const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
2776
+ if (rgbMatch) {
2777
+ return { r: parseInt(rgbMatch[1]), g: parseInt(rgbMatch[2]), b: parseInt(rgbMatch[3]) };
2778
+ }
2779
+ const hexMatch = color.match(/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
2780
+ if (hexMatch) {
2781
+ return { r: parseInt(hexMatch[1], 16), g: parseInt(hexMatch[2], 16), b: parseInt(hexMatch[3], 16) };
2782
+ }
2783
+ return null;
2784
+ }
2785
+ function getRelativeLuminance(r, g, b) {
2786
+ const [rs, gs, bs] = [r, g, b].map((c) => {
2787
+ const s = c / 255;
2788
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
2789
+ });
2790
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
2791
+ }
2792
+ function getEffectiveBackgroundColor(element) {
2793
+ let el = element;
2794
+ while (el) {
2795
+ const bg = window.getComputedStyle(el).backgroundColor;
2796
+ const parsed = parseColor(bg);
2797
+ if (parsed && bg !== "transparent" && bg !== "rgba(0, 0, 0, 0)") {
2798
+ return bg;
2799
+ }
2800
+ el = el.parentElement;
2801
+ }
2802
+ return null;
2803
+ }
2804
+ function getContrastColor(bgColor) {
2805
+ const parsed = parseColor(bgColor);
2806
+ if (!parsed) return "white";
2807
+ const luminance = getRelativeLuminance(parsed.r, parsed.g, parsed.b);
2808
+ const contrastWithWhite = (1 + 0.05) / (luminance + 0.05);
2809
+ const contrastWithBlack = (luminance + 0.05) / (0 + 0.05);
2810
+ return contrastWithWhite > contrastWithBlack ? "white" : "black";
2811
+ }
2812
+ function setupContrastDetection(element) {
2813
+ const updateContrastColor = () => {
2814
+ const bgColor = getEffectiveBackgroundColor(element);
2815
+ if (bgColor) {
2816
+ const contrastColor = getContrastColor(bgColor);
2817
+ element.style.setProperty("--ya-contrast-color", contrastColor);
2818
+ }
2819
+ };
2820
+ updateContrastColor();
2821
+ let rafId = null;
2822
+ const throttledUpdate = () => {
2823
+ if (rafId) return;
2824
+ rafId = requestAnimationFrame(() => {
2825
+ updateContrastColor();
2826
+ rafId = null;
2827
+ });
2828
+ };
2829
+ window.addEventListener("scroll", throttledUpdate, { passive: true, capture: true });
2830
+ window.addEventListener("resize", throttledUpdate, { passive: true });
2831
+ return () => {
2832
+ window.removeEventListener("scroll", throttledUpdate, { capture: true });
2833
+ window.removeEventListener("resize", throttledUpdate);
2834
+ if (rafId) cancelAnimationFrame(rafId);
2835
+ };
2836
+ }
2837
+
2656
2838
  // src/components/BubbleIcons.tsx
2657
2839
  import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
2658
2840
  function BoldIcon({ size = 16, className }) {
@@ -3090,23 +3272,34 @@ function styleInject(css, { insertAt } = {}) {
3090
3272
 
3091
3273
  // src/components/ya-text.css
3092
3274
  styleInject(`.ya-text-editable {
3275
+ position: relative;
3093
3276
  cursor: text;
3094
- transition: outline 0.15s ease;
3095
- }
3096
- .ya-text-editable:hover {
3097
- outline: 2px dashed var(--color-primary, #D4A574);
3277
+ border-radius: 4px;
3278
+ outline: 1.5px dashed transparent;
3098
3279
  outline-offset: 4px;
3280
+ transition: outline-color 0.15s ease;
3281
+ }
3282
+ .ya-text-editing {
3283
+ position: relative;
3284
+ cursor: text;
3099
3285
  border-radius: 4px;
3286
+ outline: 1.5px solid var(--ya-contrast-color, white);
3287
+ outline-offset: 4px;
3288
+ }
3289
+ .ya-text-editable:hover {
3290
+ outline-color: var(--ya-contrast-color, white);
3100
3291
  }
3101
3292
  body.builder-selector-active .ya-text-editable:hover {
3102
- outline: none;
3293
+ outline-color: transparent;
3294
+ }
3295
+ body.builder-selector-active .ya-text-editable {
3103
3296
  cursor: inherit;
3104
3297
  }
3105
- .ya-text-editing {
3106
- outline: 2px solid var(--color-primary, #D4A574);
3107
- outline-offset: 4px;
3108
- border-radius: 4px;
3109
- position: relative;
3298
+ [data-ya-link=true] .ya-text-editable {
3299
+ outline: none;
3300
+ }
3301
+ [data-ya-link=true] .ya-text-editable:hover {
3302
+ outline: none;
3110
3303
  }
3111
3304
  .ya-text-editing .ProseMirror p::selection,
3112
3305
  .ya-text-editing .ProseMirror::selection {
@@ -3637,6 +3830,10 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3637
3830
  handleSaveRef.current = handleSave;
3638
3831
  handleCancelRef.current = handleCancel;
3639
3832
  }, [handleSave, handleCancel]);
3833
+ useEffect8(() => {
3834
+ if (mode !== "inline-edit" || !containerRef.current) return;
3835
+ return setupContrastDetection(containerRef.current);
3836
+ }, [mode]);
3640
3837
  useEffect8(() => {
3641
3838
  if (mode !== "inline-edit") return;
3642
3839
  const handleEditRequest = (event) => {
@@ -3689,8 +3886,8 @@ function YaText({ fieldId, className, as: Component = "span", children }) {
3689
3886
  if (selectModeEnabled) {
3690
3887
  return;
3691
3888
  }
3692
- const isInsideLink = e.currentTarget.closest("a") !== null;
3693
- if (isInsideLink) {
3889
+ const isInsideYaLink = e.currentTarget.closest('[data-ya-link="true"]') !== null;
3890
+ if (isInsideYaLink) {
3694
3891
  return;
3695
3892
  }
3696
3893
  if (mode === "inline-edit" && !isEditing) {
@@ -5263,14 +5460,401 @@ function YaVideo({
5263
5460
  );
5264
5461
  }
5265
5462
 
5266
- // src/components/YaEmbed.tsx
5463
+ // src/components/YaProtectedMedia.tsx
5267
5464
  import { useCallback as useCallback15, useEffect as useEffect13, useRef as useRef14, useState as useState13 } from "react";
5268
5465
 
5466
+ // src/lib/api-client.ts
5467
+ function getApiUrl() {
5468
+ const runtimeConfig = window.YOAMIGO_CONFIG;
5469
+ const apiUrl = runtimeConfig?.apiUrl || import.meta.env.YA_API_URL;
5470
+ if (!apiUrl) {
5471
+ throw new Error("API URL not configured (check YOAMIGO_CONFIG or YA_API_URL)");
5472
+ }
5473
+ return apiUrl;
5474
+ }
5475
+ function getSiteId() {
5476
+ const runtimeConfig = window.YOAMIGO_CONFIG;
5477
+ const siteId = runtimeConfig?.siteId || import.meta.env.YA_SITE_ID;
5478
+ if (!siteId) {
5479
+ throw new Error("Site ID not configured (check YOAMIGO_CONFIG or YA_SITE_ID)");
5480
+ }
5481
+ return siteId;
5482
+ }
5483
+
5484
+ // src/components/ya-protected-media.css
5485
+ styleInject(".ya-protected-container {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n border-radius: 12px;\n overflow: hidden;\n background:\n linear-gradient(\n 135deg,\n #1c1917 0%,\n #292524 100%);\n}\n.ya-protected-container.ya-protected-audio {\n padding: 24px;\n background:\n linear-gradient(\n 135deg,\n #1c1917 0%,\n #292524 100%);\n}\n.ya-protected-container.ya-protected-loading {\n min-height: 200px;\n}\n.ya-protected-spinner {\n width: 40px;\n height: 40px;\n border: 3px solid rgba(255, 255, 255, 0.1);\n border-top-color: #FF6B35;\n border-radius: 50%;\n animation: ya-spin 0.8s linear infinite;\n}\n@keyframes ya-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ya-protected-error-state {\n min-height: 200px;\n}\n.ya-protected-error-message {\n color: #ef4444;\n font-size: 14px;\n text-align: center;\n padding: 20px;\n}\n.ya-protected-container.ya-protected-locked {\n background:\n linear-gradient(\n 135deg,\n #1c1917 0%,\n #292524 100%);\n}\n.ya-protected-preview-wrapper {\n position: relative;\n width: 100%;\n height: 100%;\n}\n.ya-protected-preview-badge {\n position: absolute;\n top: 12px;\n right: 12px;\n padding: 6px 12px;\n background: rgba(0, 0, 0, 0.7);\n color: #FF6B35;\n font-size: 12px;\n font-weight: 600;\n border-radius: 999px;\n backdrop-filter: blur(4px);\n}\n.ya-protected-video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.ya-protected-video.ya-protected-preview {\n opacity: 0.8;\n}\n.ya-protected-audio-player {\n width: 100%;\n height: 48px;\n border-radius: 8px;\n}\n.ya-protected-title {\n font-size: 16px;\n font-weight: 600;\n color: #f5f5f4;\n margin-bottom: 16px;\n text-align: center;\n}\n.ya-protected-unlock-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(28, 25, 23, 0.95);\n backdrop-filter: blur(8px);\n}\n.ya-protected-unlock-prompt {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n padding: 24px;\n background:\n linear-gradient(\n to top,\n rgba(28, 25, 23, 0.98) 0%,\n rgba(28, 25, 23, 0.9) 80%,\n transparent 100%);\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n}\n.ya-protected-unlock-form {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n padding: 32px;\n max-width: 320px;\n width: 100%;\n text-align: center;\n}\n.ya-protected-unlock-icon {\n color: #FF6B35;\n margin-bottom: 8px;\n}\n.ya-protected-unlock-title {\n font-size: 24px;\n font-weight: 700;\n color: #f5f5f4;\n letter-spacing: -0.02em;\n}\n.ya-protected-unlock-folder {\n font-size: 14px;\n color: #a8a29e;\n margin-top: -8px;\n}\n.ya-protected-unlock-subtitle {\n font-size: 14px;\n color: #a8a29e;\n margin-bottom: 8px;\n}\n.ya-protected-input {\n width: 100%;\n padding: 14px 16px;\n font-size: 15px;\n color: #f5f5f4;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 10px;\n outline: none;\n transition: all 0.2s ease;\n}\n.ya-protected-input::placeholder {\n color: #78716c;\n}\n.ya-protected-input:focus {\n border-color: #FF6B35;\n background: rgba(255, 107, 53, 0.05);\n box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.1);\n}\n.ya-protected-input:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n.ya-protected-button {\n width: 100%;\n padding: 14px 24px;\n font-size: 15px;\n font-weight: 600;\n color: #fff;\n background:\n linear-gradient(\n 135deg,\n #FF6B35 0%,\n #e05a2b 100%);\n border: none;\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n.ya-protected-button:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 6px 20px rgba(255, 107, 53, 0.35);\n}\n.ya-protected-button:active:not(:disabled) {\n transform: translateY(0);\n}\n.ya-protected-button:disabled {\n opacity: 0.7;\n cursor: not-allowed;\n}\n.ya-protected-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n.ya-protected-error {\n color: #ef4444;\n font-size: 13px;\n padding: 8px 12px;\n background: rgba(239, 68, 68, 0.1);\n border-radius: 6px;\n width: 100%;\n}\n.ya-protected-disclaimer {\n font-size: 12px;\n color: #78716c;\n margin-top: -4px;\n}\n.ya-protected-container.ya-protected-unlocked {\n background: transparent;\n}\n@media (max-width: 480px) {\n .ya-protected-unlock-form {\n padding: 24px 16px;\n }\n .ya-protected-unlock-title {\n font-size: 20px;\n }\n .ya-protected-input,\n .ya-protected-button {\n padding: 12px 14px;\n font-size: 14px;\n }\n}\n@media (prefers-color-scheme: light) {\n .ya-protected-container.ya-protected-locked {\n background:\n linear-gradient(\n 135deg,\n #f5f5f4 0%,\n #e7e5e4 100%);\n }\n .ya-protected-unlock-overlay {\n background: rgba(245, 245, 244, 0.95);\n }\n .ya-protected-unlock-title {\n color: #1c1917;\n }\n .ya-protected-unlock-subtitle,\n .ya-protected-unlock-folder {\n color: #57534e;\n }\n .ya-protected-input {\n color: #1c1917;\n background: rgba(0, 0, 0, 0.03);\n border-color: rgba(0, 0, 0, 0.1);\n }\n .ya-protected-input::placeholder {\n color: #a8a29e;\n }\n .ya-protected-input:focus {\n background: rgba(255, 107, 53, 0.03);\n }\n .ya-protected-disclaimer {\n color: #78716c;\n }\n}\n");
5486
+
5487
+ // src/components/YaProtectedMedia.tsx
5488
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
5489
+ var COOKIE_PREFIX = "ya_access_";
5490
+ var COOKIE_EXPIRY_DAYS = 30;
5491
+ function getStoredAccess(folderId) {
5492
+ const name = `${COOKIE_PREFIX}${folderId}=`;
5493
+ const decodedCookie = decodeURIComponent(document.cookie);
5494
+ const cookies = decodedCookie.split(";");
5495
+ for (const cookie of cookies) {
5496
+ const c = cookie.trim();
5497
+ if (c.indexOf(name) === 0) {
5498
+ return c.substring(name.length);
5499
+ }
5500
+ }
5501
+ return null;
5502
+ }
5503
+ function storeAccess(folderId, email) {
5504
+ const expires = /* @__PURE__ */ new Date();
5505
+ expires.setTime(expires.getTime() + COOKIE_EXPIRY_DAYS * 24 * 60 * 60 * 1e3);
5506
+ document.cookie = `${COOKIE_PREFIX}${folderId}=${email};expires=${expires.toUTCString()};path=/;SameSite=Lax`;
5507
+ }
5508
+ function clearStoredAccess(folderId) {
5509
+ document.cookie = `${COOKIE_PREFIX}${folderId}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
5510
+ }
5511
+ function UnlockForm({ accessInfo, onSubmit, isLoading, error }) {
5512
+ const [email, setEmail] = useState13("");
5513
+ const [password, setPassword] = useState13("");
5514
+ const handleSubmit = (e) => {
5515
+ e.preventDefault();
5516
+ if (accessInfo.authType === "password") {
5517
+ onSubmit({ password });
5518
+ } else {
5519
+ onSubmit({ email });
5520
+ }
5521
+ };
5522
+ const isEmailAuth = accessInfo.authType === "email" || accessInfo.authType === "subscriber";
5523
+ const isPasswordAuth = accessInfo.authType === "password";
5524
+ return /* @__PURE__ */ jsxs8("form", { className: "ya-protected-unlock-form", onSubmit: handleSubmit, children: [
5525
+ /* @__PURE__ */ jsx15("div", { className: "ya-protected-unlock-icon", children: /* @__PURE__ */ jsxs8(
5526
+ "svg",
5527
+ {
5528
+ width: "32",
5529
+ height: "32",
5530
+ viewBox: "0 0 24 24",
5531
+ fill: "none",
5532
+ stroke: "currentColor",
5533
+ strokeWidth: "2",
5534
+ strokeLinecap: "round",
5535
+ strokeLinejoin: "round",
5536
+ children: [
5537
+ /* @__PURE__ */ jsx15("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
5538
+ /* @__PURE__ */ jsx15("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
5539
+ ]
5540
+ }
5541
+ ) }),
5542
+ /* @__PURE__ */ jsx15("div", { className: "ya-protected-unlock-title", children: accessInfo.authType === "subscriber" ? "Subscribers Only" : "Exclusive Content" }),
5543
+ accessInfo.folderName && /* @__PURE__ */ jsx15("div", { className: "ya-protected-unlock-folder", children: accessInfo.folderName }),
5544
+ /* @__PURE__ */ jsx15("div", { className: "ya-protected-unlock-subtitle", children: isEmailAuth && accessInfo.authType === "subscriber" ? "Enter your email to verify access" : isEmailAuth ? "Enter your email to unlock" : "Enter password to access" }),
5545
+ isEmailAuth && /* @__PURE__ */ jsx15(
5546
+ "input",
5547
+ {
5548
+ type: "email",
5549
+ className: "ya-protected-input",
5550
+ placeholder: "your@email.com",
5551
+ value: email,
5552
+ onChange: (e) => setEmail(e.target.value),
5553
+ required: true,
5554
+ disabled: isLoading,
5555
+ autoFocus: true
5556
+ }
5557
+ ),
5558
+ isPasswordAuth && /* @__PURE__ */ jsx15(
5559
+ "input",
5560
+ {
5561
+ type: "password",
5562
+ className: "ya-protected-input",
5563
+ placeholder: "Enter password",
5564
+ value: password,
5565
+ onChange: (e) => setPassword(e.target.value),
5566
+ required: true,
5567
+ disabled: isLoading,
5568
+ autoFocus: true
5569
+ }
5570
+ ),
5571
+ error && /* @__PURE__ */ jsx15("div", { className: "ya-protected-error", children: error }),
5572
+ /* @__PURE__ */ jsx15("button", { type: "submit", className: "ya-protected-button", disabled: isLoading, children: isLoading ? /* @__PURE__ */ jsx15("span", { className: "ya-protected-loading", children: "Unlocking..." }) : "Unlock Now" }),
5573
+ isEmailAuth && accessInfo.authType === "email" && /* @__PURE__ */ jsx15("div", { className: "ya-protected-disclaimer", children: "Your email will be added to the mailing list." })
5574
+ ] });
5575
+ }
5576
+ function YaProtectedMedia({
5577
+ fieldId,
5578
+ assetId,
5579
+ type,
5580
+ className,
5581
+ poster,
5582
+ aspectRatio = "16/9",
5583
+ title,
5584
+ onUnlock,
5585
+ onUnlockError
5586
+ }) {
5587
+ const containerRef = useRef14(null);
5588
+ const mediaRef = useRef14(null);
5589
+ const [accessInfo, setAccessInfo] = useState13(null);
5590
+ const [isLoading, setIsLoading] = useState13(true);
5591
+ const [isUnlocking, setIsUnlocking] = useState13(false);
5592
+ const [isUnlocked, setIsUnlocked] = useState13(false);
5593
+ const [unlockedUrl, setUnlockedUrl] = useState13(null);
5594
+ const [error, setError] = useState13(null);
5595
+ const [previewEnded, setPreviewEnded] = useState13(false);
5596
+ useEffect13(() => {
5597
+ async function fetchAccessInfo() {
5598
+ try {
5599
+ const apiUrl = getApiUrl();
5600
+ const siteId = getSiteId();
5601
+ const response = await fetch(`${apiUrl}/api/websites/${siteId}/access/asset/${assetId}`);
5602
+ if (!response.ok) {
5603
+ throw new Error("Failed to fetch access info");
5604
+ }
5605
+ const data = await response.json();
5606
+ setAccessInfo(data);
5607
+ if (!data.requiresAuth && data.url) {
5608
+ setIsUnlocked(true);
5609
+ setUnlockedUrl(data.url);
5610
+ }
5611
+ if (data.requiresAuth && data.folderId) {
5612
+ const storedEmail = getStoredAccess(data.folderId);
5613
+ if (storedEmail) {
5614
+ await tryStoredAccess(data.folderId, storedEmail);
5615
+ }
5616
+ }
5617
+ } catch (err) {
5618
+ console.error("Failed to fetch access info:", err);
5619
+ setError("Unable to load content");
5620
+ } finally {
5621
+ setIsLoading(false);
5622
+ }
5623
+ }
5624
+ fetchAccessInfo();
5625
+ }, [assetId]);
5626
+ const tryStoredAccess = async (folderId, email) => {
5627
+ try {
5628
+ const apiUrl = getApiUrl();
5629
+ const siteId = getSiteId();
5630
+ const response = await fetch(`${apiUrl}/api/websites/${siteId}/access/asset/${assetId}/unlock`, {
5631
+ method: "POST",
5632
+ headers: { "Content-Type": "application/json" },
5633
+ body: JSON.stringify({ email })
5634
+ });
5635
+ if (response.ok) {
5636
+ const result = await response.json();
5637
+ if (result.success) {
5638
+ setIsUnlocked(true);
5639
+ setUnlockedUrl(result.url);
5640
+ return true;
5641
+ }
5642
+ }
5643
+ clearStoredAccess(folderId);
5644
+ return false;
5645
+ } catch {
5646
+ clearStoredAccess(folderId);
5647
+ return false;
5648
+ }
5649
+ };
5650
+ const handleUnlock = useCallback15(
5651
+ async (data) => {
5652
+ if (!accessInfo) return;
5653
+ setIsUnlocking(true);
5654
+ setError(null);
5655
+ try {
5656
+ const apiUrl = getApiUrl();
5657
+ const siteId = getSiteId();
5658
+ const response = await fetch(`${apiUrl}/api/websites/${siteId}/access/asset/${assetId}/unlock`, {
5659
+ method: "POST",
5660
+ headers: { "Content-Type": "application/json" },
5661
+ body: JSON.stringify(data)
5662
+ });
5663
+ const result = await response.json();
5664
+ if (!response.ok) {
5665
+ throw new Error(result.error || "Failed to unlock");
5666
+ }
5667
+ if (result.success) {
5668
+ setIsUnlocked(true);
5669
+ setUnlockedUrl(result.url);
5670
+ if (accessInfo.folderId && data.email) {
5671
+ storeAccess(accessInfo.folderId, data.email);
5672
+ }
5673
+ onUnlock?.();
5674
+ } else {
5675
+ throw new Error(result.error || "Failed to unlock");
5676
+ }
5677
+ } catch (err) {
5678
+ const message = err instanceof Error ? err.message : "Failed to unlock";
5679
+ setError(message);
5680
+ onUnlockError?.(message);
5681
+ } finally {
5682
+ setIsUnlocking(false);
5683
+ }
5684
+ },
5685
+ [assetId, accessInfo, onUnlock, onUnlockError]
5686
+ );
5687
+ const handleTimeUpdate = useCallback15(() => {
5688
+ if (!accessInfo?.showPreview || !mediaRef.current || isUnlocked) return;
5689
+ const media = mediaRef.current;
5690
+ if (media.currentTime >= accessInfo.previewDuration) {
5691
+ media.pause();
5692
+ media.currentTime = 0;
5693
+ setPreviewEnded(true);
5694
+ }
5695
+ }, [accessInfo, isUnlocked]);
5696
+ if (isLoading) {
5697
+ return /* @__PURE__ */ jsx15(
5698
+ "div",
5699
+ {
5700
+ ref: containerRef,
5701
+ className: `ya-protected-container ya-protected-loading ${className || ""}`,
5702
+ style: { aspectRatio: type === "video" ? aspectRatio : void 0 },
5703
+ "data-field-id": fieldId,
5704
+ children: /* @__PURE__ */ jsx15("div", { className: "ya-protected-spinner" })
5705
+ }
5706
+ );
5707
+ }
5708
+ if (error && !accessInfo) {
5709
+ return /* @__PURE__ */ jsx15(
5710
+ "div",
5711
+ {
5712
+ ref: containerRef,
5713
+ className: `ya-protected-container ya-protected-error-state ${className || ""}`,
5714
+ style: { aspectRatio: type === "video" ? aspectRatio : void 0 },
5715
+ "data-field-id": fieldId,
5716
+ children: /* @__PURE__ */ jsx15("div", { className: "ya-protected-error-message", children: error })
5717
+ }
5718
+ );
5719
+ }
5720
+ if (isUnlocked && unlockedUrl) {
5721
+ const resolvedUrl = resolveAssetUrl(unlockedUrl);
5722
+ if (type === "video") {
5723
+ return /* @__PURE__ */ jsxs8(
5724
+ "div",
5725
+ {
5726
+ ref: containerRef,
5727
+ className: `ya-protected-container ya-protected-unlocked ${className || ""}`,
5728
+ style: { aspectRatio },
5729
+ "data-field-id": fieldId,
5730
+ children: [
5731
+ /* @__PURE__ */ jsx15(
5732
+ "video",
5733
+ {
5734
+ ref: mediaRef,
5735
+ src: resolvedUrl,
5736
+ poster: poster ? resolveAssetUrl(poster) : void 0,
5737
+ controls: true,
5738
+ playsInline: true,
5739
+ className: "ya-protected-video"
5740
+ }
5741
+ ),
5742
+ title && /* @__PURE__ */ jsx15("div", { className: "ya-protected-title", children: title })
5743
+ ]
5744
+ }
5745
+ );
5746
+ }
5747
+ return /* @__PURE__ */ jsxs8(
5748
+ "div",
5749
+ {
5750
+ ref: containerRef,
5751
+ className: `ya-protected-container ya-protected-unlocked ya-protected-audio ${className || ""}`,
5752
+ "data-field-id": fieldId,
5753
+ children: [
5754
+ title && /* @__PURE__ */ jsx15("div", { className: "ya-protected-title", children: title }),
5755
+ /* @__PURE__ */ jsx15(
5756
+ "audio",
5757
+ {
5758
+ ref: mediaRef,
5759
+ src: resolvedUrl,
5760
+ controls: true,
5761
+ className: "ya-protected-audio-player"
5762
+ }
5763
+ )
5764
+ ]
5765
+ }
5766
+ );
5767
+ }
5768
+ if (accessInfo) {
5769
+ const showPreviewPlayer = accessInfo.showPreview && !previewEnded && accessInfo.url;
5770
+ return /* @__PURE__ */ jsxs8(
5771
+ "div",
5772
+ {
5773
+ ref: containerRef,
5774
+ className: `ya-protected-container ya-protected-locked ${className || ""}`,
5775
+ style: { aspectRatio: type === "video" ? aspectRatio : void 0 },
5776
+ "data-field-id": fieldId,
5777
+ children: [
5778
+ showPreviewPlayer && type === "video" && /* @__PURE__ */ jsxs8("div", { className: "ya-protected-preview-wrapper", children: [
5779
+ /* @__PURE__ */ jsx15(
5780
+ "video",
5781
+ {
5782
+ ref: mediaRef,
5783
+ src: resolveAssetUrl(accessInfo.url),
5784
+ poster: poster ? resolveAssetUrl(poster) : void 0,
5785
+ controls: true,
5786
+ playsInline: true,
5787
+ className: "ya-protected-video ya-protected-preview",
5788
+ onTimeUpdate: handleTimeUpdate
5789
+ }
5790
+ ),
5791
+ /* @__PURE__ */ jsxs8("div", { className: "ya-protected-preview-badge", children: [
5792
+ "Preview (",
5793
+ accessInfo.previewDuration,
5794
+ "s)"
5795
+ ] })
5796
+ ] }),
5797
+ showPreviewPlayer && type === "audio" && /* @__PURE__ */ jsxs8("div", { className: "ya-protected-preview-wrapper", children: [
5798
+ title && /* @__PURE__ */ jsx15("div", { className: "ya-protected-title", children: title }),
5799
+ /* @__PURE__ */ jsx15(
5800
+ "audio",
5801
+ {
5802
+ ref: mediaRef,
5803
+ src: resolveAssetUrl(accessInfo.url),
5804
+ controls: true,
5805
+ className: "ya-protected-audio-player ya-protected-preview",
5806
+ onTimeUpdate: handleTimeUpdate
5807
+ }
5808
+ ),
5809
+ /* @__PURE__ */ jsxs8("div", { className: "ya-protected-preview-badge", children: [
5810
+ "Preview (",
5811
+ accessInfo.previewDuration,
5812
+ "s)"
5813
+ ] })
5814
+ ] }),
5815
+ (!showPreviewPlayer || previewEnded) && /* @__PURE__ */ jsx15("div", { className: "ya-protected-unlock-overlay", children: /* @__PURE__ */ jsx15(
5816
+ UnlockForm,
5817
+ {
5818
+ accessInfo,
5819
+ onSubmit: handleUnlock,
5820
+ isLoading: isUnlocking,
5821
+ error
5822
+ }
5823
+ ) }),
5824
+ showPreviewPlayer && previewEnded && /* @__PURE__ */ jsxs8("div", { className: "ya-protected-unlock-prompt", children: [
5825
+ /* @__PURE__ */ jsx15(
5826
+ "button",
5827
+ {
5828
+ className: "ya-protected-button",
5829
+ onClick: () => setPreviewEnded(false),
5830
+ children: "Replay Preview"
5831
+ }
5832
+ ),
5833
+ /* @__PURE__ */ jsx15(
5834
+ UnlockForm,
5835
+ {
5836
+ accessInfo,
5837
+ onSubmit: handleUnlock,
5838
+ isLoading: isUnlocking,
5839
+ error
5840
+ }
5841
+ )
5842
+ ] })
5843
+ ]
5844
+ }
5845
+ );
5846
+ }
5847
+ return null;
5848
+ }
5849
+
5850
+ // src/components/YaEmbed.tsx
5851
+ import { useCallback as useCallback16, useEffect as useEffect14, useRef as useRef15, useState as useState14 } from "react";
5852
+
5269
5853
  // src/components/ya-embed.css
5270
5854
  styleInject('.ya-embed-wrapper {\n position: relative;\n display: block;\n width: 100%;\n}\n.ya-embed-wrapper iframe {\n display: block;\n width: 100%;\n height: 100%;\n}\n.ya-embed-container {\n position: relative;\n display: block;\n width: 100%;\n min-width: 80px;\n min-height: 80px;\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-embed-container iframe {\n display: block;\n width: 100%;\n height: 100%;\n pointer-events: none;\n}\n.ya-embed-editable {\n cursor: pointer;\n}\n.ya-embed-editable:hover {\n outline: 2px dashed var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-selected {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: rgba(0, 0, 0, 0.5);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n border-radius: inherit;\n}\n.ya-embed-editable:hover .ya-embed-overlay {\n opacity: 1;\n}\n.ya-embed-selected .ya-embed-overlay {\n opacity: 0;\n}\n.ya-embed-edit-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n background: white;\n border-radius: 50%;\n color: #1a1a1a;\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);\n}\n.ya-embed-edit-icon svg {\n width: 24px;\n height: 24px;\n}\n.ya-embed-edit-label {\n color: white;\n font-size: 14px;\n font-weight: 500;\n text-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);\n}\n.ya-embed-placeholder {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 100%;\n min-height: 120px;\n background: #f3f4f6;\n border: 2px dashed #d1d5db;\n border-radius: 8px;\n color: #6b7280;\n font-size: 14px;\n}\n.ya-embed-placeholder img {\n width: 64px;\n height: auto;\n opacity: 0.5;\n}\n@keyframes ya-embed-success {\n 0% {\n outline-color: var(--color-primary, #d4a574);\n }\n 50% {\n outline-color: #22c55e;\n outline-width: 4px;\n }\n 100% {\n outline-color: var(--color-primary, #d4a574);\n outline-width: 2px;\n }\n}\n.ya-embed-success {\n animation: ya-embed-success 0.4s ease;\n}\n.ya-embed-loading::after {\n content: "";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n rgba(255, 255, 255, 0.3) 50%,\n rgba(255, 255, 255, 0) 100%);\n background-size: 200% 100%;\n animation: ya-embed-shimmer 1.5s infinite;\n}\n@keyframes ya-embed-shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.ya-embed-container:focus {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-container:focus:not(:focus-visible) {\n outline: none;\n}\n.ya-embed-container:focus-visible {\n outline: 3px solid var(--color-primary, #d4a574);\n outline-offset: 4px;\n}\n.ya-embed-small .ya-embed-overlay {\n display: none;\n}\n.ya-embed-twitter {\n min-height: 200px;\n}\n.ya-embed-twitter .twitter-tweet {\n margin: 0 auto !important;\n}\n.ya-embed-wrapper[data-embed-type=spotify],\n.ya-embed-container[data-embed-type=spotify] {\n min-height: 80px;\n}\n.ya-embed-wrapper[data-embed-type=soundcloud],\n.ya-embed-container[data-embed-type=soundcloud] {\n min-height: 166px;\n}\n.ya-embed-wrapper[data-embed-type=instagram] iframe,\n.ya-embed-container[data-embed-type=instagram] iframe {\n min-height: 400px;\n}\n');
5271
5855
 
5272
5856
  // src/components/YaEmbed.tsx
5273
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
5857
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5274
5858
  function parseEmbedUrl(url) {
5275
5859
  if (!url) return null;
5276
5860
  const trimmedUrl = url.trim();
@@ -5385,11 +5969,11 @@ function YaEmbed({
5385
5969
  }) {
5386
5970
  const content = useContent(fieldId);
5387
5971
  const { mode } = content;
5388
- const containerRef = useRef14(null);
5389
- const [isSelected, setIsSelected] = useState13(false);
5390
- const [isHovered, setIsHovered] = useState13(false);
5391
- const [isSmallEmbed, setIsSmallEmbed] = useState13(false);
5392
- const [isInView, setIsInView] = useState13(loading === "eager");
5972
+ const containerRef = useRef15(null);
5973
+ const [isSelected, setIsSelected] = useState14(false);
5974
+ const [isHovered, setIsHovered] = useState14(false);
5975
+ const [isSmallEmbed, setIsSmallEmbed] = useState14(false);
5976
+ const [isInView, setIsInView] = useState14(loading === "eager");
5393
5977
  const rawValue = content.get();
5394
5978
  const parsedValue = parseEmbedValue(rawValue);
5395
5979
  const embedData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
@@ -5397,7 +5981,7 @@ function YaEmbed({
5397
5981
  const embedType = embedData.type || "custom";
5398
5982
  const height = embedData.height;
5399
5983
  const aspectRatio = embedData.aspectRatio || propAspectRatio || "16/9";
5400
- useEffect13(() => {
5984
+ useEffect14(() => {
5401
5985
  if (loading === "eager" || isInView) return;
5402
5986
  const observer = new IntersectionObserver(
5403
5987
  (entries) => {
@@ -5414,7 +5998,7 @@ function YaEmbed({
5414
5998
  }
5415
5999
  return () => observer.disconnect();
5416
6000
  }, [loading, isInView]);
5417
- const handleClick = useCallback15(() => {
6001
+ const handleClick = useCallback16(() => {
5418
6002
  if (mode !== "inline-edit") return;
5419
6003
  if (document.body.classList.contains("builder-selector-active")) return;
5420
6004
  setIsSelected(true);
@@ -5434,7 +6018,7 @@ function YaEmbed({
5434
6018
  "*"
5435
6019
  );
5436
6020
  }, [mode, fieldId, embedData]);
5437
- useEffect13(() => {
6021
+ useEffect14(() => {
5438
6022
  if (mode !== "inline-edit") return;
5439
6023
  const handleMessage2 = (event) => {
5440
6024
  if (event.data?.type === "YA_EMBED_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -5447,7 +6031,7 @@ function YaEmbed({
5447
6031
  window.addEventListener("message", handleMessage2);
5448
6032
  return () => window.removeEventListener("message", handleMessage2);
5449
6033
  }, [mode, fieldId]);
5450
- useEffect13(() => {
6034
+ useEffect14(() => {
5451
6035
  if (mode !== "inline-edit") return;
5452
6036
  const checkSize = () => {
5453
6037
  if (containerRef.current) {
@@ -5459,7 +6043,7 @@ function YaEmbed({
5459
6043
  window.addEventListener("resize", checkSize);
5460
6044
  return () => window.removeEventListener("resize", checkSize);
5461
6045
  }, [mode]);
5462
- useEffect13(() => {
6046
+ useEffect14(() => {
5463
6047
  if (!isSelected || mode !== "inline-edit") return;
5464
6048
  let lastRectKey = "";
5465
6049
  let lastTime = 0;
@@ -5495,17 +6079,17 @@ function YaEmbed({
5495
6079
  }, [isSelected, fieldId, mode]);
5496
6080
  const renderEmbed = (isReadOnly) => {
5497
6081
  if (!src && !isReadOnly) {
5498
- return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-placeholder", children: [
5499
- /* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }),
5500
- /* @__PURE__ */ jsx15("span", { children: "No embed selected" })
6082
+ return /* @__PURE__ */ jsxs9("div", { className: "ya-embed-placeholder", children: [
6083
+ /* @__PURE__ */ jsx16("img", { src: PLACEHOLDER_SVG3, alt: "" }),
6084
+ /* @__PURE__ */ jsx16("span", { children: "No embed selected" })
5501
6085
  ] });
5502
6086
  }
5503
6087
  if (!isInView && loading === "lazy" && !isReadOnly) {
5504
- return /* @__PURE__ */ jsx15("div", { className: "ya-embed-placeholder", style: { aspectRatio }, children: /* @__PURE__ */ jsx15("img", { src: PLACEHOLDER_SVG3, alt: "" }) });
6088
+ return /* @__PURE__ */ jsx16("div", { className: "ya-embed-placeholder", style: { aspectRatio }, children: /* @__PURE__ */ jsx16("img", { src: PLACEHOLDER_SVG3, alt: "" }) });
5505
6089
  }
5506
6090
  if (embedType === "spotify" && src) {
5507
6091
  const embedUrl = buildSpotifyEmbedUrl(src);
5508
- return /* @__PURE__ */ jsx15(
6092
+ return /* @__PURE__ */ jsx16(
5509
6093
  "iframe",
5510
6094
  {
5511
6095
  src: embedUrl,
@@ -5523,7 +6107,7 @@ function YaEmbed({
5523
6107
  }
5524
6108
  if (embedType === "soundcloud" && src) {
5525
6109
  const embedUrl = buildSoundCloudEmbedUrl(src);
5526
- return /* @__PURE__ */ jsx15(
6110
+ return /* @__PURE__ */ jsx16(
5527
6111
  "iframe",
5528
6112
  {
5529
6113
  src: embedUrl,
@@ -5539,14 +6123,14 @@ function YaEmbed({
5539
6123
  );
5540
6124
  }
5541
6125
  if (embedType === "twitter" && src) {
5542
- return /* @__PURE__ */ jsxs8("div", { className: "ya-embed-twitter", children: [
5543
- /* @__PURE__ */ jsx15("blockquote", { className: "twitter-tweet", "data-dnt": "true", children: /* @__PURE__ */ jsx15("a", { href: embedData.originalUrl || `https://twitter.com/i/status/${src}`, children: "Loading tweet..." }) }),
5544
- /* @__PURE__ */ jsx15(TwitterWidgetLoader, {})
6126
+ return /* @__PURE__ */ jsxs9("div", { className: "ya-embed-twitter", children: [
6127
+ /* @__PURE__ */ jsx16("blockquote", { className: "twitter-tweet", "data-dnt": "true", children: /* @__PURE__ */ jsx16("a", { href: embedData.originalUrl || `https://twitter.com/i/status/${src}`, children: "Loading tweet..." }) }),
6128
+ /* @__PURE__ */ jsx16(TwitterWidgetLoader, {})
5545
6129
  ] });
5546
6130
  }
5547
6131
  if (embedType === "instagram" && src) {
5548
6132
  const embedUrl = buildInstagramEmbedUrl(src);
5549
- return /* @__PURE__ */ jsx15(
6133
+ return /* @__PURE__ */ jsx16(
5550
6134
  "iframe",
5551
6135
  {
5552
6136
  src: embedUrl,
@@ -5564,7 +6148,7 @@ function YaEmbed({
5564
6148
  );
5565
6149
  }
5566
6150
  if (embedType === "custom" && src) {
5567
- return /* @__PURE__ */ jsx15(
6151
+ return /* @__PURE__ */ jsx16(
5568
6152
  "iframe",
5569
6153
  {
5570
6154
  src,
@@ -5588,7 +6172,7 @@ function YaEmbed({
5588
6172
  maxWidth: maxWidth ? `${maxWidth}px` : void 0
5589
6173
  };
5590
6174
  if (mode === "read-only") {
5591
- return /* @__PURE__ */ jsx15(
6175
+ return /* @__PURE__ */ jsx16(
5592
6176
  "div",
5593
6177
  {
5594
6178
  ref: containerRef,
@@ -5600,7 +6184,7 @@ function YaEmbed({
5600
6184
  }
5601
6185
  );
5602
6186
  }
5603
- const embedIcon = /* @__PURE__ */ jsxs8(
6187
+ const embedIcon = /* @__PURE__ */ jsxs9(
5604
6188
  "svg",
5605
6189
  {
5606
6190
  width: "24",
@@ -5612,12 +6196,12 @@ function YaEmbed({
5612
6196
  strokeLinecap: "round",
5613
6197
  strokeLinejoin: "round",
5614
6198
  children: [
5615
- /* @__PURE__ */ jsx15("polyline", { points: "16 18 22 12 16 6" }),
5616
- /* @__PURE__ */ jsx15("polyline", { points: "8 6 2 12 8 18" })
6199
+ /* @__PURE__ */ jsx16("polyline", { points: "16 18 22 12 16 6" }),
6200
+ /* @__PURE__ */ jsx16("polyline", { points: "8 6 2 12 8 18" })
5617
6201
  ]
5618
6202
  }
5619
6203
  );
5620
- return /* @__PURE__ */ jsxs8(
6204
+ return /* @__PURE__ */ jsxs9(
5621
6205
  "div",
5622
6206
  {
5623
6207
  ref: containerRef,
@@ -5640,14 +6224,14 @@ function YaEmbed({
5640
6224
  style: wrapperStyle,
5641
6225
  children: [
5642
6226
  renderEmbed(false),
5643
- isSmallEmbed ? /* @__PURE__ */ jsxs8(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
6227
+ isSmallEmbed ? /* @__PURE__ */ jsxs9(YaTooltip, { anchorRef: containerRef, show: isHovered && !isSelected, children: [
5644
6228
  embedIcon,
5645
- /* @__PURE__ */ jsx15("span", { children: "Click to edit" })
6229
+ /* @__PURE__ */ jsx16("span", { children: "Click to edit" })
5646
6230
  ] }) : (
5647
6231
  /* For large embeds: show overlay inside the container */
5648
- /* @__PURE__ */ jsxs8("div", { className: "ya-embed-overlay", children: [
5649
- /* @__PURE__ */ jsx15("div", { className: "ya-embed-edit-icon", children: embedIcon }),
5650
- /* @__PURE__ */ jsx15("span", { className: "ya-embed-edit-label", children: "Click to edit" })
6232
+ /* @__PURE__ */ jsxs9("div", { className: "ya-embed-overlay", children: [
6233
+ /* @__PURE__ */ jsx16("div", { className: "ya-embed-edit-icon", children: embedIcon }),
6234
+ /* @__PURE__ */ jsx16("span", { className: "ya-embed-edit-label", children: "Click to edit" })
5651
6235
  ] })
5652
6236
  )
5653
6237
  ]
@@ -5655,7 +6239,7 @@ function YaEmbed({
5655
6239
  );
5656
6240
  }
5657
6241
  function TwitterWidgetLoader() {
5658
- useEffect13(() => {
6242
+ useEffect14(() => {
5659
6243
  if (window.twttr?.widgets) {
5660
6244
  ;
5661
6245
  window.twttr.widgets.load();
@@ -5676,7 +6260,7 @@ function TwitterWidgetLoader() {
5676
6260
  }
5677
6261
 
5678
6262
  // src/components/YaLink.tsx
5679
- import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect3, useRef as useRef17, useState as useState16, useCallback as useCallback18, useId } from "react";
6263
+ import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect3, useRef as useRef19, useState as useState19, useCallback as useCallback20, useId } from "react";
5680
6264
  import { createPortal as createPortal6 } from "react-dom";
5681
6265
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
5682
6266
  import { BubbleMenu } from "@tiptap/react/menus";
@@ -5686,7 +6270,7 @@ import { Extension as Extension2 } from "@tiptap/core";
5686
6270
  import { Link as WouterLink, useLocation } from "wouter";
5687
6271
 
5688
6272
  // src/components/SafeTriangleBelow.tsx
5689
- import { useEffect as useEffect14, useState as useState14, useRef as useRef15, useCallback as useCallback16 } from "react";
6273
+ import { useEffect as useEffect15, useState as useState15, useRef as useRef16, useCallback as useCallback17 } from "react";
5690
6274
  function SafeTriangleBelow({
5691
6275
  triggerRef,
5692
6276
  popoverRef,
@@ -5694,10 +6278,10 @@ function SafeTriangleBelow({
5694
6278
  onLeave,
5695
6279
  onStayInside
5696
6280
  }) {
5697
- const [bounds, setBounds] = useState14(null);
5698
- const boundsRef = useRef15(bounds);
6281
+ const [bounds, setBounds] = useState15(null);
6282
+ const boundsRef = useRef16(bounds);
5699
6283
  boundsRef.current = bounds;
5700
- useEffect14(() => {
6284
+ useEffect15(() => {
5701
6285
  if (!isVisible || !triggerRef.current || !popoverRef.current) {
5702
6286
  setBounds(null);
5703
6287
  return;
@@ -5715,7 +6299,7 @@ function SafeTriangleBelow({
5715
6299
  }, 10);
5716
6300
  return () => clearTimeout(timer);
5717
6301
  }, [isVisible, triggerRef, popoverRef]);
5718
- const checkMousePosition = useCallback16((e) => {
6302
+ const checkMousePosition = useCallback17((e) => {
5719
6303
  const b = boundsRef.current;
5720
6304
  if (!b) return;
5721
6305
  const { clientX: x, clientY: y } = e;
@@ -5727,7 +6311,7 @@ function SafeTriangleBelow({
5727
6311
  onStayInside?.();
5728
6312
  }
5729
6313
  }, [onLeave, onStayInside]);
5730
- useEffect14(() => {
6314
+ useEffect15(() => {
5731
6315
  if (!isVisible || !bounds) return;
5732
6316
  document.addEventListener("mousemove", checkMousePosition);
5733
6317
  return () => document.removeEventListener("mousemove", checkMousePosition);
@@ -5736,22 +6320,36 @@ function SafeTriangleBelow({
5736
6320
  }
5737
6321
 
5738
6322
  // src/hooks/useSafeTriangle.ts
5739
- import { useState as useState15, useRef as useRef16, useCallback as useCallback17, useEffect as useEffect15 } from "react";
6323
+ import { useState as useState16, useRef as useRef17, useCallback as useCallback18, useEffect as useEffect16 } from "react";
5740
6324
  function useSafeTriangle(options = {}) {
5741
6325
  const { showDelay = 0, hideDelay = 150, enabled = true } = options;
5742
- const [isVisible, setIsVisible] = useState15(false);
5743
- const [isHovering, setIsHovering] = useState15(false);
5744
- const triggerRef = useRef16(null);
5745
- const popoverRef = useRef16(null);
5746
- const showTimeoutRef = useRef16(null);
5747
- const hideTimeoutRef = useRef16(null);
5748
- useEffect15(() => {
6326
+ const [isVisible, setIsVisible] = useState16(false);
6327
+ const [isHovering, setIsHovering] = useState16(false);
6328
+ const triggerRef = useRef17(null);
6329
+ const popoverRef = useRef17(null);
6330
+ const showTimeoutRef = useRef17(null);
6331
+ const hideTimeoutRef = useRef17(null);
6332
+ useEffect16(() => {
5749
6333
  return () => {
5750
6334
  if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
5751
6335
  if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
5752
6336
  };
5753
6337
  }, []);
5754
- const show = useCallback17(() => {
6338
+ useEffect16(() => {
6339
+ if (!enabled) {
6340
+ if (showTimeoutRef.current) {
6341
+ clearTimeout(showTimeoutRef.current);
6342
+ showTimeoutRef.current = null;
6343
+ }
6344
+ if (hideTimeoutRef.current) {
6345
+ clearTimeout(hideTimeoutRef.current);
6346
+ hideTimeoutRef.current = null;
6347
+ }
6348
+ setIsVisible(false);
6349
+ setIsHovering(false);
6350
+ }
6351
+ }, [enabled]);
6352
+ const show = useCallback18(() => {
5755
6353
  if (!enabled) return;
5756
6354
  if (hideTimeoutRef.current) {
5757
6355
  clearTimeout(hideTimeoutRef.current);
@@ -5759,7 +6357,7 @@ function useSafeTriangle(options = {}) {
5759
6357
  }
5760
6358
  setIsVisible(true);
5761
6359
  }, [enabled]);
5762
- const hide = useCallback17(() => {
6360
+ const hide = useCallback18(() => {
5763
6361
  if (showTimeoutRef.current) {
5764
6362
  clearTimeout(showTimeoutRef.current);
5765
6363
  showTimeoutRef.current = null;
@@ -5767,7 +6365,7 @@ function useSafeTriangle(options = {}) {
5767
6365
  setIsVisible(false);
5768
6366
  setIsHovering(false);
5769
6367
  }, []);
5770
- const handleMouseEnter = useCallback17(() => {
6368
+ const handleMouseEnter = useCallback18(() => {
5771
6369
  if (!enabled) return;
5772
6370
  setIsHovering(true);
5773
6371
  if (hideTimeoutRef.current) {
@@ -5782,7 +6380,7 @@ function useSafeTriangle(options = {}) {
5782
6380
  setIsVisible(true);
5783
6381
  }
5784
6382
  }, [showDelay, enabled]);
5785
- const handleMouseLeave = useCallback17(() => {
6383
+ const handleMouseLeave = useCallback18(() => {
5786
6384
  setIsHovering(false);
5787
6385
  if (showTimeoutRef.current) {
5788
6386
  clearTimeout(showTimeoutRef.current);
@@ -5792,16 +6390,16 @@ function useSafeTriangle(options = {}) {
5792
6390
  setIsVisible(false);
5793
6391
  }, hideDelay);
5794
6392
  }, [hideDelay]);
5795
- const handleFocus = useCallback17(() => {
6393
+ const handleFocus = useCallback18(() => {
5796
6394
  if (!enabled) return;
5797
6395
  setIsVisible(true);
5798
6396
  }, [enabled]);
5799
- const handleTriangleLeave = useCallback17(() => {
6397
+ const handleTriangleLeave = useCallback18(() => {
5800
6398
  if (!isHovering) {
5801
6399
  setIsVisible(false);
5802
6400
  }
5803
6401
  }, [isHovering]);
5804
- const handleStayInside = useCallback17(() => {
6402
+ const handleStayInside = useCallback18(() => {
5805
6403
  if (hideTimeoutRef.current) {
5806
6404
  clearTimeout(hideTimeoutRef.current);
5807
6405
  hideTimeoutRef.current = null;
@@ -5828,13 +6426,696 @@ function useSafeTriangle(options = {}) {
5828
6426
  };
5829
6427
  }
5830
6428
 
5831
- // src/components/ya-link.css
5832
- styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-editing .ProseMirror {\n color: #1a1a1a !important;\n caret-color: #1a1a1a;\n}\n.ya-link-editing .ProseMirror p::selection,\n.ya-link-editing .ProseMirror::selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ya-link-editing .ProseMirror p::-moz-selection,\n.ya-link-editing .ProseMirror::-moz-selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ProseMirror-gapcursor {\n display: none !important;\n}\n.ProseMirror .ProseMirror-dropcursor {\n display: none !important;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::selection {\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::-moz-selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::-moz-selection {\n color: inherit;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n z-index: 9999;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: fixed;\n z-index: 10000;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n animation: ya-href-popover-fade-in-above 0.15s ease;\n}\n@keyframes ya-href-popover-fade-in-above {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n.ya-link-edit-popover {\n position: fixed;\n z-index: 10000;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transition: opacity 100ms ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
6429
+ // src/icons/DynamicIcon.tsx
6430
+ import { useEffect as useEffect17, useState as useState17, memo } from "react";
5833
6431
 
5834
- // src/components/YaLink.tsx
5835
- import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5836
- function isInternalPath(path) {
5837
- if (!path) return false;
6432
+ // src/icons/icon-registry.ts
6433
+ var iconCache = /* @__PURE__ */ new Map();
6434
+ var pendingLoads = /* @__PURE__ */ new Map();
6435
+ var registeredLoaders = /* @__PURE__ */ new Map();
6436
+ var MAX_CACHE_SIZE = 100;
6437
+ function registerIcon(name, loader) {
6438
+ registeredLoaders.set(name, loader);
6439
+ }
6440
+ function registerIcons(loaders) {
6441
+ for (const [name, loader] of Object.entries(loaders)) {
6442
+ registeredLoaders.set(name, loader);
6443
+ }
6444
+ }
6445
+ function getIcon(name) {
6446
+ return iconCache.get(name) ?? null;
6447
+ }
6448
+ async function loadIcon(name) {
6449
+ if (iconCache.has(name)) {
6450
+ return iconCache.get(name);
6451
+ }
6452
+ if (pendingLoads.has(name)) {
6453
+ return pendingLoads.get(name);
6454
+ }
6455
+ const loadPromise = (async () => {
6456
+ try {
6457
+ let IconComponent;
6458
+ if (name === "IconBrandAppleMusic") {
6459
+ const customModule = await Promise.resolve().then(() => (init_custom_icons(), custom_icons_exports));
6460
+ IconComponent = customModule.IconBrandAppleMusic;
6461
+ } else if (registeredLoaders.has(name)) {
6462
+ const loader = registeredLoaders.get(name);
6463
+ const module = await loader();
6464
+ IconComponent = module.default;
6465
+ } else {
6466
+ const module = await import("@tabler/icons-react");
6467
+ IconComponent = module[name];
6468
+ }
6469
+ if (!IconComponent) {
6470
+ console.warn(`Icon "${name}" not found in @tabler/icons-react or custom icons`);
6471
+ return null;
6472
+ }
6473
+ if (iconCache.size >= MAX_CACHE_SIZE) {
6474
+ const firstKey = iconCache.keys().next().value;
6475
+ if (firstKey) {
6476
+ iconCache.delete(firstKey);
6477
+ }
6478
+ }
6479
+ iconCache.set(name, IconComponent);
6480
+ return IconComponent;
6481
+ } catch (error) {
6482
+ console.error(`Failed to load icon "${name}":`, error);
6483
+ return null;
6484
+ } finally {
6485
+ pendingLoads.delete(name);
6486
+ }
6487
+ })();
6488
+ pendingLoads.set(name, loadPromise);
6489
+ return loadPromise;
6490
+ }
6491
+ async function preloadIcons(names) {
6492
+ await Promise.all(names.map(loadIcon));
6493
+ }
6494
+ function isIconLoaded(name) {
6495
+ return iconCache.has(name);
6496
+ }
6497
+
6498
+ // src/icons/DynamicIcon.tsx
6499
+ import { Fragment as Fragment4, jsx as jsx17 } from "react/jsx-runtime";
6500
+ function DynamicIconComponent({
6501
+ name,
6502
+ fallback = null,
6503
+ className,
6504
+ size = 24,
6505
+ stroke = 2,
6506
+ ...props
6507
+ }) {
6508
+ const cachedIcon = getIcon(name);
6509
+ const [Icon, setIcon] = useState17(cachedIcon);
6510
+ const [isLoading, setIsLoading] = useState17(!cachedIcon && !!name);
6511
+ useEffect17(() => {
6512
+ if (!name) {
6513
+ setIcon(null);
6514
+ setIsLoading(false);
6515
+ return;
6516
+ }
6517
+ const cached = getIcon(name);
6518
+ if (cached) {
6519
+ setIcon(cached);
6520
+ setIsLoading(false);
6521
+ return;
6522
+ }
6523
+ setIsLoading(true);
6524
+ let cancelled = false;
6525
+ loadIcon(name).then((LoadedIcon) => {
6526
+ if (!cancelled) {
6527
+ setIcon(LoadedIcon);
6528
+ setIsLoading(false);
6529
+ }
6530
+ });
6531
+ return () => {
6532
+ cancelled = true;
6533
+ };
6534
+ }, [name]);
6535
+ if (!name) {
6536
+ return null;
6537
+ }
6538
+ if (isLoading || !Icon) {
6539
+ if (fallback) {
6540
+ return /* @__PURE__ */ jsx17(Fragment4, { children: fallback });
6541
+ }
6542
+ return /* @__PURE__ */ jsx17(
6543
+ "span",
6544
+ {
6545
+ className,
6546
+ style: {
6547
+ display: "inline-flex",
6548
+ width: size,
6549
+ height: size
6550
+ },
6551
+ "aria-hidden": "true"
6552
+ }
6553
+ );
6554
+ }
6555
+ return /* @__PURE__ */ jsx17(Icon, { size, stroke, className, ...props });
6556
+ }
6557
+ var DynamicIcon = memo(DynamicIconComponent);
6558
+
6559
+ // src/components/IconPicker.tsx
6560
+ import { useState as useState18, useEffect as useEffect18, useCallback as useCallback19, useRef as useRef18, useMemo as useMemo7 } from "react";
6561
+
6562
+ // src/icons/icon-metadata.ts
6563
+ var ICON_METADATA = [
6564
+ // ============================================================================
6565
+ // BRAND / SOCIAL MEDIA (~30 icons)
6566
+ // ============================================================================
6567
+ { name: "IconBrandTwitter", category: "brand", keywords: ["twitter", "x", "social", "tweet"] },
6568
+ { name: "IconBrandX", category: "brand", keywords: ["twitter", "x", "social"] },
6569
+ { name: "IconBrandFacebook", category: "brand", keywords: ["facebook", "fb", "social", "meta"] },
6570
+ { name: "IconBrandInstagram", category: "brand", keywords: ["instagram", "ig", "social", "photo"] },
6571
+ { name: "IconBrandLinkedin", category: "brand", keywords: ["linkedin", "professional", "social", "job"] },
6572
+ { name: "IconBrandYoutube", category: "brand", keywords: ["youtube", "video", "social", "stream"] },
6573
+ { name: "IconBrandTiktok", category: "brand", keywords: ["tiktok", "video", "social", "short"] },
6574
+ { name: "IconBrandSpotify", category: "brand", keywords: ["spotify", "music", "streaming", "audio"] },
6575
+ { name: "IconBrandApple", category: "brand", keywords: ["apple", "mac", "ios", "iphone"] },
6576
+ { name: "IconBrandApplePodcast", category: "brand", keywords: ["apple", "podcast", "audio"] },
6577
+ { name: "IconBrandAppleMusic", category: "brand", keywords: ["apple", "music", "streaming", "audio", "itunes"] },
6578
+ { name: "IconBrandGithub", category: "brand", keywords: ["github", "code", "git", "developer"] },
6579
+ { name: "IconBrandDiscord", category: "brand", keywords: ["discord", "chat", "gaming", "community"] },
6580
+ { name: "IconBrandSlack", category: "brand", keywords: ["slack", "chat", "work", "team"] },
6581
+ { name: "IconBrandWhatsapp", category: "brand", keywords: ["whatsapp", "message", "chat", "phone"] },
6582
+ { name: "IconBrandTelegram", category: "brand", keywords: ["telegram", "message", "chat"] },
6583
+ { name: "IconBrandSnapchat", category: "brand", keywords: ["snapchat", "snap", "social", "photo"] },
6584
+ { name: "IconBrandPinterest", category: "brand", keywords: ["pinterest", "pin", "social", "image"] },
6585
+ { name: "IconBrandDribbble", category: "brand", keywords: ["dribbble", "design", "portfolio"] },
6586
+ { name: "IconBrandBehance", category: "brand", keywords: ["behance", "design", "portfolio", "adobe"] },
6587
+ { name: "IconBrandFigma", category: "brand", keywords: ["figma", "design", "ui", "prototype"] },
6588
+ { name: "IconBrandStripe", category: "brand", keywords: ["stripe", "payment", "money"] },
6589
+ { name: "IconBrandPaypal", category: "brand", keywords: ["paypal", "payment", "money"] },
6590
+ { name: "IconBrandAmazon", category: "brand", keywords: ["amazon", "shop", "ecommerce"] },
6591
+ { name: "IconBrandGoogle", category: "brand", keywords: ["google", "search", "gmail"] },
6592
+ { name: "IconBrandMedium", category: "brand", keywords: ["medium", "blog", "writing", "article"] },
6593
+ { name: "IconBrandReddit", category: "brand", keywords: ["reddit", "social", "community", "forum"] },
6594
+ { name: "IconBrandTwitch", category: "brand", keywords: ["twitch", "stream", "gaming", "video"] },
6595
+ { name: "IconBrandSoundcloud", category: "brand", keywords: ["soundcloud", "music", "audio", "stream"] },
6596
+ { name: "IconBrandVimeo", category: "brand", keywords: ["vimeo", "video", "film"] },
6597
+ { name: "IconBrandPatreon", category: "brand", keywords: ["patreon", "creator", "support", "subscription"] },
6598
+ // ============================================================================
6599
+ // COMMUNICATION (~15 icons)
6600
+ // ============================================================================
6601
+ { name: "IconMail", category: "communication", keywords: ["mail", "email", "envelope", "message"] },
6602
+ { name: "IconMailOpened", category: "communication", keywords: ["mail", "email", "open", "read"] },
6603
+ { name: "IconInbox", category: "communication", keywords: ["inbox", "mail", "message"] },
6604
+ { name: "IconSend", category: "communication", keywords: ["send", "submit", "message", "arrow"] },
6605
+ { name: "IconPhone", category: "communication", keywords: ["phone", "call", "contact", "mobile"] },
6606
+ { name: "IconPhoneCall", category: "communication", keywords: ["phone", "call", "ringing"] },
6607
+ { name: "IconMessage", category: "communication", keywords: ["message", "chat", "bubble", "sms"] },
6608
+ { name: "IconMessageCircle", category: "communication", keywords: ["message", "chat", "bubble"] },
6609
+ { name: "IconMessages", category: "communication", keywords: ["messages", "chat", "conversation"] },
6610
+ { name: "IconAt", category: "communication", keywords: ["at", "email", "mention", "address"] },
6611
+ { name: "IconBell", category: "communication", keywords: ["bell", "notification", "alert"] },
6612
+ { name: "IconBellRinging", category: "communication", keywords: ["bell", "notification", "alert", "ring"] },
6613
+ { name: "IconBroadcast", category: "communication", keywords: ["broadcast", "live", "stream", "radio"] },
6614
+ { name: "IconMicrophone", category: "communication", keywords: ["microphone", "audio", "voice", "record"] },
6615
+ { name: "IconVideo", category: "communication", keywords: ["video", "camera", "record", "call"] },
6616
+ // ============================================================================
6617
+ // MEDIA (~20 icons)
6618
+ // ============================================================================
6619
+ { name: "IconPlayerPlay", category: "media", keywords: ["play", "video", "start", "media"] },
6620
+ { name: "IconPlayerPause", category: "media", keywords: ["pause", "stop", "media"] },
6621
+ { name: "IconPlayerStop", category: "media", keywords: ["stop", "media", "end"] },
6622
+ { name: "IconPlayerSkipForward", category: "media", keywords: ["skip", "forward", "next"] },
6623
+ { name: "IconPlayerSkipBack", category: "media", keywords: ["skip", "back", "previous"] },
6624
+ { name: "IconPlayerRecord", category: "media", keywords: ["record", "recording", "media"] },
6625
+ { name: "IconVolume", category: "media", keywords: ["volume", "sound", "audio", "speaker"] },
6626
+ { name: "IconVolume2", category: "media", keywords: ["volume", "sound", "audio", "medium"] },
6627
+ { name: "IconVolume3", category: "media", keywords: ["volume", "sound", "audio", "high"] },
6628
+ { name: "IconVolumeOff", category: "media", keywords: ["volume", "mute", "silent", "off"] },
6629
+ { name: "IconMusic", category: "media", keywords: ["music", "audio", "note", "song"] },
6630
+ { name: "IconPlaylist", category: "media", keywords: ["playlist", "music", "queue", "list"] },
6631
+ { name: "IconHeadphones", category: "media", keywords: ["headphones", "audio", "music", "listen"] },
6632
+ { name: "IconCamera", category: "media", keywords: ["camera", "photo", "picture", "capture"] },
6633
+ { name: "IconPhoto", category: "media", keywords: ["photo", "image", "picture", "gallery"] },
6634
+ { name: "IconMovie", category: "media", keywords: ["movie", "film", "video", "cinema"] },
6635
+ { name: "IconScreenShare", category: "media", keywords: ["screen", "share", "present", "display"] },
6636
+ { name: "IconCast", category: "media", keywords: ["cast", "chromecast", "stream", "tv"] },
6637
+ { name: "IconPodium", category: "media", keywords: ["podium", "present", "speech", "stage"] },
6638
+ { name: "IconVinyl", category: "media", keywords: ["vinyl", "record", "music", "retro"] },
6639
+ // ============================================================================
6640
+ // NAVIGATION (~20 icons)
6641
+ // ============================================================================
6642
+ { name: "IconArrowRight", category: "navigation", keywords: ["arrow", "right", "next", "forward"] },
6643
+ { name: "IconArrowLeft", category: "navigation", keywords: ["arrow", "left", "back", "previous"] },
6644
+ { name: "IconArrowUp", category: "navigation", keywords: ["arrow", "up", "top"] },
6645
+ { name: "IconArrowDown", category: "navigation", keywords: ["arrow", "down", "bottom"] },
6646
+ { name: "IconArrowUpRight", category: "navigation", keywords: ["arrow", "external", "link", "open"] },
6647
+ { name: "IconChevronRight", category: "navigation", keywords: ["chevron", "right", "next", "expand"] },
6648
+ { name: "IconChevronLeft", category: "navigation", keywords: ["chevron", "left", "back", "collapse"] },
6649
+ { name: "IconChevronUp", category: "navigation", keywords: ["chevron", "up", "expand"] },
6650
+ { name: "IconChevronDown", category: "navigation", keywords: ["chevron", "down", "dropdown", "collapse"] },
6651
+ { name: "IconMenu2", category: "navigation", keywords: ["menu", "hamburger", "nav", "mobile"] },
6652
+ { name: "IconX", category: "navigation", keywords: ["close", "x", "cancel", "remove"] },
6653
+ { name: "IconHome", category: "navigation", keywords: ["home", "house", "main", "start"] },
6654
+ { name: "IconSearch", category: "navigation", keywords: ["search", "find", "magnify", "lookup"] },
6655
+ { name: "IconExternalLink", category: "navigation", keywords: ["external", "link", "open", "new"] },
6656
+ { name: "IconLink", category: "navigation", keywords: ["link", "chain", "url", "connect"] },
6657
+ { name: "IconAnchor", category: "navigation", keywords: ["anchor", "link", "section", "scroll"] },
6658
+ { name: "IconMapPin", category: "navigation", keywords: ["map", "pin", "location", "place"] },
6659
+ { name: "IconMap", category: "navigation", keywords: ["map", "location", "directions"] },
6660
+ { name: "IconCompass", category: "navigation", keywords: ["compass", "direction", "explore", "navigate"] },
6661
+ { name: "IconRefresh", category: "navigation", keywords: ["refresh", "reload", "update", "sync"] },
6662
+ // ============================================================================
6663
+ // COMMERCE (~20 icons)
6664
+ // ============================================================================
6665
+ { name: "IconShoppingCart", category: "commerce", keywords: ["cart", "shop", "buy", "ecommerce"] },
6666
+ { name: "IconShoppingBag", category: "commerce", keywords: ["bag", "shop", "buy", "store"] },
6667
+ { name: "IconBasket", category: "commerce", keywords: ["basket", "shop", "buy", "cart"] },
6668
+ { name: "IconCreditCard", category: "commerce", keywords: ["credit", "card", "payment", "pay"] },
6669
+ { name: "IconWallet", category: "commerce", keywords: ["wallet", "money", "payment", "cash"] },
6670
+ { name: "IconCash", category: "commerce", keywords: ["cash", "money", "payment", "dollar"] },
6671
+ { name: "IconReceipt", category: "commerce", keywords: ["receipt", "invoice", "bill", "payment"] },
6672
+ { name: "IconTruck", category: "commerce", keywords: ["truck", "delivery", "shipping", "transport"] },
6673
+ { name: "IconPackage", category: "commerce", keywords: ["package", "box", "shipping", "delivery"] },
6674
+ { name: "IconGift", category: "commerce", keywords: ["gift", "present", "reward", "prize"] },
6675
+ { name: "IconTicket", category: "commerce", keywords: ["ticket", "event", "coupon", "pass"] },
6676
+ { name: "IconTag", category: "commerce", keywords: ["tag", "label", "price", "sale"] },
6677
+ { name: "IconTags", category: "commerce", keywords: ["tags", "labels", "categories"] },
6678
+ { name: "IconDiscount", category: "commerce", keywords: ["discount", "sale", "percent", "offer"] },
6679
+ { name: "IconBuildingStore", category: "commerce", keywords: ["store", "shop", "building", "retail"] },
6680
+ { name: "IconStarFilled", category: "commerce", keywords: ["star", "rating", "review", "favorite"] },
6681
+ { name: "IconStar", category: "commerce", keywords: ["star", "rating", "review", "favorite"] },
6682
+ { name: "IconHeart", category: "commerce", keywords: ["heart", "like", "love", "favorite", "wishlist"] },
6683
+ { name: "IconHeartFilled", category: "commerce", keywords: ["heart", "like", "love", "favorite", "wishlist"] },
6684
+ { name: "IconCoin", category: "commerce", keywords: ["coin", "money", "currency", "token"] },
6685
+ // ============================================================================
6686
+ // UI ELEMENTS (~25 icons)
6687
+ // ============================================================================
6688
+ { name: "IconPlus", category: "ui", keywords: ["plus", "add", "new", "create"] },
6689
+ { name: "IconMinus", category: "ui", keywords: ["minus", "remove", "subtract"] },
6690
+ { name: "IconCheck", category: "ui", keywords: ["check", "done", "complete", "success"] },
6691
+ { name: "IconCircleCheck", category: "ui", keywords: ["check", "done", "complete", "circle"] },
6692
+ { name: "IconCircleX", category: "ui", keywords: ["close", "error", "fail", "circle"] },
6693
+ { name: "IconAlertCircle", category: "ui", keywords: ["alert", "warning", "error", "info"] },
6694
+ { name: "IconAlertTriangle", category: "ui", keywords: ["alert", "warning", "caution", "danger"] },
6695
+ { name: "IconInfoCircle", category: "ui", keywords: ["info", "information", "help", "about"] },
6696
+ { name: "IconQuestionMark", category: "ui", keywords: ["question", "help", "faq", "support"] },
6697
+ { name: "IconHelp", category: "ui", keywords: ["help", "support", "question", "assist"] },
6698
+ { name: "IconSettings", category: "ui", keywords: ["settings", "gear", "config", "preferences"] },
6699
+ { name: "IconAdjustments", category: "ui", keywords: ["adjustments", "settings", "sliders", "filter"] },
6700
+ { name: "IconFilter", category: "ui", keywords: ["filter", "sort", "funnel"] },
6701
+ { name: "IconDotsVertical", category: "ui", keywords: ["dots", "menu", "more", "options"] },
6702
+ { name: "IconDots", category: "ui", keywords: ["dots", "menu", "more", "options", "horizontal"] },
6703
+ { name: "IconEdit", category: "ui", keywords: ["edit", "pencil", "modify", "write"] },
6704
+ { name: "IconTrash", category: "ui", keywords: ["trash", "delete", "remove", "bin"] },
6705
+ { name: "IconCopy", category: "ui", keywords: ["copy", "duplicate", "clone"] },
6706
+ { name: "IconDownload", category: "ui", keywords: ["download", "save", "export", "arrow"] },
6707
+ { name: "IconUpload", category: "ui", keywords: ["upload", "import", "add", "arrow"] },
6708
+ { name: "IconShare", category: "ui", keywords: ["share", "social", "send", "export"] },
6709
+ { name: "IconShare2", category: "ui", keywords: ["share", "network", "connect"] },
6710
+ { name: "IconEye", category: "ui", keywords: ["eye", "view", "visible", "show"] },
6711
+ { name: "IconEyeOff", category: "ui", keywords: ["eye", "hidden", "invisible", "hide"] },
6712
+ { name: "IconLock", category: "ui", keywords: ["lock", "secure", "private", "password"] },
6713
+ { name: "IconLockOpen", category: "ui", keywords: ["unlock", "open", "public", "access"] },
6714
+ // ============================================================================
6715
+ // FILES & DOCUMENTS (~15 icons)
6716
+ // ============================================================================
6717
+ { name: "IconFile", category: "files", keywords: ["file", "document", "page"] },
6718
+ { name: "IconFileText", category: "files", keywords: ["file", "document", "text", "page"] },
6719
+ { name: "IconFileTypePdf", category: "files", keywords: ["pdf", "file", "document", "adobe"] },
6720
+ { name: "IconFileMusic", category: "files", keywords: ["file", "music", "audio", "mp3"] },
6721
+ { name: "IconVideo", category: "files", keywords: ["file", "video", "movie", "mp4"] },
6722
+ { name: "IconPhoto", category: "files", keywords: ["file", "image", "photo", "picture"] },
6723
+ { name: "IconFileCode", category: "files", keywords: ["file", "code", "programming", "dev"] },
6724
+ { name: "IconFileZip", category: "files", keywords: ["file", "zip", "archive", "compress"] },
6725
+ { name: "IconFolder", category: "files", keywords: ["folder", "directory", "files"] },
6726
+ { name: "IconFolderOpen", category: "files", keywords: ["folder", "open", "directory"] },
6727
+ { name: "IconClipboard", category: "files", keywords: ["clipboard", "paste", "copy"] },
6728
+ { name: "IconClipboardCheck", category: "files", keywords: ["clipboard", "done", "complete"] },
6729
+ { name: "IconNotes", category: "files", keywords: ["notes", "document", "memo", "write"] },
6730
+ { name: "IconBook", category: "files", keywords: ["book", "read", "documentation", "manual"] },
6731
+ { name: "IconBookmark", category: "files", keywords: ["bookmark", "save", "favorite", "mark"] },
6732
+ // ============================================================================
6733
+ // WEATHER (~10 icons)
6734
+ // ============================================================================
6735
+ { name: "IconSun", category: "weather", keywords: ["sun", "sunny", "day", "bright"] },
6736
+ { name: "IconMoon", category: "weather", keywords: ["moon", "night", "dark", "sleep"] },
6737
+ { name: "IconCloud", category: "weather", keywords: ["cloud", "cloudy", "weather"] },
6738
+ { name: "IconCloudRain", category: "weather", keywords: ["cloud", "rain", "weather", "rainy"] },
6739
+ { name: "IconCloudSnow", category: "weather", keywords: ["cloud", "snow", "weather", "winter"] },
6740
+ { name: "IconWind", category: "weather", keywords: ["wind", "windy", "weather", "air"] },
6741
+ { name: "IconUmbrella", category: "weather", keywords: ["umbrella", "rain", "weather", "protection"] },
6742
+ { name: "IconTemperature", category: "weather", keywords: ["temperature", "thermometer", "weather"] },
6743
+ { name: "IconFlame", category: "weather", keywords: ["flame", "fire", "hot", "trending"] },
6744
+ { name: "IconSnowflake", category: "weather", keywords: ["snowflake", "snow", "winter", "cold"] },
6745
+ // ============================================================================
6746
+ // MISCELLANEOUS (~15 icons)
6747
+ // ============================================================================
6748
+ { name: "IconUser", category: "misc", keywords: ["user", "person", "account", "profile"] },
6749
+ { name: "IconUsers", category: "misc", keywords: ["users", "people", "team", "group"] },
6750
+ { name: "IconUserCircle", category: "misc", keywords: ["user", "avatar", "profile", "account"] },
6751
+ { name: "IconBriefcase", category: "misc", keywords: ["briefcase", "work", "job", "business"] },
6752
+ { name: "IconBuilding", category: "misc", keywords: ["building", "office", "company", "business"] },
6753
+ { name: "IconCalendar", category: "misc", keywords: ["calendar", "date", "schedule", "event"] },
6754
+ { name: "IconCalendarEvent", category: "misc", keywords: ["calendar", "event", "schedule", "meeting"] },
6755
+ { name: "IconClock", category: "misc", keywords: ["clock", "time", "hour", "schedule"] },
6756
+ { name: "IconHourglass", category: "misc", keywords: ["hourglass", "time", "wait", "timer"] },
6757
+ { name: "IconRocket", category: "misc", keywords: ["rocket", "launch", "startup", "fast"] },
6758
+ { name: "IconBolt", category: "misc", keywords: ["bolt", "lightning", "fast", "power"] },
6759
+ { name: "IconSparkles", category: "misc", keywords: ["sparkles", "magic", "new", "ai"] },
6760
+ { name: "IconTrophy", category: "misc", keywords: ["trophy", "award", "winner", "achievement"] },
6761
+ { name: "IconTarget", category: "misc", keywords: ["target", "goal", "aim", "focus"] },
6762
+ { name: "IconWorld", category: "misc", keywords: ["world", "globe", "earth", "international"] }
6763
+ ];
6764
+ var ICON_CATEGORIES = {
6765
+ brand: "Social & Brands",
6766
+ communication: "Communication",
6767
+ media: "Media",
6768
+ navigation: "Navigation",
6769
+ commerce: "Commerce",
6770
+ ui: "UI Elements",
6771
+ files: "Files",
6772
+ weather: "Weather",
6773
+ misc: "Miscellaneous"
6774
+ };
6775
+ var ICON_ALIASES = {
6776
+ // Social media rebrands & abbreviations
6777
+ "x": ["IconBrandTwitter", "IconBrandX", "IconX"],
6778
+ "tweet": ["IconBrandTwitter", "IconBrandX"],
6779
+ "bird": ["IconBrandTwitter"],
6780
+ "ig": ["IconBrandInstagram"],
6781
+ "insta": ["IconBrandInstagram"],
6782
+ "gram": ["IconBrandInstagram"],
6783
+ "fb": ["IconBrandFacebook"],
6784
+ "meta": ["IconBrandFacebook", "IconBrandInstagram", "IconBrandWhatsapp"],
6785
+ "li": ["IconBrandLinkedin"],
6786
+ "yt": ["IconBrandYoutube"],
6787
+ "tt": ["IconBrandTiktok"],
6788
+ "gh": ["IconBrandGithub"],
6789
+ "wa": ["IconBrandWhatsapp"],
6790
+ "am": ["IconBrandAppleMusic"],
6791
+ "applemusic": ["IconBrandAppleMusic"],
6792
+ "itunes": ["IconBrandAppleMusic"],
6793
+ // Common abbreviations
6794
+ "email": ["IconMail", "IconMailOpened", "IconInbox", "IconAt"],
6795
+ "envelope": ["IconMail", "IconMailOpened"],
6796
+ "telephone": ["IconPhone", "IconPhoneCall"],
6797
+ "mobile": ["IconPhone", "IconPhoneCall"],
6798
+ "cell": ["IconPhone", "IconPhoneCall"],
6799
+ "sms": ["IconMessage", "IconMessageCircle", "IconMessages"],
6800
+ "txt": ["IconMessage", "IconMessageCircle"],
6801
+ "text": ["IconMessage", "IconMessageCircle", "IconFileText"],
6802
+ // Commerce
6803
+ "basket": ["IconShoppingCart", "IconShoppingBag", "IconBasket"],
6804
+ "buy": ["IconShoppingCart", "IconShoppingBag", "IconCreditCard"],
6805
+ "purchase": ["IconShoppingCart", "IconCreditCard", "IconReceipt"],
6806
+ "checkout": ["IconShoppingCart", "IconCreditCard"],
6807
+ "pay": ["IconCreditCard", "IconWallet", "IconCash", "IconBrandStripe", "IconBrandPaypal"],
6808
+ "money": ["IconCash", "IconWallet", "IconCoin", "IconCreditCard"],
6809
+ "dollar": ["IconCash", "IconCoin"],
6810
+ "ship": ["IconTruck", "IconPackage"],
6811
+ "deliver": ["IconTruck", "IconPackage"],
6812
+ // Common UI terms
6813
+ "close": ["IconX", "IconCircleX"],
6814
+ "cancel": ["IconX", "IconCircleX"],
6815
+ "remove": ["IconX", "IconTrash", "IconMinus"],
6816
+ "delete": ["IconTrash", "IconX"],
6817
+ "add": ["IconPlus", "IconUpload"],
6818
+ "new": ["IconPlus", "IconSparkles"],
6819
+ "create": ["IconPlus", "IconEdit"],
6820
+ "ok": ["IconCheck", "IconCircleCheck"],
6821
+ "yes": ["IconCheck", "IconCircleCheck"],
6822
+ "done": ["IconCheck", "IconCircleCheck", "IconClipboardCheck"],
6823
+ "complete": ["IconCheck", "IconCircleCheck"],
6824
+ "success": ["IconCheck", "IconCircleCheck"],
6825
+ "error": ["IconCircleX", "IconAlertCircle", "IconAlertTriangle"],
6826
+ "warning": ["IconAlertTriangle", "IconAlertCircle"],
6827
+ "info": ["IconInfoCircle", "IconHelp"],
6828
+ "help": ["IconHelp", "IconQuestionMark", "IconInfoCircle"],
6829
+ "faq": ["IconQuestionMark", "IconHelp"],
6830
+ "gear": ["IconSettings", "IconAdjustments"],
6831
+ "cog": ["IconSettings"],
6832
+ "config": ["IconSettings", "IconAdjustments"],
6833
+ "prefs": ["IconSettings", "IconAdjustments"],
6834
+ "menu": ["IconMenu2", "IconDotsVertical", "IconDotsHorizontal"],
6835
+ "hamburger": ["IconMenu2"],
6836
+ "more": ["IconDotsVertical", "IconDotsHorizontal"],
6837
+ "options": ["IconDotsVertical", "IconDotsHorizontal", "IconSettings"],
6838
+ // Navigation
6839
+ "next": ["IconArrowRight", "IconChevronRight", "IconPlayerSkipForward"],
6840
+ "prev": ["IconArrowLeft", "IconChevronLeft", "IconPlayerSkipBack"],
6841
+ "previous": ["IconArrowLeft", "IconChevronLeft", "IconPlayerSkipBack"],
6842
+ "back": ["IconArrowLeft", "IconChevronLeft"],
6843
+ "forward": ["IconArrowRight", "IconChevronRight", "IconPlayerSkipForward"],
6844
+ "up": ["IconArrowUp", "IconChevronUp"],
6845
+ "down": ["IconArrowDown", "IconChevronDown"],
6846
+ "external": ["IconExternalLink", "IconArrowUpRight"],
6847
+ "outbound": ["IconExternalLink", "IconArrowUpRight"],
6848
+ // Media
6849
+ "start": ["IconPlayerPlay"],
6850
+ "stop": ["IconPlayerStop", "IconPlayerPause"],
6851
+ "mute": ["IconVolumeOff"],
6852
+ "silent": ["IconVolumeOff", "IconBellOff"],
6853
+ "audio": ["IconVolume", "IconMusic", "IconHeadphones", "IconMicrophone"],
6854
+ "sound": ["IconVolume", "IconVolume2", "IconVolume3"],
6855
+ "speaker": ["IconVolume", "IconVolume2", "IconVolume3"],
6856
+ "mic": ["IconMicrophone"],
6857
+ "cam": ["IconCamera", "IconVideo"],
6858
+ "pic": ["IconPhoto", "IconCamera", "IconFileImage"],
6859
+ "img": ["IconPhoto", "IconFileImage"],
6860
+ "image": ["IconPhoto", "IconFileImage"],
6861
+ "picture": ["IconPhoto", "IconFileImage"],
6862
+ // Misc
6863
+ "person": ["IconUser", "IconUserCircle"],
6864
+ "profile": ["IconUser", "IconUserCircle"],
6865
+ "account": ["IconUser", "IconUserCircle"],
6866
+ "avatar": ["IconUserCircle"],
6867
+ "people": ["IconUsers"],
6868
+ "team": ["IconUsers"],
6869
+ "group": ["IconUsers"],
6870
+ "date": ["IconCalendar", "IconCalendarEvent"],
6871
+ "schedule": ["IconCalendar", "IconCalendarEvent", "IconClock"],
6872
+ "event": ["IconCalendar", "IconCalendarEvent", "IconTicket"],
6873
+ "time": ["IconClock", "IconHourglass"],
6874
+ "hour": ["IconClock"],
6875
+ "fast": ["IconRocket", "IconBolt"],
6876
+ "quick": ["IconRocket", "IconBolt"],
6877
+ "magic": ["IconSparkles"],
6878
+ "ai": ["IconSparkles", "IconRocket"],
6879
+ "globe": ["IconWorld"],
6880
+ "earth": ["IconWorld"],
6881
+ "international": ["IconWorld"],
6882
+ "hot": ["IconFlame", "IconTrending"],
6883
+ "fire": ["IconFlame"],
6884
+ "trending": ["IconFlame"]
6885
+ };
6886
+ function levenshteinDistance(str1, str2) {
6887
+ const m = str1.length;
6888
+ const n = str2.length;
6889
+ if (m === 0) return n;
6890
+ if (n === 0) return m;
6891
+ const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
6892
+ for (let i = 0; i <= m; i++) dp[i][0] = i;
6893
+ for (let j = 0; j <= n; j++) dp[0][j] = j;
6894
+ for (let i = 1; i <= m; i++) {
6895
+ for (let j = 1; j <= n; j++) {
6896
+ const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
6897
+ dp[i][j] = Math.min(
6898
+ dp[i - 1][j] + 1,
6899
+ // deletion
6900
+ dp[i][j - 1] + 1,
6901
+ // insertion
6902
+ dp[i - 1][j - 1] + cost
6903
+ // substitution
6904
+ );
6905
+ }
6906
+ }
6907
+ return dp[m][n];
6908
+ }
6909
+ function fuzzyMatch(query, target) {
6910
+ if (query.length < 3) return false;
6911
+ const threshold = query.length <= 5 ? 1 : 2;
6912
+ return levenshteinDistance(query, target) <= threshold;
6913
+ }
6914
+ function getIconsByCategory(category) {
6915
+ return ICON_METADATA.filter((icon) => icon.category === category);
6916
+ }
6917
+ function searchIcons(query) {
6918
+ const lowerQuery = query.toLowerCase().trim();
6919
+ if (!lowerQuery) return ICON_METADATA;
6920
+ const matches = /* @__PURE__ */ new Map();
6921
+ const addMatch = (iconName, score) => {
6922
+ const existing = matches.get(iconName);
6923
+ if (existing === void 0 || score < existing) {
6924
+ matches.set(iconName, score);
6925
+ }
6926
+ };
6927
+ const aliasMatches = ICON_ALIASES[lowerQuery];
6928
+ if (aliasMatches) {
6929
+ aliasMatches.forEach((iconName) => addMatch(iconName, 0));
6930
+ }
6931
+ for (const icon of ICON_METADATA) {
6932
+ const lowerName = icon.name.toLowerCase();
6933
+ if (lowerName.includes(lowerQuery)) {
6934
+ addMatch(icon.name, 1);
6935
+ continue;
6936
+ }
6937
+ if (icon.keywords.some((keyword) => keyword.includes(lowerQuery))) {
6938
+ addMatch(icon.name, 2);
6939
+ continue;
6940
+ }
6941
+ if (icon.keywords.some((keyword) => fuzzyMatch(lowerQuery, keyword))) {
6942
+ addMatch(icon.name, 3);
6943
+ continue;
6944
+ }
6945
+ const nameParts = icon.name.replace(/([A-Z])/g, " $1").toLowerCase().trim().split(/\s+/);
6946
+ if (nameParts.some((part) => fuzzyMatch(lowerQuery, part))) {
6947
+ addMatch(icon.name, 4);
6948
+ }
6949
+ }
6950
+ const sortedNames = [...matches.entries()].sort((a, b) => a[1] - b[1]).map(([name]) => name);
6951
+ return sortedNames.map((name) => ICON_METADATA.find((icon) => icon.name === name)).filter((icon) => icon !== void 0);
6952
+ }
6953
+ function getIconMeta(name) {
6954
+ return ICON_METADATA.find((icon) => icon.name === name);
6955
+ }
6956
+ function getIconLabel(name) {
6957
+ let label = name.replace(/^Icon/, "");
6958
+ label = label.replace(/^Brand/, "");
6959
+ label = label.replace(/([A-Z])/g, " $1").trim();
6960
+ return label;
6961
+ }
6962
+
6963
+ // src/components/icon-picker.css
6964
+ styleInject('.ya-icon-picker {\n min-width: 320px;\n max-width: 360px;\n background: #1a1a1a;\n border-radius: 12px;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-icon-picker-search {\n padding: 12px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-icon-picker-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-icon-picker-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-icon-picker-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-icon-picker-categories {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n padding: 8px 12px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-icon-category-btn {\n padding: 5px 10px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 6px;\n color: rgba(255, 255, 255, 0.7);\n font-size: 11px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n.ya-icon-category-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: #ffffff;\n}\n.ya-icon-category-btn.is-active {\n background: var(--color-primary, #D4A574);\n color: #1a1a1a;\n border-color: var(--color-primary, #D4A574);\n}\n.ya-icon-picker-grid-container {\n position: relative;\n height: 264px;\n overflow: hidden;\n}\n.ya-icon-picker-grid {\n display: grid;\n grid-template-columns: repeat(6, 1fr);\n gap: 4px;\n padding: 12px;\n height: 100%;\n overflow-y: auto;\n align-content: start;\n}\n.ya-icon-picker-grid::-webkit-scrollbar {\n width: 6px;\n}\n.ya-icon-picker-grid::-webkit-scrollbar-track {\n background: transparent;\n}\n.ya-icon-picker-grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2);\n border-radius: 3px;\n}\n.ya-icon-picker-grid::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.3);\n}\n.ya-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: rgba(255, 255, 255, 0.8);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-icon-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n color: #ffffff;\n}\n.ya-icon-btn.is-selected {\n background: var(--color-primary, #D4A574);\n color: #1a1a1a;\n border-color: var(--color-primary, #D4A574);\n}\n.ya-icon-btn.is-focused {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: -2px;\n}\n.ya-icon-btn-none {\n position: relative;\n}\n.ya-icon-btn-none-x {\n font-size: 20px;\n line-height: 1;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-icon-btn-none:hover .ya-icon-btn-none-x {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-icon-btn-none.is-selected .ya-icon-btn-none-x {\n color: #1a1a1a;\n}\n.ya-icon-picker-empty {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: rgba(255, 255, 255, 0.5);\n font-size: 13px;\n pointer-events: none;\n}\n.ya-icon-picker-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n background: rgba(255, 255, 255, 0.02);\n}\n.ya-icon-picker-selected-name {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.7);\n}\n.ya-edit-icon-btn {\n display: flex;\n align-items: center;\n gap: 6px;\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-edit-icon-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-edit-icon-preview {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n}\n.ya-edit-icon-label {\n flex: 1;\n}\n');
6965
+
6966
+ // src/components/IconPicker.tsx
6967
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
6968
+ function getIconPickerLabel(value) {
6969
+ if (!value) return "Icon";
6970
+ return getIconLabel(value);
6971
+ }
6972
+ function IconPicker({ value, onChange, onClose }) {
6973
+ const [searchQuery, setSearchQuery] = useState18("");
6974
+ const [activeCategory, setActiveCategory] = useState18("all");
6975
+ const [focusedIndex, setFocusedIndex] = useState18(-1);
6976
+ const searchInputRef = useRef18(null);
6977
+ const gridRef = useRef18(null);
6978
+ useEffect18(() => {
6979
+ searchInputRef.current?.focus();
6980
+ }, []);
6981
+ const filteredIcons = useMemo7(() => {
6982
+ if (searchQuery.trim()) {
6983
+ return searchIcons(searchQuery);
6984
+ }
6985
+ if (activeCategory === "all") {
6986
+ return ICON_METADATA;
6987
+ }
6988
+ return getIconsByCategory(activeCategory);
6989
+ }, [searchQuery, activeCategory]);
6990
+ const handleSearchChange = useCallback19((e) => {
6991
+ setSearchQuery(e.target.value);
6992
+ setFocusedIndex(-1);
6993
+ if (e.target.value.trim()) {
6994
+ setActiveCategory("all");
6995
+ }
6996
+ }, []);
6997
+ const handleIconSelect = useCallback19((iconName) => {
6998
+ onChange(iconName);
6999
+ onClose();
7000
+ }, [onChange, onClose]);
7001
+ const handleKeyDown = useCallback19((e) => {
7002
+ const iconsPerRow = 6;
7003
+ const totalIcons = filteredIcons.length + 1;
7004
+ switch (e.key) {
7005
+ case "ArrowDown":
7006
+ e.preventDefault();
7007
+ setFocusedIndex((prev) => {
7008
+ const next = prev + iconsPerRow;
7009
+ return next < totalIcons ? next : prev;
7010
+ });
7011
+ break;
7012
+ case "ArrowUp":
7013
+ e.preventDefault();
7014
+ setFocusedIndex((prev) => {
7015
+ const next = prev - iconsPerRow;
7016
+ return next >= 0 ? next : prev;
7017
+ });
7018
+ break;
7019
+ case "ArrowRight":
7020
+ e.preventDefault();
7021
+ setFocusedIndex((prev) => {
7022
+ const next = prev + 1;
7023
+ return next < totalIcons ? next : prev;
7024
+ });
7025
+ break;
7026
+ case "ArrowLeft":
7027
+ e.preventDefault();
7028
+ setFocusedIndex((prev) => {
7029
+ const next = prev - 1;
7030
+ return next >= 0 ? next : prev;
7031
+ });
7032
+ break;
7033
+ case "Enter":
7034
+ e.preventDefault();
7035
+ if (focusedIndex === 0) {
7036
+ handleIconSelect(null);
7037
+ } else if (focusedIndex > 0 && focusedIndex <= filteredIcons.length) {
7038
+ handleIconSelect(filteredIcons[focusedIndex - 1].name);
7039
+ }
7040
+ break;
7041
+ case "Escape":
7042
+ e.preventDefault();
7043
+ onClose();
7044
+ break;
7045
+ }
7046
+ }, [filteredIcons, focusedIndex, handleIconSelect, onClose]);
7047
+ useEffect18(() => {
7048
+ if (focusedIndex >= 0 && gridRef.current) {
7049
+ const focusedButton = gridRef.current.children[focusedIndex];
7050
+ focusedButton?.scrollIntoView({ block: "nearest", behavior: "smooth" });
7051
+ }
7052
+ }, [focusedIndex]);
7053
+ const handleMouseDown = useCallback19((e) => {
7054
+ e.preventDefault();
7055
+ e.stopPropagation();
7056
+ }, []);
7057
+ return /* @__PURE__ */ jsxs10("div", { className: "ya-icon-picker", onKeyDown: handleKeyDown, children: [
7058
+ /* @__PURE__ */ jsx18("div", { className: "ya-icon-picker-search", children: /* @__PURE__ */ jsx18(
7059
+ "input",
7060
+ {
7061
+ ref: searchInputRef,
7062
+ type: "text",
7063
+ value: searchQuery,
7064
+ onChange: handleSearchChange,
7065
+ onClick: (e) => e.stopPropagation(),
7066
+ onMouseDown: (e) => e.stopPropagation(),
7067
+ className: "ya-icon-picker-input",
7068
+ placeholder: "Search icons...",
7069
+ autoComplete: "off",
7070
+ spellCheck: false
7071
+ }
7072
+ ) }),
7073
+ /* @__PURE__ */ jsxs10("div", { className: "ya-icon-picker-grid-container", children: [
7074
+ /* @__PURE__ */ jsxs10("div", { className: "ya-icon-picker-grid", ref: gridRef, children: [
7075
+ /* @__PURE__ */ jsx18(
7076
+ "button",
7077
+ {
7078
+ type: "button",
7079
+ className: `ya-icon-btn ya-icon-btn-none ${!value ? "is-selected" : ""} ${focusedIndex === 0 ? "is-focused" : ""}`,
7080
+ onClick: () => handleIconSelect(null),
7081
+ onMouseDown: handleMouseDown,
7082
+ title: "No icon",
7083
+ children: /* @__PURE__ */ jsx18("span", { className: "ya-icon-btn-none-x", children: "\xD7" })
7084
+ }
7085
+ ),
7086
+ filteredIcons.map((icon, index) => /* @__PURE__ */ jsx18(
7087
+ "button",
7088
+ {
7089
+ type: "button",
7090
+ className: `ya-icon-btn ${value === icon.name ? "is-selected" : ""} ${focusedIndex === index + 1 ? "is-focused" : ""}`,
7091
+ onClick: () => handleIconSelect(icon.name),
7092
+ onMouseDown: handleMouseDown,
7093
+ title: getIconLabel(icon.name),
7094
+ children: /* @__PURE__ */ jsx18(DynamicIcon, { name: icon.name, size: 20 })
7095
+ },
7096
+ icon.name
7097
+ ))
7098
+ ] }),
7099
+ filteredIcons.length === 0 && /* @__PURE__ */ jsxs10("div", { className: "ya-icon-picker-empty", children: [
7100
+ 'No icons found for "',
7101
+ searchQuery,
7102
+ '"'
7103
+ ] })
7104
+ ] }),
7105
+ value && /* @__PURE__ */ jsxs10("div", { className: "ya-icon-picker-footer", children: [
7106
+ /* @__PURE__ */ jsx18(DynamicIcon, { name: value, size: 16 }),
7107
+ /* @__PURE__ */ jsx18("span", { className: "ya-icon-picker-selected-name", children: getIconLabel(value) })
7108
+ ] })
7109
+ ] });
7110
+ }
7111
+
7112
+ // src/components/ya-link.css
7113
+ 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-editable:has(.ya-text-editing),\n.ya-link-editable:has(.ya-text-editing):hover {\n outline: none !important;\n cursor: text;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-editing .ProseMirror {\n color: #1a1a1a !important;\n caret-color: #1a1a1a;\n}\n.ya-link-editing .ProseMirror p::selection,\n.ya-link-editing .ProseMirror::selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ya-link-editing .ProseMirror p::-moz-selection,\n.ya-link-editing .ProseMirror::-moz-selection {\n background-color: rgba(212, 165, 116, 0.4);\n color: inherit;\n}\n.ProseMirror-gapcursor {\n display: none !important;\n}\n.ProseMirror .ProseMirror-dropcursor {\n display: none !important;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::selection {\n color: inherit;\n}\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing)::-moz-selection,\nbody.builder-selector-active .ya-link-editable:not(.ya-link-editing) *::-moz-selection {\n color: inherit;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n z-index: 9999;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: fixed;\n z-index: 10000;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover--above {\n animation: ya-href-popover-fade-in-above 0.15s ease;\n}\n@keyframes ya-href-popover-fade-in-above {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-href-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n.ya-link-edit-popover {\n position: fixed;\n z-index: 10000;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transition: opacity 100ms ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n@keyframes ya-link-success {\n 0% {\n outline-color: var(--color-primary, #D4A574);\n }\n 30% {\n outline-color: rgba(134, 239, 172, 0.6);\n outline-width: 2px;\n }\n 100% {\n outline-color: transparent;\n outline-width: 2px;\n }\n}\n.ya-link-success {\n outline: 2px solid transparent;\n outline-offset: 4px;\n border-radius: 4px;\n animation: ya-link-success 0.5s ease;\n}\n');
7114
+
7115
+ // src/components/YaLink.tsx
7116
+ import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
7117
+ function isInternalPath(path) {
7118
+ if (!path) return false;
5838
7119
  if (path.startsWith("#")) return false;
5839
7120
  if (path.startsWith("//")) return false;
5840
7121
  if (path.includes("://")) return false;
@@ -5929,41 +7210,49 @@ function discoverSectionsFromDOM() {
5929
7210
  });
5930
7211
  return sections;
5931
7212
  }
5932
- function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName, style, as: Component = "a", children, availablePages, onClick, target, rel }) {
7213
+ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName, style, as: Component = "a", children, availablePages, onClick, target, rel, title, iconPosition, iconSize }) {
7214
+ const effectiveIconSize = iconSize ?? (iconPosition === "only" ? 24 : 20);
5933
7215
  const textFieldId = `${fieldId}.text`;
5934
7216
  const hrefFieldId = `${fieldId}.href`;
7217
+ const iconFieldId = `${fieldId}.icon`;
5935
7218
  const textContent = useContent(textFieldId);
5936
7219
  const hrefContent = useContent(hrefFieldId);
7220
+ const iconContent = useContent(iconFieldId);
5937
7221
  const { mode } = textContent;
5938
7222
  const { getPages } = useContentStore();
5939
7223
  const [, navigate] = useLocation();
5940
7224
  const pages = availablePages ?? getPages();
5941
- const [sections, setSections] = useState16([]);
5942
- const [sectionsExpanded, setSectionsExpanded] = useState16(false);
7225
+ const [sections, setSections] = useState19([]);
7226
+ const [sectionsExpanded, setSectionsExpanded] = useState19(false);
5943
7227
  const storeText = textContent.get();
5944
7228
  const storeHref = hrefContent.get();
7229
+ const storeIcon = iconContent.get();
5945
7230
  const isIconMode = children != null && typeof children !== "string";
5946
7231
  const text2 = storeText || (typeof children === "string" ? children : "");
5947
7232
  const href = storeHref || defaultHref;
7233
+ const currentIcon = storeIcon || null;
5948
7234
  const isExternal = isExternalHref(href);
5949
7235
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
5950
7236
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
5951
- const [editingMode, setEditingMode] = useState16(null);
5952
- const [originalText, setOriginalText] = useState16(text2);
5953
- const [originalHref, setOriginalHref] = useState16(href);
5954
- const [currentHref, setCurrentHref] = useState16(href);
5955
- const [isExternalUrl, setIsExternalUrl] = useState16(false);
5956
- const [externalUrl, setExternalUrl] = useState16("");
5957
- const containerRef = useRef17(null);
5958
- const hrefPopoverRef = useRef17(null);
5959
- const [actionButtonsPos, setActionButtonsPos] = useState16(null);
5960
- const [editPopoverPos, setEditPopoverPos] = useState16(null);
5961
- const [editPopoverVisible, setEditPopoverVisible] = useState16(false);
5962
- const [editPopoverMounted, setEditPopoverMounted] = useState16(false);
5963
- const [hrefPopoverPos, setHrefPopoverPos] = useState16(null);
5964
- const handleSaveTextRef = useRef17(() => {
7237
+ const [editingMode, setEditingMode] = useState19(null);
7238
+ const [showSuccess, setShowSuccess] = useState19(false);
7239
+ const [originalText, setOriginalText] = useState19(text2);
7240
+ const [originalHref, setOriginalHref] = useState19(href);
7241
+ const [currentHref, setCurrentHref] = useState19(href);
7242
+ const [isExternalUrl, setIsExternalUrl] = useState19(false);
7243
+ const [externalUrl, setExternalUrl] = useState19("");
7244
+ const containerRef = useRef19(null);
7245
+ const hrefPopoverRef = useRef19(null);
7246
+ const [actionButtonsPos, setActionButtonsPos] = useState19(null);
7247
+ const [editPopoverPos, setEditPopoverPos] = useState19(null);
7248
+ const [editPopoverVisible, setEditPopoverVisible] = useState19(false);
7249
+ const [editPopoverMounted, setEditPopoverMounted] = useState19(false);
7250
+ const [hrefPopoverPos, setHrefPopoverPos] = useState19(null);
7251
+ const [iconPopoverPos, setIconPopoverPos] = useState19(null);
7252
+ const iconPopoverRef = useRef19(null);
7253
+ const handleSaveTextRef = useRef19(() => {
5965
7254
  });
5966
- const handleCancelTextRef = useRef17(() => {
7255
+ const handleCancelTextRef = useRef19(() => {
5967
7256
  });
5968
7257
  const {
5969
7258
  popoverRef: editPopoverRef,
@@ -5977,12 +7266,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
5977
7266
  });
5978
7267
  const triggerRef = containerRef;
5979
7268
  const instanceId = useId();
5980
- useEffect16(() => {
7269
+ useEffect19(() => {
5981
7270
  if (showEditPopover && mode === "inline-edit" && !editingMode) {
5982
7271
  window.dispatchEvent(new CustomEvent("yalink:popover-open", { detail: { id: instanceId } }));
5983
7272
  }
5984
7273
  }, [showEditPopover, mode, editingMode, instanceId]);
5985
- useEffect16(() => {
7274
+ useEffect19(() => {
5986
7275
  const handleOtherPopoverOpen = (event) => {
5987
7276
  const customEvent = event;
5988
7277
  if (customEvent.detail.id !== instanceId && showEditPopover) {
@@ -6036,19 +7325,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6036
7325
  }
6037
7326
  }
6038
7327
  });
6039
- useEffect16(() => {
7328
+ useEffect19(() => {
6040
7329
  if (editor && editingMode !== "text") {
6041
7330
  if (editor.getHTML() !== text2) {
6042
7331
  editor.commands.setContent(text2);
6043
7332
  }
6044
7333
  }
6045
7334
  }, [text2, editor, editingMode]);
6046
- useEffect16(() => {
7335
+ useEffect19(() => {
6047
7336
  if (editingMode !== "link") {
6048
7337
  setCurrentHref(href);
6049
7338
  }
6050
7339
  }, [href, editingMode]);
6051
- useEffect16(() => {
7340
+ useEffect19(() => {
6052
7341
  if (editingMode !== "text" || !containerRef.current) {
6053
7342
  setActionButtonsPos(null);
6054
7343
  return;
@@ -6069,7 +7358,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6069
7358
  window.removeEventListener("resize", updatePosition);
6070
7359
  };
6071
7360
  }, [editingMode]);
6072
- useEffect16(() => {
7361
+ useEffect19(() => {
6073
7362
  const shouldShow = showEditPopover && !editingMode && mode === "inline-edit";
6074
7363
  if (shouldShow) {
6075
7364
  setEditPopoverMounted(true);
@@ -6131,7 +7420,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6131
7420
  window.removeEventListener("resize", updatePosition);
6132
7421
  };
6133
7422
  }, [editingMode]);
6134
- useEffect16(() => {
7423
+ useEffect19(() => {
6135
7424
  if (editingMode !== "link") return;
6136
7425
  const handleClickOutside = (event) => {
6137
7426
  const target2 = event.target;
@@ -6145,7 +7434,44 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6145
7434
  document.addEventListener("mousedown", handleClickOutside);
6146
7435
  return () => document.removeEventListener("mousedown", handleClickOutside);
6147
7436
  }, [editingMode, originalHref]);
6148
- const handleSaveText = useCallback18(() => {
7437
+ useLayoutEffect3(() => {
7438
+ if (editingMode !== "icon" || !containerRef.current) {
7439
+ setIconPopoverPos(null);
7440
+ return;
7441
+ }
7442
+ const updatePosition = () => {
7443
+ if (!containerRef.current) return;
7444
+ const rect = containerRef.current.getBoundingClientRect();
7445
+ const popoverHeight = 400;
7446
+ const spaceBelow = window.innerHeight - rect.bottom;
7447
+ const spaceAbove = rect.top;
7448
+ const isAbove = spaceBelow < popoverHeight && spaceAbove > spaceBelow;
7449
+ setIconPopoverPos({
7450
+ top: isAbove ? rect.top - 8 : rect.bottom + 8,
7451
+ left: rect.left + rect.width / 2,
7452
+ isAbove
7453
+ });
7454
+ };
7455
+ updatePosition();
7456
+ window.addEventListener("scroll", updatePosition, true);
7457
+ window.addEventListener("resize", updatePosition);
7458
+ return () => {
7459
+ window.removeEventListener("scroll", updatePosition, true);
7460
+ window.removeEventListener("resize", updatePosition);
7461
+ };
7462
+ }, [editingMode]);
7463
+ useEffect19(() => {
7464
+ if (editingMode !== "icon") return;
7465
+ const handleClickOutside = (event) => {
7466
+ const target2 = event.target;
7467
+ if (iconPopoverRef.current?.contains(target2)) return;
7468
+ if (containerRef.current?.contains(target2)) return;
7469
+ setEditingMode(null);
7470
+ };
7471
+ document.addEventListener("mousedown", handleClickOutside);
7472
+ return () => document.removeEventListener("mousedown", handleClickOutside);
7473
+ }, [editingMode]);
7474
+ const handleSaveText = useCallback20(() => {
6149
7475
  if (!editor) return;
6150
7476
  let html = editor.getHTML();
6151
7477
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -6153,30 +7479,40 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6153
7479
  textContent.save();
6154
7480
  setEditingMode(null);
6155
7481
  }, [editor, textContent]);
6156
- const handleSaveLink = useCallback18(() => {
7482
+ const handleSaveLink = useCallback20(() => {
6157
7483
  hrefContent.set(currentHref, "user");
6158
7484
  hrefContent.save();
6159
7485
  setEditingMode(null);
6160
7486
  setIsExternalUrl(false);
6161
7487
  setExternalUrl("");
6162
7488
  }, [currentHref, hrefContent]);
6163
- const handleCancelText = useCallback18(() => {
7489
+ const handleCancelText = useCallback20(() => {
6164
7490
  if (editor) {
6165
7491
  editor.commands.setContent(originalText);
6166
7492
  }
6167
7493
  setEditingMode(null);
6168
7494
  }, [editor, originalText]);
6169
- const handleCancelLink = useCallback18(() => {
7495
+ const handleCancelLink = useCallback20(() => {
6170
7496
  setCurrentHref(originalHref);
6171
7497
  setEditingMode(null);
6172
7498
  setIsExternalUrl(false);
6173
7499
  setExternalUrl("");
6174
7500
  }, [originalHref]);
6175
- useEffect16(() => {
7501
+ const handleIconSelect = useCallback20((iconName) => {
7502
+ iconContent.set(iconName || "", "user");
7503
+ iconContent.save();
7504
+ setEditingMode(null);
7505
+ setShowSuccess(true);
7506
+ setTimeout(() => setShowSuccess(false), 500);
7507
+ }, [iconContent]);
7508
+ const handleCancelIcon = useCallback20(() => {
7509
+ setEditingMode(null);
7510
+ }, []);
7511
+ useEffect19(() => {
6176
7512
  handleSaveTextRef.current = handleSaveText;
6177
7513
  handleCancelTextRef.current = handleCancelText;
6178
7514
  }, [handleSaveText, handleCancelText]);
6179
- const handleClick = useCallback18(
7515
+ const handleClick = useCallback20(
6180
7516
  (e) => {
6181
7517
  const selectModeEnabled = window.__builderSelectModeEnabled;
6182
7518
  if (selectModeEnabled) {
@@ -6208,7 +7544,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6208
7544
  },
6209
7545
  [href, navigate, onClick]
6210
7546
  );
6211
- const startEditText = useCallback18(() => {
7547
+ const startEditText = useCallback20(() => {
6212
7548
  hideEditPopover();
6213
7549
  if (isIconMode) {
6214
7550
  window.dispatchEvent(new CustomEvent("yatext:edit-mode", {
@@ -6222,14 +7558,18 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6222
7558
  }, 20);
6223
7559
  }
6224
7560
  }, [text2, editor, hideEditPopover, isIconMode, fieldId]);
6225
- const startEditLink = useCallback18(() => {
7561
+ const startEditLink = useCallback20(() => {
6226
7562
  hideEditPopover();
6227
7563
  setEditingMode("link");
6228
7564
  setOriginalHref(href);
6229
7565
  setCurrentHref(href);
6230
7566
  setSections(discoverSectionsFromDOM());
6231
7567
  }, [href, hideEditPopover]);
6232
- const handleKeyDown = useCallback18(
7568
+ const startEditIcon = useCallback20(() => {
7569
+ hideEditPopover();
7570
+ setEditingMode("icon");
7571
+ }, [hideEditPopover]);
7572
+ const handleKeyDown = useCallback20(
6233
7573
  (event) => {
6234
7574
  if (editingMode !== "text") return;
6235
7575
  if (event.key === "Enter" && !event.shiftKey) {
@@ -6250,7 +7590,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6250
7590
  },
6251
7591
  [editingMode, handleSaveText, handleCancelText]
6252
7592
  );
6253
- const handleFontSizeChange = useCallback18(
7593
+ const handleFontSizeChange = useCallback20(
6254
7594
  (e) => {
6255
7595
  if (!editor) return;
6256
7596
  const size = e.target.value;
@@ -6262,7 +7602,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6262
7602
  },
6263
7603
  [editor]
6264
7604
  );
6265
- const handleFontWeightChange = useCallback18(
7605
+ const handleFontWeightChange = useCallback20(
6266
7606
  (e) => {
6267
7607
  if (!editor) return;
6268
7608
  const weight = e.target.value;
@@ -6274,11 +7614,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6274
7614
  },
6275
7615
  [editor]
6276
7616
  );
6277
- const handlePageSelect = useCallback18((path) => {
7617
+ const handlePageSelect = useCallback20((path) => {
6278
7618
  setCurrentHref(path);
6279
7619
  setIsExternalUrl(false);
6280
7620
  }, []);
6281
- const handleExternalUrlApply = useCallback18(() => {
7621
+ const handleExternalUrlApply = useCallback20(() => {
6282
7622
  if (externalUrl) {
6283
7623
  setCurrentHref(externalUrl);
6284
7624
  }
@@ -6293,28 +7633,58 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6293
7633
  const attrs = editor.getAttributes("textStyle");
6294
7634
  return attrs.fontWeight || "";
6295
7635
  };
7636
+ const renderIcon = () => currentIcon ? /* @__PURE__ */ jsx19(DynamicIcon, { name: currentIcon, size: effectiveIconSize }) : null;
7637
+ const renderLinkContent = (textContent2) => {
7638
+ if (iconPosition === "only") {
7639
+ return currentIcon ? renderIcon() : children;
7640
+ }
7641
+ if (iconPosition === "left") {
7642
+ return /* @__PURE__ */ jsxs11(Fragment5, { children: [
7643
+ renderIcon(),
7644
+ renderIcon() && /* @__PURE__ */ jsx19("span", { style: { marginLeft: "0.35em" } }),
7645
+ textContent2
7646
+ ] });
7647
+ }
7648
+ if (iconPosition === "right") {
7649
+ return /* @__PURE__ */ jsxs11(Fragment5, { children: [
7650
+ textContent2,
7651
+ renderIcon() && /* @__PURE__ */ jsx19("span", { style: { marginRight: "0.35em" } }),
7652
+ renderIcon()
7653
+ ] });
7654
+ }
7655
+ return textContent2;
7656
+ };
6296
7657
  if (mode === "read-only") {
6297
- const content = isIconMode ? children : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode });
7658
+ let content;
7659
+ if (iconPosition) {
7660
+ content = renderLinkContent(/* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode }));
7661
+ } else if (isIconMode) {
7662
+ content = children;
7663
+ } else {
7664
+ content = /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode });
7665
+ }
6298
7666
  if (isInternalPath(href)) {
6299
- return /* @__PURE__ */ jsx16(
7667
+ return /* @__PURE__ */ jsx19(
6300
7668
  WouterLink,
6301
7669
  {
6302
7670
  href,
6303
7671
  className,
6304
7672
  style,
7673
+ title,
6305
7674
  "data-ya-restricted": "true",
6306
7675
  "data-field-id": fieldId,
6307
7676
  children: content
6308
7677
  }
6309
7678
  );
6310
7679
  }
6311
- return /* @__PURE__ */ jsx16(
7680
+ return /* @__PURE__ */ jsx19(
6312
7681
  Component,
6313
7682
  {
6314
7683
  ref: containerRef,
6315
7684
  href: Component === "a" ? href : void 0,
6316
7685
  target: Component === "a" ? effectiveTarget : void 0,
6317
7686
  rel: Component === "a" ? effectiveRel : void 0,
7687
+ title,
6318
7688
  className,
6319
7689
  style,
6320
7690
  "data-ya-restricted": "true",
@@ -6323,29 +7693,48 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6323
7693
  }
6324
7694
  );
6325
7695
  }
6326
- return /* @__PURE__ */ jsxs9("span", { className: `ya-link-wrapper ${wrapperClassName || ""}`, children: [
6327
- /* @__PURE__ */ jsx16(
7696
+ return /* @__PURE__ */ jsxs11("span", { className: `ya-link-wrapper ${wrapperClassName || ""}`, children: [
7697
+ /* @__PURE__ */ jsx19(
6328
7698
  Component,
6329
7699
  {
6330
7700
  ref: containerRef,
6331
7701
  href: Component === "a" ? href : void 0,
6332
7702
  target: Component === "a" ? effectiveTarget : void 0,
6333
7703
  rel: Component === "a" ? effectiveRel : void 0,
6334
- className: `${className || ""} ${editingMode ? "ya-link-editing" : "ya-link-editable"}`,
7704
+ title,
7705
+ className: `${className || ""} ${editingMode ? "ya-link-editing" : "ya-link-editable"} ${showSuccess ? "ya-link-success" : ""}`,
6335
7706
  style,
6336
7707
  "data-ya-restricted": "true",
7708
+ "data-ya-link": "true",
6337
7709
  "data-field-id": fieldId,
6338
7710
  onClick: handleClick,
6339
7711
  onMouseEnter: safeTriangleHandlers.onMouseEnter,
6340
7712
  onMouseLeave: safeTriangleHandlers.onMouseLeave,
6341
7713
  onFocus: safeTriangleHandlers.onFocus,
6342
7714
  onKeyDown: handleKeyDown,
6343
- children: isIconMode ? (
6344
- // Icon mode: render children directly, no text editing
7715
+ children: iconPosition === "only" ? (
7716
+ // Icon-only mode: render DynamicIcon
7717
+ currentIcon ? /* @__PURE__ */ jsx19(DynamicIcon, { name: currentIcon, size: effectiveIconSize }) : children
7718
+ ) : iconPosition === "left" ? (
7719
+ // Icon before text
7720
+ /* @__PURE__ */ jsxs11(Fragment5, { children: [
7721
+ renderIcon(),
7722
+ renderIcon() && /* @__PURE__ */ jsx19("span", { style: { marginLeft: "0.35em" } }),
7723
+ isIconMode ? children : editor ? editingMode === "text" ? /* @__PURE__ */ jsx19(EditorContent2, { editor }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode })
7724
+ ] })
7725
+ ) : iconPosition === "right" ? (
7726
+ // Text before icon
7727
+ /* @__PURE__ */ jsxs11(Fragment5, { children: [
7728
+ isIconMode ? children : editor ? editingMode === "text" ? /* @__PURE__ */ jsx19(EditorContent2, { editor }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode }),
7729
+ renderIcon() && /* @__PURE__ */ jsx19("span", { style: { marginRight: "0.35em" } }),
7730
+ renderIcon()
7731
+ ] })
7732
+ ) : isIconMode ? (
7733
+ // Icon mode (children is React node): render children directly, no text editing
6345
7734
  children
6346
- ) : editor ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
7735
+ ) : editor ? /* @__PURE__ */ jsxs11(Fragment5, { children: [
6347
7736
  createPortal6(
6348
- /* @__PURE__ */ jsxs9(
7737
+ /* @__PURE__ */ jsxs11(
6349
7738
  BubbleMenu,
6350
7739
  {
6351
7740
  editor,
@@ -6353,28 +7742,28 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6353
7742
  options: { offset: 6, placement: "top" },
6354
7743
  className: "ya-bubble-menu",
6355
7744
  children: [
6356
- /* @__PURE__ */ jsx16(
7745
+ /* @__PURE__ */ jsx19(
6357
7746
  "button",
6358
7747
  {
6359
7748
  type: "button",
6360
7749
  onClick: () => editor.chain().focus().toggleBold().run(),
6361
7750
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
6362
7751
  title: "Bold",
6363
- children: /* @__PURE__ */ jsx16("strong", { children: "B" })
7752
+ children: /* @__PURE__ */ jsx19("strong", { children: "B" })
6364
7753
  }
6365
7754
  ),
6366
- /* @__PURE__ */ jsx16(
7755
+ /* @__PURE__ */ jsx19(
6367
7756
  "button",
6368
7757
  {
6369
7758
  type: "button",
6370
7759
  onClick: () => editor.chain().focus().toggleItalic().run(),
6371
7760
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
6372
7761
  title: "Italic",
6373
- children: /* @__PURE__ */ jsx16("em", { children: "I" })
7762
+ children: /* @__PURE__ */ jsx19("em", { children: "I" })
6374
7763
  }
6375
7764
  ),
6376
- /* @__PURE__ */ jsx16("span", { className: "ya-bubble-divider" }),
6377
- /* @__PURE__ */ jsxs9(
7765
+ /* @__PURE__ */ jsx19("span", { className: "ya-bubble-divider" }),
7766
+ /* @__PURE__ */ jsxs11(
6378
7767
  "select",
6379
7768
  {
6380
7769
  value: getCurrentFontSize(),
@@ -6382,12 +7771,12 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6382
7771
  className: "ya-bubble-select",
6383
7772
  title: "Font Size",
6384
7773
  children: [
6385
- /* @__PURE__ */ jsx16("option", { value: "", children: "Size" }),
6386
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx16("option", { value: size, children: name }, name))
7774
+ /* @__PURE__ */ jsx19("option", { value: "", children: "Size" }),
7775
+ Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx19("option", { value: size, children: name }, name))
6387
7776
  ]
6388
7777
  }
6389
7778
  ),
6390
- /* @__PURE__ */ jsxs9(
7779
+ /* @__PURE__ */ jsxs11(
6391
7780
  "select",
6392
7781
  {
6393
7782
  value: getCurrentFontWeight(),
@@ -6395,8 +7784,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6395
7784
  className: "ya-bubble-select",
6396
7785
  title: "Font Weight",
6397
7786
  children: [
6398
- /* @__PURE__ */ jsx16("option", { value: "", children: "Weight" }),
6399
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx16("option", { value: weight, children: name }, name))
7787
+ /* @__PURE__ */ jsx19("option", { value: "", children: "Weight" }),
7788
+ Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx19("option", { value: weight, children: name }, name))
6400
7789
  ]
6401
7790
  }
6402
7791
  )
@@ -6405,10 +7794,10 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6405
7794
  ),
6406
7795
  document.body
6407
7796
  ),
6408
- editingMode === "text" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
6409
- /* @__PURE__ */ jsx16(EditorContent2, { editor }),
7797
+ editingMode === "text" ? /* @__PURE__ */ jsxs11(Fragment5, { children: [
7798
+ /* @__PURE__ */ jsx19(EditorContent2, { editor }),
6410
7799
  actionButtonsPos && createPortal6(
6411
- /* @__PURE__ */ jsxs9(
7800
+ /* @__PURE__ */ jsxs11(
6412
7801
  "div",
6413
7802
  {
6414
7803
  className: "ya-link-actions",
@@ -6418,19 +7807,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6418
7807
  right: actionButtonsPos.right
6419
7808
  },
6420
7809
  children: [
6421
- /* @__PURE__ */ jsx16("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
6422
- /* @__PURE__ */ jsx16("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
7810
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
7811
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
6423
7812
  ]
6424
7813
  }
6425
7814
  ),
6426
7815
  document.body
6427
7816
  )
6428
- ] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
6429
- ] }) : /* @__PURE__ */ jsx16(SafeHtml, { content: text2, mode })
7817
+ ] }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode })
7818
+ ] }) : /* @__PURE__ */ jsx19(SafeHtml, { content: text2, mode })
6430
7819
  }
6431
7820
  ),
6432
7821
  editPopoverMounted && editPopoverPos && createPortal6(
6433
- /* @__PURE__ */ jsxs9(
7822
+ /* @__PURE__ */ jsx19(
6434
7823
  "div",
6435
7824
  {
6436
7825
  ref: editPopoverRef,
@@ -6443,15 +7832,31 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6443
7832
  },
6444
7833
  onMouseEnter: safeTriangleHandlers.onMouseEnter,
6445
7834
  onMouseLeave: safeTriangleHandlers.onMouseLeave,
6446
- children: [
6447
- /* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditText, children: "Edit text" }),
6448
- /* @__PURE__ */ jsx16("button", { type: "button", onClick: startEditLink, children: "Edit link" })
6449
- ]
7835
+ children: iconPosition === "only" ? (
7836
+ // Icon-only mode: show "Edit icon" + "Edit link"
7837
+ /* @__PURE__ */ jsxs11(Fragment5, { children: [
7838
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditIcon, children: "Edit icon" }),
7839
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditLink, children: "Edit link" })
7840
+ ] })
7841
+ ) : iconPosition ? (
7842
+ // Icon + text mode: show all three options
7843
+ /* @__PURE__ */ jsxs11(Fragment5, { children: [
7844
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditIcon, children: "Edit icon" }),
7845
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditText, children: "Edit text" }),
7846
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditLink, children: "Edit link" })
7847
+ ] })
7848
+ ) : (
7849
+ // Text-only mode: show "Edit text" + "Edit link"
7850
+ /* @__PURE__ */ jsxs11(Fragment5, { children: [
7851
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditText, children: "Edit text" }),
7852
+ /* @__PURE__ */ jsx19("button", { type: "button", onClick: startEditLink, children: "Edit link" })
7853
+ ] })
7854
+ )
6450
7855
  }
6451
7856
  ),
6452
7857
  document.body
6453
7858
  ),
6454
- /* @__PURE__ */ jsx16(
7859
+ /* @__PURE__ */ jsx19(
6455
7860
  SafeTriangleBelow,
6456
7861
  {
6457
7862
  triggerRef,
@@ -6462,7 +7867,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6462
7867
  }
6463
7868
  ),
6464
7869
  editingMode === "link" && hrefPopoverPos && createPortal6(
6465
- /* @__PURE__ */ jsxs9(
7870
+ /* @__PURE__ */ jsxs11(
6466
7871
  "div",
6467
7872
  {
6468
7873
  ref: hrefPopoverRef,
@@ -6474,24 +7879,24 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6474
7879
  transform: "translateX(-50%)"
6475
7880
  },
6476
7881
  children: [
6477
- /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-header", children: "Link destination" }),
6478
- !isExternalUrl ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
6479
- sections.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6480
- /* @__PURE__ */ jsxs9(
7882
+ /* @__PURE__ */ jsx19("div", { className: "ya-href-popover-header", children: "Link destination" }),
7883
+ !isExternalUrl ? /* @__PURE__ */ jsxs11(Fragment5, { children: [
7884
+ sections.length > 0 && /* @__PURE__ */ jsxs11("div", { className: "ya-href-popover-section", children: [
7885
+ /* @__PURE__ */ jsxs11(
6481
7886
  "button",
6482
7887
  {
6483
7888
  type: "button",
6484
7889
  className: "ya-href-popover-label ya-href-collapsible-header",
6485
7890
  onClick: () => setSectionsExpanded(!sectionsExpanded),
6486
7891
  children: [
6487
- /* @__PURE__ */ jsx16("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
7892
+ /* @__PURE__ */ jsx19("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
6488
7893
  "Scroll to section (",
6489
7894
  sections.length,
6490
7895
  ")"
6491
7896
  ]
6492
7897
  }
6493
7898
  ),
6494
- sectionsExpanded && /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs9(
7899
+ sectionsExpanded && /* @__PURE__ */ jsx19("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs11(
6495
7900
  "button",
6496
7901
  {
6497
7902
  type: "button",
@@ -6499,15 +7904,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6499
7904
  onClick: () => handlePageSelect(section.path),
6500
7905
  children: [
6501
7906
  section.label,
6502
- /* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: section.path })
7907
+ /* @__PURE__ */ jsx19("span", { className: "ya-href-page-path", children: section.path })
6503
7908
  ]
6504
7909
  },
6505
7910
  section.path
6506
7911
  )) })
6507
7912
  ] }),
6508
- pages.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6509
- /* @__PURE__ */ jsx16("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
6510
- /* @__PURE__ */ jsx16("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs9(
7913
+ pages.length > 0 && /* @__PURE__ */ jsxs11("div", { className: "ya-href-popover-section", children: [
7914
+ /* @__PURE__ */ jsx19("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
7915
+ /* @__PURE__ */ jsx19("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs11(
6511
7916
  "button",
6512
7917
  {
6513
7918
  type: "button",
@@ -6515,13 +7920,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6515
7920
  onClick: () => handlePageSelect(page.path),
6516
7921
  children: [
6517
7922
  page.label,
6518
- /* @__PURE__ */ jsx16("span", { className: "ya-href-page-path", children: page.path })
7923
+ /* @__PURE__ */ jsx19("span", { className: "ya-href-page-path", children: page.path })
6519
7924
  ]
6520
7925
  },
6521
7926
  page.path
6522
7927
  )) })
6523
7928
  ] }),
6524
- /* @__PURE__ */ jsx16(
7929
+ /* @__PURE__ */ jsx19(
6525
7930
  "button",
6526
7931
  {
6527
7932
  type: "button",
@@ -6533,10 +7938,10 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6533
7938
  children: "Use external URL instead"
6534
7939
  }
6535
7940
  )
6536
- ] }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
6537
- /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-section", children: [
6538
- /* @__PURE__ */ jsx16("label", { className: "ya-href-popover-label", children: "External URL" }),
6539
- /* @__PURE__ */ jsx16(
7941
+ ] }) : /* @__PURE__ */ jsxs11(Fragment5, { children: [
7942
+ /* @__PURE__ */ jsxs11("div", { className: "ya-href-popover-section", children: [
7943
+ /* @__PURE__ */ jsx19("label", { className: "ya-href-popover-label", children: "External URL" }),
7944
+ /* @__PURE__ */ jsx19(
6540
7945
  "input",
6541
7946
  {
6542
7947
  type: "url",
@@ -6548,49 +7953,313 @@ function YaLink({ fieldId, href: defaultHref = "#", className, wrapperClassName,
6548
7953
  }
6549
7954
  )
6550
7955
  ] }),
6551
- /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
7956
+ /* @__PURE__ */ jsx19("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
6552
7957
  ] }),
6553
- /* @__PURE__ */ jsxs9("div", { className: "ya-href-popover-actions", children: [
6554
- /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
6555
- isExternalUrl ? /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx16("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
7958
+ /* @__PURE__ */ jsxs11("div", { className: "ya-href-popover-actions", children: [
7959
+ /* @__PURE__ */ jsx19("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
7960
+ isExternalUrl ? /* @__PURE__ */ jsx19("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx19("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
6556
7961
  ] })
6557
7962
  ]
6558
7963
  }
6559
7964
  ),
6560
7965
  document.body
7966
+ ),
7967
+ editingMode === "icon" && iconPopoverPos && createPortal6(
7968
+ /* @__PURE__ */ jsx19(
7969
+ "div",
7970
+ {
7971
+ ref: iconPopoverRef,
7972
+ className: `ya-href-popover ${iconPopoverPos.isAbove ? "ya-href-popover--above" : ""}`,
7973
+ style: {
7974
+ top: iconPopoverPos.isAbove ? "auto" : iconPopoverPos.top,
7975
+ bottom: iconPopoverPos.isAbove ? window.innerHeight - iconPopoverPos.top : "auto",
7976
+ left: iconPopoverPos.left,
7977
+ transform: "translateX(-50%)"
7978
+ },
7979
+ children: /* @__PURE__ */ jsx19(
7980
+ IconPicker,
7981
+ {
7982
+ value: currentIcon,
7983
+ onChange: handleIconSelect,
7984
+ onClose: handleCancelIcon
7985
+ }
7986
+ )
7987
+ }
7988
+ ),
7989
+ document.body
7990
+ )
7991
+ ] });
7992
+ }
7993
+
7994
+ // src/components/YaIcon.tsx
7995
+ import React9, { useLayoutEffect as useLayoutEffect4, useRef as useRef20, useState as useState20, useCallback as useCallback21, useId as useId2, useEffect as useEffect20 } from "react";
7996
+ import { createPortal as createPortal7 } from "react-dom";
7997
+
7998
+ // src/components/ya-icon.css
7999
+ styleInject('.ya-icon-wrapper {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n.ya-icon-editable {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 4px;\n}\n.ya-icon-editable::after {\n content: "";\n position: absolute;\n inset: -4px;\n border: 1.5px dotted var(--ya-contrast-color, white);\n border-radius: 4px;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s ease;\n}\n.ya-icon-editable:hover::after {\n opacity: 1;\n}\nbody.builder-selector-active .ya-icon-editable:hover::after {\n opacity: 0;\n}\nbody.builder-selector-active .ya-icon-editable {\n cursor: inherit;\n}\n.ya-icon-editing::after {\n opacity: 1;\n border-style: solid;\n}\n.ya-icon-placeholder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: rgba(212, 165, 116, 0.15);\n border: 1px dashed rgba(212, 165, 116, 0.5);\n border-radius: 4px;\n color: var(--color-primary, #D4A574);\n}\n@keyframes ya-icon-success {\n 0% {\n opacity: 1;\n border-color: white;\n }\n 30% {\n opacity: 1;\n border-color: rgba(134, 239, 172, 0.8);\n }\n 100% {\n opacity: 0;\n border-color: rgba(134, 239, 172, 0.8);\n }\n}\n.ya-icon-success::after {\n border-style: solid;\n animation: ya-icon-success 0.5s ease forwards;\n}\n.ya-icon-edit-popover {\n position: fixed;\n z-index: 10000;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transition: opacity 100ms ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n.ya-icon-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-icon-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-icon-edit-popover button:hover {\n background: #4a4a4a;\n}\n.ya-icon-picker-popover {\n position: fixed;\n z-index: 10000;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n animation: ya-icon-picker-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-icon-picker-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-icon-picker-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-icon-picker-popover--above {\n animation: ya-icon-picker-fade-in-above 0.15s ease;\n}\n@keyframes ya-icon-picker-fade-in-above {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-icon-picker-popover--above::before {\n top: auto;\n bottom: -6px;\n border-bottom: none;\n border-top: 8px solid #1a1a1a;\n}\n');
8000
+
8001
+ // src/components/YaIcon.tsx
8002
+ import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
8003
+ function YaIcon({
8004
+ fieldId,
8005
+ fallback,
8006
+ size = 24,
8007
+ stroke = 2,
8008
+ className,
8009
+ wrapperClassName
8010
+ }) {
8011
+ const iconFieldId = `${fieldId}.icon`;
8012
+ const iconContent = useContent(iconFieldId);
8013
+ const { mode } = iconContent;
8014
+ const storeIcon = iconContent.get();
8015
+ const currentIcon = storeIcon || fallback || null;
8016
+ const [isEditing, setIsEditing] = useState20(false);
8017
+ const [showSuccess, setShowSuccess] = useState20(false);
8018
+ const containerRef = useRef20(null);
8019
+ const iconPopoverRef = useRef20(null);
8020
+ const [editPopoverPos, setEditPopoverPos] = useState20(null);
8021
+ const [editPopoverVisible, setEditPopoverVisible] = useState20(false);
8022
+ const [editPopoverMounted, setEditPopoverMounted] = useState20(false);
8023
+ const [iconPickerPos, setIconPickerPos] = useState20(null);
8024
+ const instanceId = useId2();
8025
+ const {
8026
+ popoverRef: editPopoverRef,
8027
+ isVisible: showEditPopover,
8028
+ handlers: safeTriangleHandlers,
8029
+ triangleProps,
8030
+ hide: hideEditPopover
8031
+ } = useSafeTriangle({
8032
+ enabled: mode === "inline-edit" && !isEditing,
8033
+ hideDelay: 150
8034
+ });
8035
+ const triggerRef = containerRef;
8036
+ useEffect20(() => {
8037
+ if (mode !== "inline-edit" || !containerRef.current) return;
8038
+ return setupContrastDetection(containerRef.current);
8039
+ }, [mode]);
8040
+ React9.useEffect(() => {
8041
+ if (showEditPopover && mode === "inline-edit" && !isEditing) {
8042
+ window.dispatchEvent(new CustomEvent("yaicon:popover-open", { detail: { id: instanceId } }));
8043
+ }
8044
+ }, [showEditPopover, mode, isEditing, instanceId]);
8045
+ React9.useEffect(() => {
8046
+ const handleOtherPopoverOpen = (event) => {
8047
+ const customEvent = event;
8048
+ if (customEvent.detail.id !== instanceId && showEditPopover) {
8049
+ hideEditPopover();
8050
+ }
8051
+ };
8052
+ window.addEventListener("yaicon:popover-open", handleOtherPopoverOpen);
8053
+ window.addEventListener("yalink:popover-open", handleOtherPopoverOpen);
8054
+ return () => {
8055
+ window.removeEventListener("yaicon:popover-open", handleOtherPopoverOpen);
8056
+ window.removeEventListener("yalink:popover-open", handleOtherPopoverOpen);
8057
+ };
8058
+ }, [instanceId, showEditPopover, hideEditPopover]);
8059
+ React9.useEffect(() => {
8060
+ const shouldShow = showEditPopover && !isEditing && mode === "inline-edit";
8061
+ if (shouldShow) {
8062
+ setEditPopoverMounted(true);
8063
+ requestAnimationFrame(() => {
8064
+ setEditPopoverVisible(true);
8065
+ });
8066
+ } else {
8067
+ setEditPopoverVisible(false);
8068
+ const timer = setTimeout(() => {
8069
+ setEditPopoverMounted(false);
8070
+ }, 100);
8071
+ return () => clearTimeout(timer);
8072
+ }
8073
+ }, [showEditPopover, isEditing, mode]);
8074
+ useLayoutEffect4(() => {
8075
+ if (!editPopoverMounted || !containerRef.current) {
8076
+ setEditPopoverPos(null);
8077
+ return;
8078
+ }
8079
+ const updatePosition = () => {
8080
+ if (!containerRef.current) return;
8081
+ const rect = containerRef.current.getBoundingClientRect();
8082
+ setEditPopoverPos({
8083
+ top: rect.bottom + 8,
8084
+ left: rect.left + rect.width / 2
8085
+ });
8086
+ };
8087
+ updatePosition();
8088
+ window.addEventListener("scroll", updatePosition, true);
8089
+ window.addEventListener("resize", updatePosition);
8090
+ return () => {
8091
+ window.removeEventListener("scroll", updatePosition, true);
8092
+ window.removeEventListener("resize", updatePosition);
8093
+ };
8094
+ }, [editPopoverMounted]);
8095
+ useLayoutEffect4(() => {
8096
+ if (!isEditing || !containerRef.current) {
8097
+ setIconPickerPos(null);
8098
+ return;
8099
+ }
8100
+ const updatePosition = () => {
8101
+ if (!containerRef.current) return;
8102
+ const rect = containerRef.current.getBoundingClientRect();
8103
+ const popoverHeight = 400;
8104
+ const spaceBelow = window.innerHeight - rect.bottom;
8105
+ const spaceAbove = rect.top;
8106
+ const isAbove = spaceBelow < popoverHeight && spaceAbove > spaceBelow;
8107
+ setIconPickerPos({
8108
+ top: isAbove ? rect.top - 8 : rect.bottom + 8,
8109
+ left: rect.left + rect.width / 2,
8110
+ isAbove
8111
+ });
8112
+ };
8113
+ updatePosition();
8114
+ window.addEventListener("scroll", updatePosition, true);
8115
+ window.addEventListener("resize", updatePosition);
8116
+ return () => {
8117
+ window.removeEventListener("scroll", updatePosition, true);
8118
+ window.removeEventListener("resize", updatePosition);
8119
+ };
8120
+ }, [isEditing]);
8121
+ React9.useEffect(() => {
8122
+ if (!isEditing) return;
8123
+ const handleClickOutside = (event) => {
8124
+ const target = event.target;
8125
+ if (iconPopoverRef.current?.contains(target)) return;
8126
+ if (containerRef.current?.contains(target)) return;
8127
+ setIsEditing(false);
8128
+ };
8129
+ document.addEventListener("mousedown", handleClickOutside);
8130
+ return () => document.removeEventListener("mousedown", handleClickOutside);
8131
+ }, [isEditing]);
8132
+ const startEdit = useCallback21(() => {
8133
+ hideEditPopover();
8134
+ setIsEditing(true);
8135
+ }, [hideEditPopover]);
8136
+ const handleIconSelect = useCallback21((iconName) => {
8137
+ iconContent.set(iconName || "", "user");
8138
+ iconContent.save();
8139
+ setIsEditing(false);
8140
+ setShowSuccess(true);
8141
+ setTimeout(() => setShowSuccess(false), 500);
8142
+ }, [iconContent]);
8143
+ const handleCancel = useCallback21(() => {
8144
+ setIsEditing(false);
8145
+ }, []);
8146
+ if (mode === "read-only") {
8147
+ if (!currentIcon) return null;
8148
+ return /* @__PURE__ */ jsx20(
8149
+ DynamicIcon,
8150
+ {
8151
+ name: currentIcon,
8152
+ size,
8153
+ stroke,
8154
+ className,
8155
+ "data-ya-restricted": "true",
8156
+ "data-field-id": fieldId
8157
+ }
8158
+ );
8159
+ }
8160
+ return /* @__PURE__ */ jsxs12("span", { className: `ya-icon-wrapper ${wrapperClassName || ""}`, children: [
8161
+ /* @__PURE__ */ jsx20(
8162
+ "span",
8163
+ {
8164
+ ref: containerRef,
8165
+ className: `ya-icon-editable ${isEditing ? "ya-icon-editing" : ""} ${showSuccess ? "ya-icon-success" : ""}`,
8166
+ "data-ya-restricted": "true",
8167
+ "data-ya-icon": "true",
8168
+ "data-field-id": fieldId,
8169
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
8170
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
8171
+ onFocus: safeTriangleHandlers.onFocus,
8172
+ children: currentIcon ? /* @__PURE__ */ jsx20(DynamicIcon, { name: currentIcon, size, stroke, className }) : (
8173
+ // Placeholder when no icon set
8174
+ /* @__PURE__ */ jsx20("span", { className: `ya-icon-placeholder ${className || ""}`, style: { width: size, height: size }, children: /* @__PURE__ */ jsx20(DynamicIcon, { name: "IconPlus", size: size * 0.6, stroke }) })
8175
+ )
8176
+ }
8177
+ ),
8178
+ editPopoverMounted && editPopoverPos && createPortal7(
8179
+ /* @__PURE__ */ jsx20(
8180
+ "div",
8181
+ {
8182
+ ref: editPopoverRef,
8183
+ className: "ya-icon-edit-popover",
8184
+ style: {
8185
+ top: editPopoverPos.top,
8186
+ left: editPopoverPos.left,
8187
+ transform: "translateX(-50%)",
8188
+ opacity: editPopoverVisible ? 1 : 0
8189
+ },
8190
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
8191
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
8192
+ children: /* @__PURE__ */ jsx20("button", { type: "button", onClick: startEdit, children: "Edit icon" })
8193
+ }
8194
+ ),
8195
+ document.body
8196
+ ),
8197
+ /* @__PURE__ */ jsx20(
8198
+ SafeTriangleBelow,
8199
+ {
8200
+ triggerRef,
8201
+ popoverRef: editPopoverRef,
8202
+ isVisible: showEditPopover && !isEditing && mode === "inline-edit",
8203
+ onLeave: triangleProps.onLeave,
8204
+ onStayInside: triangleProps.onStayInside
8205
+ }
8206
+ ),
8207
+ isEditing && iconPickerPos && createPortal7(
8208
+ /* @__PURE__ */ jsx20(
8209
+ "div",
8210
+ {
8211
+ ref: iconPopoverRef,
8212
+ className: `ya-icon-picker-popover ${iconPickerPos.isAbove ? "ya-icon-picker-popover--above" : ""}`,
8213
+ style: {
8214
+ top: iconPickerPos.isAbove ? "auto" : iconPickerPos.top,
8215
+ bottom: iconPickerPos.isAbove ? window.innerHeight - iconPickerPos.top : "auto",
8216
+ left: iconPickerPos.left,
8217
+ transform: "translateX(-50%)"
8218
+ },
8219
+ children: /* @__PURE__ */ jsx20(
8220
+ IconPicker,
8221
+ {
8222
+ value: currentIcon,
8223
+ onChange: handleIconSelect,
8224
+ onClose: handleCancel
8225
+ }
8226
+ )
8227
+ }
8228
+ ),
8229
+ document.body
6561
8230
  )
6562
8231
  ] });
6563
8232
  }
6564
8233
 
6565
8234
  // src/components/YaContainer.tsx
6566
- import { useCallback as useCallback20, useEffect as useEffect18, useRef as useRef19, useState as useState18 } from "react";
6567
- import { createPortal as createPortal8 } from "react-dom";
8235
+ import { useCallback as useCallback23, useEffect as useEffect22, useRef as useRef22, useState as useState22 } from "react";
8236
+ import { createPortal as createPortal9 } from "react-dom";
6568
8237
 
6569
8238
  // src/components/Tooltip.tsx
6570
- import { useState as useState17, useRef as useRef18, useEffect as useEffect17, useLayoutEffect as useLayoutEffect4, useCallback as useCallback19 } from "react";
6571
- import { createPortal as createPortal7 } from "react-dom";
8239
+ import { useState as useState21, useRef as useRef21, useEffect as useEffect21, useLayoutEffect as useLayoutEffect5, useCallback as useCallback22 } from "react";
8240
+ import { createPortal as createPortal8 } from "react-dom";
6572
8241
 
6573
8242
  // src/components/tooltip.css
6574
8243
  styleInject('.ya-tooltip-trigger {\n display: inline-flex;\n}\n.ya-tooltip-v2 {\n position: fixed;\n z-index: 10000;\n padding: 8px 12px;\n background: #1a1a1a;\n color: white;\n font-size: 13px;\n font-weight: 500;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n animation: ya-tooltip-v2-fade-in 0.15s ease-out;\n}\n@keyframes ya-tooltip-v2-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.ya-tooltip-v2-arrow {\n position: absolute;\n width: 0;\n height: 0;\n left: 50%;\n transform: translateX(-50%);\n}\n.ya-tooltip-v2-bottom .ya-tooltip-v2-arrow {\n top: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-top .ya-tooltip-v2-arrow {\n bottom: -6px;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-left .ya-tooltip-v2-arrow {\n right: -6px;\n left: auto;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-left: 6px solid #1a1a1a;\n}\n.ya-tooltip-v2-right .ya-tooltip-v2-arrow {\n left: -6px;\n top: 50%;\n transform: translateY(-50%);\n border-top: 6px solid transparent;\n border-bottom: 6px solid transparent;\n border-right: 6px solid #1a1a1a;\n}\n');
6575
8244
 
6576
8245
  // src/components/Tooltip.tsx
6577
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
8246
+ import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
6578
8247
  function Tooltip({
6579
8248
  content,
6580
8249
  children,
6581
8250
  position = "bottom",
6582
8251
  delay = 0
6583
8252
  }) {
6584
- const [isVisible, setIsVisible] = useState17(false);
6585
- const [tooltipPosition, setTooltipPosition] = useState17(null);
6586
- const [isMounted, setIsMounted] = useState17(false);
6587
- const triggerRef = useRef18(null);
6588
- const tooltipRef = useRef18(null);
6589
- const timeoutRef = useRef18(null);
6590
- useEffect17(() => {
8253
+ const [isVisible, setIsVisible] = useState21(false);
8254
+ const [tooltipPosition, setTooltipPosition] = useState21(null);
8255
+ const [isMounted, setIsMounted] = useState21(false);
8256
+ const triggerRef = useRef21(null);
8257
+ const tooltipRef = useRef21(null);
8258
+ const timeoutRef = useRef21(null);
8259
+ useEffect21(() => {
6591
8260
  setIsMounted(true);
6592
8261
  }, []);
6593
- const calculatePosition = useCallback19(() => {
8262
+ const calculatePosition = useCallback22(() => {
6594
8263
  if (!triggerRef.current) return null;
6595
8264
  const triggerRect = triggerRef.current.getBoundingClientRect();
6596
8265
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -6675,7 +8344,7 @@ function Tooltip({
6675
8344
  setIsVisible(false);
6676
8345
  setTooltipPosition(null);
6677
8346
  };
6678
- useEffect17(() => {
8347
+ useEffect21(() => {
6679
8348
  return () => {
6680
8349
  if (timeoutRef.current) {
6681
8350
  clearTimeout(timeoutRef.current);
@@ -6683,7 +8352,7 @@ function Tooltip({
6683
8352
  };
6684
8353
  }, []);
6685
8354
  const edgePadding = 12;
6686
- useLayoutEffect4(() => {
8355
+ useLayoutEffect5(() => {
6687
8356
  if (!isVisible || !tooltipRef.current || !tooltipPosition || tooltipPosition.adjusted) {
6688
8357
  return;
6689
8358
  }
@@ -6734,8 +8403,8 @@ function Tooltip({
6734
8403
  }
6735
8404
  }
6736
8405
  }, [isVisible, tooltipPosition]);
6737
- const tooltipContent = isMounted && isVisible && tooltipPosition ? createPortal7(
6738
- /* @__PURE__ */ jsxs10(
8406
+ const tooltipContent = isMounted && isVisible && tooltipPosition ? createPortal8(
8407
+ /* @__PURE__ */ jsxs13(
6739
8408
  "div",
6740
8409
  {
6741
8410
  ref: tooltipRef,
@@ -6748,7 +8417,7 @@ function Tooltip({
6748
8417
  role: "tooltip",
6749
8418
  children: [
6750
8419
  content,
6751
- /* @__PURE__ */ jsx17(
8420
+ /* @__PURE__ */ jsx21(
6752
8421
  "div",
6753
8422
  {
6754
8423
  className: "ya-tooltip-v2-arrow",
@@ -6760,8 +8429,8 @@ function Tooltip({
6760
8429
  ),
6761
8430
  document.body
6762
8431
  ) : null;
6763
- return /* @__PURE__ */ jsxs10(Fragment5, { children: [
6764
- /* @__PURE__ */ jsx17(
8432
+ return /* @__PURE__ */ jsxs13(Fragment6, { children: [
8433
+ /* @__PURE__ */ jsx21(
6765
8434
  "div",
6766
8435
  {
6767
8436
  ref: triggerRef,
@@ -6779,7 +8448,7 @@ function Tooltip({
6779
8448
  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');
6780
8449
 
6781
8450
  // src/components/YaContainer.tsx
6782
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
8451
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
6783
8452
  function parseBackgroundConfig(value) {
6784
8453
  if (!value) {
6785
8454
  return { type: "none" };
@@ -6821,8 +8490,8 @@ function deriveContainerLabel(element) {
6821
8490
  return tagLabels[tagName] || "Section";
6822
8491
  }
6823
8492
  function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAIClick, onClearClick, hasBackground }) {
6824
- const [position, setPosition] = useState18(null);
6825
- useEffect18(() => {
8493
+ const [position, setPosition] = useState22(null);
8494
+ useEffect22(() => {
6826
8495
  const updatePosition = () => {
6827
8496
  if (containerRef.current) {
6828
8497
  const rect = containerRef.current.getBoundingClientRect();
@@ -6841,8 +8510,8 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAICli
6841
8510
  };
6842
8511
  }, [containerRef]);
6843
8512
  if (!position) return null;
6844
- return createPortal8(
6845
- /* @__PURE__ */ jsxs11(
8513
+ return createPortal9(
8514
+ /* @__PURE__ */ jsxs14(
6846
8515
  "div",
6847
8516
  {
6848
8517
  className: "ya-container-toolbar",
@@ -6853,40 +8522,40 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick: _onAICli
6853
8522
  },
6854
8523
  onClick: (e) => e.stopPropagation(),
6855
8524
  children: [
6856
- /* @__PURE__ */ jsx18(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx18(
8525
+ /* @__PURE__ */ jsx22(Tooltip, { content: "Background Image", position: "bottom", children: /* @__PURE__ */ jsx22(
6857
8526
  "button",
6858
8527
  {
6859
8528
  type: "button",
6860
8529
  onClick: onImageClick,
6861
8530
  "aria-label": "Edit background image",
6862
- children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6863
- /* @__PURE__ */ jsx18("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
6864
- /* @__PURE__ */ jsx18("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
6865
- /* @__PURE__ */ jsx18("polyline", { points: "21 15 16 10 5 21" })
8531
+ children: /* @__PURE__ */ jsxs14("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
8532
+ /* @__PURE__ */ jsx22("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
8533
+ /* @__PURE__ */ jsx22("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
8534
+ /* @__PURE__ */ jsx22("polyline", { points: "21 15 16 10 5 21" })
6866
8535
  ] })
6867
8536
  }
6868
8537
  ) }),
6869
- /* @__PURE__ */ jsx18(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx18(
8538
+ /* @__PURE__ */ jsx22(Tooltip, { content: "Background Color", position: "bottom", children: /* @__PURE__ */ jsx22(
6870
8539
  "button",
6871
8540
  {
6872
8541
  type: "button",
6873
8542
  onClick: onColorClick,
6874
8543
  "aria-label": "Edit background color",
6875
- children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6876
- /* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "10" }),
6877
- /* @__PURE__ */ jsx18("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
8544
+ children: /* @__PURE__ */ jsxs14("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
8545
+ /* @__PURE__ */ jsx22("circle", { cx: "12", cy: "12", r: "10" }),
8546
+ /* @__PURE__ */ jsx22("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
6878
8547
  ] })
6879
8548
  }
6880
8549
  ) }),
6881
- hasBackground && /* @__PURE__ */ jsx18(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx18(
8550
+ hasBackground && /* @__PURE__ */ jsx22(Tooltip, { content: "Remove Background", position: "bottom", children: /* @__PURE__ */ jsx22(
6882
8551
  "button",
6883
8552
  {
6884
8553
  type: "button",
6885
8554
  onClick: onClearClick,
6886
8555
  "aria-label": "Clear background",
6887
- children: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
6888
- /* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "10" }),
6889
- /* @__PURE__ */ jsx18("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
8556
+ children: /* @__PURE__ */ jsxs14("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
8557
+ /* @__PURE__ */ jsx22("circle", { cx: "12", cy: "12", r: "10" }),
8558
+ /* @__PURE__ */ jsx22("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07" })
6890
8559
  ] })
6891
8560
  }
6892
8561
  ) })
@@ -6905,13 +8574,13 @@ function YaContainer({
6905
8574
  defaultBackground
6906
8575
  }) {
6907
8576
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
6908
- const containerRef = useRef19(null);
6909
- const [isHovered, setIsHovered] = useState18(false);
6910
- const [isSelected, setIsSelected] = useState18(false);
6911
- const [isDropMode, setIsDropMode] = useState18(false);
6912
- const [isDropHover, setIsDropHover] = useState18(false);
6913
- const [previewConfig, setPreviewConfig] = useState18(null);
6914
- useEffect18(() => {
8577
+ const containerRef = useRef22(null);
8578
+ const [isHovered, setIsHovered] = useState22(false);
8579
+ const [isSelected, setIsSelected] = useState22(false);
8580
+ const [isDropMode, setIsDropMode] = useState22(false);
8581
+ const [isDropHover, setIsDropHover] = useState22(false);
8582
+ const [previewConfig, setPreviewConfig] = useState22(null);
8583
+ useEffect22(() => {
6915
8584
  if (mode !== "inline-edit") return;
6916
8585
  const containerEl = containerRef.current;
6917
8586
  if (!containerEl) return;
@@ -6954,7 +8623,7 @@ function YaContainer({
6954
8623
  overlayCustomProps["--ya-overlay-color"] = displayConfig.overlay.color;
6955
8624
  overlayCustomProps["--ya-overlay-opacity"] = displayConfig.overlay.opacity;
6956
8625
  }
6957
- const handleImageClick = useCallback20(() => {
8626
+ const handleImageClick = useCallback23(() => {
6958
8627
  if (mode !== "inline-edit") return;
6959
8628
  setIsSelected(true);
6960
8629
  const rect = containerRef.current?.getBoundingClientRect();
@@ -6974,7 +8643,7 @@ function YaContainer({
6974
8643
  "*"
6975
8644
  );
6976
8645
  }, [mode, fieldId, backgroundConfig]);
6977
- const handleColorClick = useCallback20(() => {
8646
+ const handleColorClick = useCallback23(() => {
6978
8647
  if (mode !== "inline-edit") return;
6979
8648
  setIsSelected(true);
6980
8649
  const rect = containerRef.current?.getBoundingClientRect();
@@ -6994,7 +8663,7 @@ function YaContainer({
6994
8663
  "*"
6995
8664
  );
6996
8665
  }, [mode, fieldId, backgroundConfig]);
6997
- const handleAIClick = useCallback20(() => {
8666
+ const handleAIClick = useCallback23(() => {
6998
8667
  if (mode !== "inline-edit") return;
6999
8668
  const label = deriveContainerLabel(containerRef.current);
7000
8669
  window.parent.postMessage(
@@ -7007,14 +8676,14 @@ function YaContainer({
7007
8676
  "*"
7008
8677
  );
7009
8678
  }, [mode, fieldId, backgroundConfig]);
7010
- const handleClearClick = useCallback20(() => {
8679
+ const handleClearClick = useCallback23(() => {
7011
8680
  if (mode !== "inline-edit") return;
7012
8681
  const clearedConfig = { type: "none" };
7013
8682
  const serialized = serializeBackgroundConfig(clearedConfig);
7014
8683
  setValue(fieldId, serialized);
7015
8684
  saveToWorker?.(fieldId, serialized);
7016
8685
  }, [mode, fieldId, setValue, saveToWorker]);
7017
- useEffect18(() => {
8686
+ useEffect22(() => {
7018
8687
  if (mode !== "inline-edit") return;
7019
8688
  const handleMessage2 = (event) => {
7020
8689
  if (event.data?.type === "YA_CONTAINER_UPDATE_PREVIEW" && event.data.fieldId === fieldId) {
@@ -7035,7 +8704,7 @@ function YaContainer({
7035
8704
  window.addEventListener("message", handleMessage2);
7036
8705
  return () => window.removeEventListener("message", handleMessage2);
7037
8706
  }, [mode, fieldId]);
7038
- useEffect18(() => {
8707
+ useEffect22(() => {
7039
8708
  if (mode !== "inline-edit") return;
7040
8709
  const handleDropModeMessage = (event) => {
7041
8710
  if (event.data?.type === "DROP_MODE_START") {
@@ -7049,7 +8718,7 @@ function YaContainer({
7049
8718
  window.addEventListener("message", handleDropModeMessage);
7050
8719
  return () => window.removeEventListener("message", handleDropModeMessage);
7051
8720
  }, [mode]);
7052
- const handleDragEnter = useCallback20(
8721
+ const handleDragEnter = useCallback23(
7053
8722
  (e) => {
7054
8723
  if (!isDropMode) return;
7055
8724
  e.preventDefault();
@@ -7073,7 +8742,7 @@ function YaContainer({
7073
8742
  },
7074
8743
  [isDropMode, fieldId]
7075
8744
  );
7076
- const handleDragOver = useCallback20(
8745
+ const handleDragOver = useCallback23(
7077
8746
  (e) => {
7078
8747
  if (!isDropMode) return;
7079
8748
  e.preventDefault();
@@ -7081,7 +8750,7 @@ function YaContainer({
7081
8750
  },
7082
8751
  [isDropMode]
7083
8752
  );
7084
- const handleDragLeave = useCallback20(
8753
+ const handleDragLeave = useCallback23(
7085
8754
  (e) => {
7086
8755
  if (!isDropMode) return;
7087
8756
  e.preventDefault();
@@ -7095,7 +8764,7 @@ function YaContainer({
7095
8764
  },
7096
8765
  [isDropMode]
7097
8766
  );
7098
- const handleDrop = useCallback20(
8767
+ const handleDrop = useCallback23(
7099
8768
  (e) => {
7100
8769
  if (!isDropMode) return;
7101
8770
  e.preventDefault();
@@ -7113,7 +8782,7 @@ function YaContainer({
7113
8782
  },
7114
8783
  [isDropMode, fieldId]
7115
8784
  );
7116
- useEffect18(() => {
8785
+ useEffect22(() => {
7117
8786
  if (!isSelected || mode !== "inline-edit") return;
7118
8787
  let lastRectKey = "";
7119
8788
  let lastTime = 0;
@@ -7148,7 +8817,7 @@ function YaContainer({
7148
8817
  return () => cancelAnimationFrame(rafId);
7149
8818
  }, [isSelected, fieldId, mode]);
7150
8819
  if (mode === "read-only") {
7151
- return /* @__PURE__ */ jsx18(
8820
+ return /* @__PURE__ */ jsx22(
7152
8821
  Tag,
7153
8822
  {
7154
8823
  className: `ya-container ${className || ""}`,
@@ -7172,7 +8841,7 @@ function YaContainer({
7172
8841
  isDropHover ? "ya-container-drop-hover" : "",
7173
8842
  className || ""
7174
8843
  ].filter(Boolean).join(" ");
7175
- return /* @__PURE__ */ jsxs11(
8844
+ return /* @__PURE__ */ jsxs14(
7176
8845
  Tag,
7177
8846
  {
7178
8847
  ref: containerRef,
@@ -7191,7 +8860,7 @@ function YaContainer({
7191
8860
  onDrop: handleDrop,
7192
8861
  children: [
7193
8862
  children,
7194
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx18(
8863
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx22(
7195
8864
  Toolbar,
7196
8865
  {
7197
8866
  containerRef,
@@ -7208,10 +8877,10 @@ function YaContainer({
7208
8877
  }
7209
8878
 
7210
8879
  // src/components/StaticText.tsx
7211
- import { jsx as jsx19 } from "react/jsx-runtime";
8880
+ import { jsx as jsx23 } from "react/jsx-runtime";
7212
8881
  function MpText({ fieldId, className, as: Component = "span", children }) {
7213
8882
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
7214
- return /* @__PURE__ */ jsx19(
8883
+ return /* @__PURE__ */ jsx23(
7215
8884
  Component,
7216
8885
  {
7217
8886
  className,
@@ -7222,7 +8891,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
7222
8891
  }
7223
8892
 
7224
8893
  // src/components/StaticImage.tsx
7225
- import { jsx as jsx20 } from "react/jsx-runtime";
8894
+ import { jsx as jsx24 } from "react/jsx-runtime";
7226
8895
  function parseImageValue2(value) {
7227
8896
  if (!value) {
7228
8897
  return { src: "" };
@@ -7258,7 +8927,7 @@ function MpImage({
7258
8927
  const altText = imageData.alt || alt || fallbackAlt || "";
7259
8928
  const objectFit = imageData.objectFit || propObjectFit || "cover";
7260
8929
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
7261
- return /* @__PURE__ */ jsx20(
8930
+ return /* @__PURE__ */ jsx24(
7262
8931
  "img",
7263
8932
  {
7264
8933
  src: resolveAssetUrl(src),
@@ -7275,8 +8944,8 @@ function MpImage({
7275
8944
  }
7276
8945
 
7277
8946
  // src/components/MarkdownText.tsx
7278
- import { Fragment as Fragment6 } from "react";
7279
- import { jsx as jsx21 } from "react/jsx-runtime";
8947
+ import { Fragment as Fragment7 } from "react";
8948
+ import { jsx as jsx25 } from "react/jsx-runtime";
7280
8949
  function tokenize(text2) {
7281
8950
  const tokens = [];
7282
8951
  let remaining = text2;
@@ -7338,13 +9007,13 @@ function tokensToElements(tokens) {
7338
9007
  return tokens.map((token, index) => {
7339
9008
  switch (token.type) {
7340
9009
  case "text":
7341
- return /* @__PURE__ */ jsx21(Fragment6, { children: token.content }, index);
9010
+ return /* @__PURE__ */ jsx25(Fragment7, { children: token.content }, index);
7342
9011
  case "bold":
7343
- return /* @__PURE__ */ jsx21("strong", { children: token.content }, index);
9012
+ return /* @__PURE__ */ jsx25("strong", { children: token.content }, index);
7344
9013
  case "italic":
7345
- return /* @__PURE__ */ jsx21("em", { children: token.content }, index);
9014
+ return /* @__PURE__ */ jsx25("em", { children: token.content }, index);
7346
9015
  case "link":
7347
- return /* @__PURE__ */ jsx21(
9016
+ return /* @__PURE__ */ jsx25(
7348
9017
  "a",
7349
9018
  {
7350
9019
  href: token.url,
@@ -7356,7 +9025,7 @@ function tokensToElements(tokens) {
7356
9025
  index
7357
9026
  );
7358
9027
  case "newline":
7359
- return /* @__PURE__ */ jsx21("br", {}, index);
9028
+ return /* @__PURE__ */ jsx25("br", {}, index);
7360
9029
  default:
7361
9030
  return null;
7362
9031
  }
@@ -7368,14 +9037,14 @@ function parseMarkdownToElements(content) {
7368
9037
  }
7369
9038
  function MarkdownText({ content, className }) {
7370
9039
  const elements = parseMarkdownToElements(content);
7371
- return /* @__PURE__ */ jsx21("span", { className, children: elements });
9040
+ return /* @__PURE__ */ jsx25("span", { className, children: elements });
7372
9041
  }
7373
9042
 
7374
9043
  // src/components/CollectionPage.tsx
7375
9044
  import { useParams } from "wouter";
7376
9045
 
7377
9046
  // src/hooks/useCollection.ts
7378
- import { useState as useState19, useEffect as useEffect19, useCallback as useCallback21, useRef as useRef20 } from "react";
9047
+ import { useState as useState23, useEffect as useEffect23, useCallback as useCallback24, useRef as useRef23 } from "react";
7379
9048
 
7380
9049
  // src/lib/collection-client.ts
7381
9050
  function getEnvVar(key) {
@@ -7541,13 +9210,13 @@ function useCollectionList(options) {
7541
9210
  orderDir,
7542
9211
  enabled = true
7543
9212
  } = options;
7544
- const [data, setData] = useState19(null);
7545
- const [isLoading, setIsLoading] = useState19(true);
7546
- const [error, setError] = useState19(null);
7547
- const [totalCount, setTotalCount] = useState19(0);
7548
- const [currentPage, setCurrentPage] = useState19(page);
7549
- const fetchVersion = useRef20(0);
7550
- const fetchData = useCallback21(async (pageNum) => {
9213
+ const [data, setData] = useState23(null);
9214
+ const [isLoading, setIsLoading] = useState23(true);
9215
+ const [error, setError] = useState23(null);
9216
+ const [totalCount, setTotalCount] = useState23(0);
9217
+ const [currentPage, setCurrentPage] = useState23(page);
9218
+ const fetchVersion = useRef23(0);
9219
+ const fetchData = useCallback24(async (pageNum) => {
7551
9220
  if (!enabled) {
7552
9221
  setIsLoading(false);
7553
9222
  return;
@@ -7585,15 +9254,15 @@ function useCollectionList(options) {
7585
9254
  }
7586
9255
  }
7587
9256
  }, [collection, JSON.stringify(filters), pageSize, orderBy, orderDir, enabled]);
7588
- useEffect19(() => {
9257
+ useEffect23(() => {
7589
9258
  fetchData(page);
7590
9259
  }, [fetchData, page]);
7591
9260
  const totalPages = Math.ceil(totalCount / pageSize);
7592
9261
  const hasMore = currentPage < totalPages;
7593
- const refetch = useCallback21(() => {
9262
+ const refetch = useCallback24(() => {
7594
9263
  fetchData(currentPage);
7595
9264
  }, [fetchData, currentPage]);
7596
- const goToPage = useCallback21((newPage) => {
9265
+ const goToPage = useCallback24((newPage) => {
7597
9266
  if (newPage >= 1 && newPage <= Math.max(1, totalPages)) {
7598
9267
  fetchData(newPage);
7599
9268
  }
@@ -7617,12 +9286,12 @@ function useCollectionRecord(options) {
7617
9286
  slugValue,
7618
9287
  enabled = true
7619
9288
  } = options;
7620
- const [data, setData] = useState19(null);
7621
- const [isLoading, setIsLoading] = useState19(true);
7622
- const [error, setError] = useState19(null);
7623
- const [notFound, setNotFound] = useState19(false);
7624
- const fetchVersion = useRef20(0);
7625
- const fetchData = useCallback21(async () => {
9289
+ const [data, setData] = useState23(null);
9290
+ const [isLoading, setIsLoading] = useState23(true);
9291
+ const [error, setError] = useState23(null);
9292
+ const [notFound, setNotFound] = useState23(false);
9293
+ const fetchVersion = useRef23(0);
9294
+ const fetchData = useCallback24(async () => {
7626
9295
  if (!enabled || !slugValue) {
7627
9296
  setIsLoading(false);
7628
9297
  return;
@@ -7660,10 +9329,10 @@ function useCollectionRecord(options) {
7660
9329
  }
7661
9330
  }
7662
9331
  }, [collection, slugField, slugValue, enabled]);
7663
- useEffect19(() => {
9332
+ useEffect23(() => {
7664
9333
  fetchData();
7665
9334
  }, [fetchData]);
7666
- const refetch = useCallback21(() => {
9335
+ const refetch = useCallback24(() => {
7667
9336
  fetchData();
7668
9337
  }, [fetchData]);
7669
9338
  return {
@@ -7720,7 +9389,7 @@ function CollectionDetailPage({
7720
9389
  }
7721
9390
 
7722
9391
  // src/components/CollectionList.tsx
7723
- import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
9392
+ import { Fragment as Fragment8, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
7724
9393
  function CollectionList({
7725
9394
  collection,
7726
9395
  prefix,
@@ -7753,7 +9422,7 @@ function CollectionList({
7753
9422
  { length: skeletonCount },
7754
9423
  (_, index) => skeleton({ index })
7755
9424
  );
7756
- return Wrapper ? /* @__PURE__ */ jsx22(Wrapper, { children: skeletonItems }) : /* @__PURE__ */ jsx22(Fragment7, { children: skeletonItems });
9425
+ return Wrapper ? /* @__PURE__ */ jsx26(Wrapper, { children: skeletonItems }) : /* @__PURE__ */ jsx26(Fragment8, { children: skeletonItems });
7757
9426
  }
7758
9427
  if (result.error) {
7759
9428
  return error?.(result.error) ?? null;
@@ -7763,7 +9432,7 @@ function CollectionList({
7763
9432
  }
7764
9433
  const items = result.data.map((record, index) => {
7765
9434
  const fieldPrefix = `${prefix}.${record.id}`;
7766
- return /* @__PURE__ */ jsx22(
9435
+ return /* @__PURE__ */ jsx26(
7767
9436
  CollectionContentProvider,
7768
9437
  {
7769
9438
  record: record.data,
@@ -7776,9 +9445,9 @@ function CollectionList({
7776
9445
  record.id
7777
9446
  );
7778
9447
  });
7779
- const content = Wrapper ? /* @__PURE__ */ jsx22(Wrapper, { children: items }) : /* @__PURE__ */ jsx22(Fragment7, { children: items });
9448
+ const content = Wrapper ? /* @__PURE__ */ jsx26(Wrapper, { children: items }) : /* @__PURE__ */ jsx26(Fragment8, { children: items });
7780
9449
  if (pagination) {
7781
- return /* @__PURE__ */ jsxs12(Fragment7, { children: [
9450
+ return /* @__PURE__ */ jsxs15(Fragment8, { children: [
7782
9451
  content,
7783
9452
  pagination({
7784
9453
  currentPage: result.currentPage,
@@ -7793,7 +9462,7 @@ function CollectionList({
7793
9462
  }
7794
9463
 
7795
9464
  // src/components/CollectionItem.tsx
7796
- import { jsx as jsx23 } from "react/jsx-runtime";
9465
+ import { jsx as jsx27 } from "react/jsx-runtime";
7797
9466
  function CollectionItem({
7798
9467
  collection,
7799
9468
  prefix,
@@ -7823,7 +9492,7 @@ function CollectionItem({
7823
9492
  if (result.error || result.notFound || !result.data) {
7824
9493
  return children(renderProps);
7825
9494
  }
7826
- return /* @__PURE__ */ jsx23(
9495
+ return /* @__PURE__ */ jsx27(
7827
9496
  CollectionContentProvider,
7828
9497
  {
7829
9498
  record: result.data.data,
@@ -7838,10 +9507,10 @@ function CollectionItem({
7838
9507
 
7839
9508
  // src/router/Link.tsx
7840
9509
  import { Link as WouterLink2 } from "wouter";
7841
- import { jsx as jsx24 } from "react/jsx-runtime";
9510
+ import { jsx as jsx28 } from "react/jsx-runtime";
7842
9511
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
7843
9512
  const target = href ?? to ?? "/";
7844
- return /* @__PURE__ */ jsx24(WouterLink2, { href: target, className, onClick, replace, ...props, children });
9513
+ return /* @__PURE__ */ jsx28(WouterLink2, { href: target, className, onClick, replace, ...props, children });
7845
9514
  }
7846
9515
 
7847
9516
  // src/router/useNavigate.ts
@@ -7860,7 +9529,7 @@ function useNavigate() {
7860
9529
 
7861
9530
  // src/router/Router.tsx
7862
9531
  import { Router as WouterRouter } from "wouter";
7863
- import { jsx as jsx25 } from "react/jsx-runtime";
9532
+ import { jsx as jsx29 } from "react/jsx-runtime";
7864
9533
  function detectBasename() {
7865
9534
  if (typeof window === "undefined") return "";
7866
9535
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -7875,11 +9544,11 @@ function detectBasename() {
7875
9544
  }
7876
9545
  function Router({ children, base }) {
7877
9546
  const basename = base ?? detectBasename();
7878
- return /* @__PURE__ */ jsx25(WouterRouter, { base: basename, children });
9547
+ return /* @__PURE__ */ jsx29(WouterRouter, { base: basename, children });
7879
9548
  }
7880
9549
 
7881
9550
  // src/router/ScrollRestoration.tsx
7882
- import { useEffect as useEffect20, useRef as useRef21 } from "react";
9551
+ import { useEffect as useEffect24, useRef as useRef24 } from "react";
7883
9552
  import { useLocation as useLocation3 } from "wouter";
7884
9553
  var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
7885
9554
  var HISTORY_INDEX_KEY = "yoamigo-history-index";
@@ -7915,10 +9584,10 @@ function setHistoryIndex(index) {
7915
9584
  var globalHistoryIndex = 0;
7916
9585
  function ScrollRestoration() {
7917
9586
  const [location] = useLocation3();
7918
- const previousLocation = useRef21(location);
7919
- const isPopState = useRef21(false);
7920
- const scrollPositionsRef = useRef21({});
7921
- useEffect20(() => {
9587
+ const previousLocation = useRef24(location);
9588
+ const isPopState = useRef24(false);
9589
+ const scrollPositionsRef = useRef24({});
9590
+ useEffect24(() => {
7922
9591
  if (typeof history !== "undefined" && "scrollRestoration" in history) {
7923
9592
  history.scrollRestoration = "manual";
7924
9593
  }
@@ -7936,7 +9605,7 @@ function ScrollRestoration() {
7936
9605
  window.addEventListener("popstate", handlePopState);
7937
9606
  return () => window.removeEventListener("popstate", handlePopState);
7938
9607
  }, []);
7939
- useEffect20(() => {
9608
+ useEffect24(() => {
7940
9609
  if (previousLocation.current === location) return;
7941
9610
  const prevHistoryIndex = globalHistoryIndex;
7942
9611
  const currentScrollY = window.scrollY;
@@ -7956,7 +9625,7 @@ function ScrollRestoration() {
7956
9625
  }
7957
9626
  previousLocation.current = location;
7958
9627
  }, [location]);
7959
- useEffect20(() => {
9628
+ useEffect24(() => {
7960
9629
  let timeoutId;
7961
9630
  const handleScroll = () => {
7962
9631
  clearTimeout(timeoutId);
@@ -8060,12 +9729,15 @@ function video(config) {
8060
9729
  function embed(config) {
8061
9730
  return JSON.stringify(config);
8062
9731
  }
9732
+ function link(href) {
9733
+ return href;
9734
+ }
8063
9735
 
8064
9736
  // src/contexts/CartContext.tsx
8065
- import { createContext as createContext5, useContext as useContext5, useEffect as useEffect22 } from "react";
9737
+ import { createContext as createContext5, useContext as useContext5, useEffect as useEffect26 } from "react";
8066
9738
 
8067
9739
  // src/hooks/useCart.ts
8068
- import { useState as useState20, useEffect as useEffect21, useCallback as useCallback22, useRef as useRef22 } from "react";
9740
+ import { useState as useState24, useEffect as useEffect25, useCallback as useCallback25, useRef as useRef25 } from "react";
8069
9741
 
8070
9742
  // src/lib/cart-storage.ts
8071
9743
  var CART_STORAGE_KEY_PREFIX = "yoamigo_cart_";
@@ -8201,11 +9873,11 @@ function getConfig2(options) {
8201
9873
  }
8202
9874
  function useCart(options = {}) {
8203
9875
  const { userToken } = options;
8204
- const [items, setItems] = useState20([]);
8205
- const [isLoading, setIsLoading] = useState20(true);
8206
- const [error, setError] = useState20(null);
8207
- const fetchVersion = useRef22(0);
8208
- const configRef = useRef22(null);
9876
+ const [items, setItems] = useState24([]);
9877
+ const [isLoading, setIsLoading] = useState24(true);
9878
+ const [error, setError] = useState24(null);
9879
+ const fetchVersion = useRef25(0);
9880
+ const configRef = useRef25(null);
8209
9881
  if (!configRef.current && typeof window !== "undefined") {
8210
9882
  try {
8211
9883
  configRef.current = getConfig2(options);
@@ -8214,7 +9886,7 @@ function useCart(options = {}) {
8214
9886
  }
8215
9887
  const isAuthenticated = !!userToken;
8216
9888
  const sessionId = typeof window !== "undefined" ? getSessionId() : null;
8217
- const apiCall = useCallback22(async (endpoint, method = "GET", body) => {
9889
+ const apiCall = useCallback25(async (endpoint, method = "GET", body) => {
8218
9890
  const config = configRef.current;
8219
9891
  if (!config) throw new Error("Cart not configured");
8220
9892
  const headers = {
@@ -8235,7 +9907,7 @@ function useCart(options = {}) {
8235
9907
  );
8236
9908
  return response.json();
8237
9909
  }, [userToken, isAuthenticated, sessionId]);
8238
- const fetchCart = useCallback22(async () => {
9910
+ const fetchCart = useCallback25(async () => {
8239
9911
  const config = configRef.current;
8240
9912
  if (!config) {
8241
9913
  setIsLoading(false);
@@ -8274,10 +9946,10 @@ function useCart(options = {}) {
8274
9946
  }
8275
9947
  }
8276
9948
  }, [apiCall, isAuthenticated, sessionId]);
8277
- useEffect21(() => {
9949
+ useEffect25(() => {
8278
9950
  fetchCart();
8279
9951
  }, [fetchCart]);
8280
- const addItem = useCallback22(async (productId, collectionSlug, quantity = 1, variantId, data) => {
9952
+ const addItem = useCallback25(async (productId, collectionSlug, quantity = 1, variantId, data) => {
8281
9953
  const config = configRef.current;
8282
9954
  if (!config) throw new Error("Cart not configured");
8283
9955
  setError(null);
@@ -8305,7 +9977,7 @@ function useCart(options = {}) {
8305
9977
  throw err;
8306
9978
  }
8307
9979
  }, [apiCall, isAuthenticated, sessionId]);
8308
- const updateQuantity = useCallback22(async (itemId, quantity) => {
9980
+ const updateQuantity = useCallback25(async (itemId, quantity) => {
8309
9981
  const config = configRef.current;
8310
9982
  if (!config) throw new Error("Cart not configured");
8311
9983
  setError(null);
@@ -8327,7 +9999,7 @@ function useCart(options = {}) {
8327
9999
  throw err;
8328
10000
  }
8329
10001
  }, [apiCall, isAuthenticated, sessionId]);
8330
- const removeItem = useCallback22(async (itemId) => {
10002
+ const removeItem = useCallback25(async (itemId) => {
8331
10003
  const config = configRef.current;
8332
10004
  if (!config) throw new Error("Cart not configured");
8333
10005
  setError(null);
@@ -8349,7 +10021,7 @@ function useCart(options = {}) {
8349
10021
  throw err;
8350
10022
  }
8351
10023
  }, [apiCall, isAuthenticated, sessionId]);
8352
- const clearCart = useCallback22(async () => {
10024
+ const clearCart = useCallback25(async () => {
8353
10025
  const config = configRef.current;
8354
10026
  if (!config) throw new Error("Cart not configured");
8355
10027
  setError(null);
@@ -8371,7 +10043,7 @@ function useCart(options = {}) {
8371
10043
  throw err;
8372
10044
  }
8373
10045
  }, [apiCall, isAuthenticated, sessionId]);
8374
- const mergeGuestCart = useCallback22(async () => {
10046
+ const mergeGuestCart = useCallback25(async () => {
8375
10047
  if (!isAuthenticated || !sessionId) return;
8376
10048
  setError(null);
8377
10049
  try {
@@ -8408,7 +10080,7 @@ function useCart(options = {}) {
8408
10080
  }
8409
10081
 
8410
10082
  // src/contexts/CartContext.tsx
8411
- import { jsx as jsx26 } from "react/jsx-runtime";
10083
+ import { jsx as jsx30 } from "react/jsx-runtime";
8412
10084
  var CartContext = createContext5(null);
8413
10085
  function CartProvider({
8414
10086
  children,
@@ -8417,13 +10089,13 @@ function CartProvider({
8417
10089
  ...options
8418
10090
  }) {
8419
10091
  const cart = useCart({ ...options, userToken });
8420
- useEffect22(() => {
10092
+ useEffect26(() => {
8421
10093
  if (userToken) {
8422
10094
  cart.mergeGuestCart();
8423
10095
  }
8424
10096
  onUserTokenChange?.(!!userToken);
8425
10097
  }, [userToken]);
8426
- return /* @__PURE__ */ jsx26(CartContext.Provider, { value: cart, children });
10098
+ return /* @__PURE__ */ jsx30(CartContext.Provider, { value: cart, children });
8427
10099
  }
8428
10100
  function useCartContext() {
8429
10101
  const context = useContext5(CartContext);
@@ -8437,7 +10109,7 @@ function useOptionalCartContext() {
8437
10109
  }
8438
10110
 
8439
10111
  // src/hooks/useCheckout.ts
8440
- import { useState as useState21, useCallback as useCallback23, useRef as useRef23 } from "react";
10112
+ import { useState as useState25, useCallback as useCallback26, useRef as useRef26 } from "react";
8441
10113
  function getConfig3(options) {
8442
10114
  if (typeof window === "undefined") {
8443
10115
  throw new Error("useCheckout requires browser environment");
@@ -8455,9 +10127,9 @@ function getConfig3(options) {
8455
10127
  }
8456
10128
  function useCheckout(options = {}) {
8457
10129
  const { userToken } = options;
8458
- const [isLoading, setIsLoading] = useState21(false);
8459
- const [error, setError] = useState21(null);
8460
- const configRef = useRef23(null);
10130
+ const [isLoading, setIsLoading] = useState25(false);
10131
+ const [error, setError] = useState25(null);
10132
+ const configRef = useRef26(null);
8461
10133
  if (!configRef.current && typeof window !== "undefined") {
8462
10134
  try {
8463
10135
  configRef.current = getConfig3(options);
@@ -8466,7 +10138,7 @@ function useCheckout(options = {}) {
8466
10138
  }
8467
10139
  const isAuthenticated = !!userToken;
8468
10140
  const sessionId = typeof window !== "undefined" ? getSessionId() : null;
8469
- const initiateCheckout = useCallback23(async (checkoutOptions) => {
10141
+ const initiateCheckout = useCallback26(async (checkoutOptions) => {
8470
10142
  const config = configRef.current;
8471
10143
  if (!config) {
8472
10144
  throw new Error("Checkout not configured");
@@ -8511,10 +10183,10 @@ function useCheckout(options = {}) {
8511
10183
  }
8512
10184
  function useCheckoutStatus(options) {
8513
10185
  const { userToken, sessionId: checkoutSessionId, poll = false, pollInterval = 2e3 } = options;
8514
- const [status, setStatus] = useState21(null);
8515
- const [isLoading, setIsLoading] = useState21(true);
8516
- const [error, setError] = useState21(null);
8517
- const configRef = useRef23(null);
10186
+ const [status, setStatus] = useState25(null);
10187
+ const [isLoading, setIsLoading] = useState25(true);
10188
+ const [error, setError] = useState25(null);
10189
+ const configRef = useRef26(null);
8518
10190
  if (!configRef.current && typeof window !== "undefined") {
8519
10191
  try {
8520
10192
  configRef.current = getConfig3(options);
@@ -8523,7 +10195,7 @@ function useCheckoutStatus(options) {
8523
10195
  }
8524
10196
  const isAuthenticated = !!userToken;
8525
10197
  const guestSessionId = typeof window !== "undefined" ? getSessionId() : null;
8526
- const fetchStatus = useCallback23(async () => {
10198
+ const fetchStatus = useCallback26(async () => {
8527
10199
  const config = configRef.current;
8528
10200
  if (!config || !checkoutSessionId) {
8529
10201
  setIsLoading(false);
@@ -8555,7 +10227,7 @@ function useCheckoutStatus(options) {
8555
10227
  setIsLoading(false);
8556
10228
  }
8557
10229
  }, [checkoutSessionId, userToken, isAuthenticated, guestSessionId]);
8558
- useState21(() => {
10230
+ useState25(() => {
8559
10231
  fetchStatus();
8560
10232
  if (poll) {
8561
10233
  const interval = setInterval(() => {
@@ -8647,7 +10319,7 @@ function useProduct(options) {
8647
10319
  }
8648
10320
 
8649
10321
  // src/hooks/useSubscription.ts
8650
- import { useState as useState22, useCallback as useCallback24, useRef as useRef24 } from "react";
10322
+ import { useState as useState26, useCallback as useCallback27, useRef as useRef27 } from "react";
8651
10323
  function getConfig4(options) {
8652
10324
  if (typeof window === "undefined") {
8653
10325
  throw new Error("useSubscription requires browser environment");
@@ -8665,16 +10337,16 @@ function getConfig4(options) {
8665
10337
  }
8666
10338
  function useSubscription(options = {}) {
8667
10339
  const { userToken } = options;
8668
- const [isLoading, setIsLoading] = useState22(false);
8669
- const [error, setError] = useState22(null);
8670
- const configRef = useRef24(null);
10340
+ const [isLoading, setIsLoading] = useState26(false);
10341
+ const [error, setError] = useState26(null);
10342
+ const configRef = useRef27(null);
8671
10343
  if (!configRef.current && typeof window !== "undefined") {
8672
10344
  try {
8673
10345
  configRef.current = getConfig4(options);
8674
10346
  } catch {
8675
10347
  }
8676
10348
  }
8677
- const subscribe = useCallback24(async (params) => {
10349
+ const subscribe = useCallback27(async (params) => {
8678
10350
  const config = configRef.current;
8679
10351
  if (!config) {
8680
10352
  return {
@@ -8740,7 +10412,7 @@ function useSubscription(options = {}) {
8740
10412
  }
8741
10413
 
8742
10414
  // src/hooks/useSubscriptionTiers.ts
8743
- import { useState as useState23, useCallback as useCallback25, useEffect as useEffect23, useRef as useRef25 } from "react";
10415
+ import { useState as useState27, useCallback as useCallback28, useEffect as useEffect27, useRef as useRef28 } from "react";
8744
10416
  function getConfig5(options) {
8745
10417
  if (typeof window === "undefined") {
8746
10418
  throw new Error("useSubscriptionTiers requires browser environment");
@@ -8762,17 +10434,17 @@ function getConfig5(options) {
8762
10434
  }
8763
10435
  function useSubscriptionTiers(options = {}) {
8764
10436
  const { fetchOnMount = true } = options;
8765
- const [tiers, setTiers] = useState23([]);
8766
- const [isLoading, setIsLoading] = useState23(false);
8767
- const [error, setError] = useState23(null);
8768
- const configRef = useRef25(null);
10437
+ const [tiers, setTiers] = useState27([]);
10438
+ const [isLoading, setIsLoading] = useState27(false);
10439
+ const [error, setError] = useState27(null);
10440
+ const configRef = useRef28(null);
8769
10441
  if (!configRef.current && typeof window !== "undefined") {
8770
10442
  try {
8771
10443
  configRef.current = getConfig5(options);
8772
10444
  } catch {
8773
10445
  }
8774
10446
  }
8775
- const refresh = useCallback25(async () => {
10447
+ const refresh = useCallback28(async () => {
8776
10448
  const config = configRef.current;
8777
10449
  if (!config) {
8778
10450
  setError("Subscription tiers not configured");
@@ -8804,7 +10476,7 @@ function useSubscriptionTiers(options = {}) {
8804
10476
  setIsLoading(false);
8805
10477
  }
8806
10478
  }, []);
8807
- useEffect23(() => {
10479
+ useEffect27(() => {
8808
10480
  if (fetchOnMount && configRef.current) {
8809
10481
  refresh();
8810
10482
  }
@@ -8818,7 +10490,7 @@ function useSubscriptionTiers(options = {}) {
8818
10490
  }
8819
10491
 
8820
10492
  // src/hooks/useCustomerPortal.ts
8821
- import { useState as useState24, useCallback as useCallback26, useRef as useRef26 } from "react";
10493
+ import { useState as useState28, useCallback as useCallback29, useRef as useRef29 } from "react";
8822
10494
  function getConfig6(options) {
8823
10495
  if (typeof window === "undefined") {
8824
10496
  throw new Error("useCustomerPortal requires browser environment");
@@ -8836,16 +10508,16 @@ function getConfig6(options) {
8836
10508
  }
8837
10509
  function useCustomerPortal(options) {
8838
10510
  const { userToken } = options;
8839
- const [isLoading, setIsLoading] = useState24(false);
8840
- const [error, setError] = useState24(null);
8841
- const configRef = useRef26(null);
10511
+ const [isLoading, setIsLoading] = useState28(false);
10512
+ const [error, setError] = useState28(null);
10513
+ const configRef = useRef29(null);
8842
10514
  if (!configRef.current && typeof window !== "undefined") {
8843
10515
  try {
8844
10516
  configRef.current = getConfig6(options);
8845
10517
  } catch {
8846
10518
  }
8847
10519
  }
8848
- const openPortal = useCallback26(async (params) => {
10520
+ const openPortal = useCallback29(async (params) => {
8849
10521
  const config = configRef.current;
8850
10522
  if (!config) {
8851
10523
  return {
@@ -8907,7 +10579,7 @@ function useCustomerPortal(options) {
8907
10579
  }
8908
10580
 
8909
10581
  // src/hooks/useSubscriptionStatus.ts
8910
- import { useState as useState25, useCallback as useCallback27, useRef as useRef27, useEffect as useEffect24 } from "react";
10582
+ import { useState as useState29, useCallback as useCallback30, useRef as useRef30, useEffect as useEffect28 } from "react";
8911
10583
  function getConfig7(options) {
8912
10584
  if (typeof window === "undefined") {
8913
10585
  throw new Error("useSubscriptionStatus requires browser environment");
@@ -8925,18 +10597,18 @@ function getConfig7(options) {
8925
10597
  }
8926
10598
  function useSubscriptionStatus(options) {
8927
10599
  const { userToken, autoFetch = true, pollInterval = 0 } = options;
8928
- const [status, setStatus] = useState25(null);
8929
- const [subscriptions, setSubscriptions] = useState25([]);
8930
- const [isLoading, setIsLoading] = useState25(autoFetch);
8931
- const [error, setError] = useState25(null);
8932
- const configRef = useRef27(null);
10600
+ const [status, setStatus] = useState29(null);
10601
+ const [subscriptions, setSubscriptions] = useState29([]);
10602
+ const [isLoading, setIsLoading] = useState29(autoFetch);
10603
+ const [error, setError] = useState29(null);
10604
+ const configRef = useRef30(null);
8933
10605
  if (!configRef.current && typeof window !== "undefined") {
8934
10606
  try {
8935
10607
  configRef.current = getConfig7(options);
8936
10608
  } catch {
8937
10609
  }
8938
10610
  }
8939
- const fetchStatus = useCallback27(async () => {
10611
+ const fetchStatus = useCallback30(async () => {
8940
10612
  const config = configRef.current;
8941
10613
  if (!config) {
8942
10614
  setError("Subscription status not configured");
@@ -8975,12 +10647,12 @@ function useSubscriptionStatus(options) {
8975
10647
  setIsLoading(false);
8976
10648
  }
8977
10649
  }, [userToken]);
8978
- useEffect24(() => {
10650
+ useEffect28(() => {
8979
10651
  if (autoFetch && userToken) {
8980
10652
  fetchStatus();
8981
10653
  }
8982
10654
  }, [autoFetch, userToken, fetchStatus]);
8983
- useEffect24(() => {
10655
+ useEffect28(() => {
8984
10656
  if (pollInterval <= 0 || !userToken) {
8985
10657
  return;
8986
10658
  }
@@ -9008,6 +10680,10 @@ export {
9008
10680
  CollectionListPage,
9009
10681
  ContentStoreProvider,
9010
10682
  ContentStoreProvider2 as ContentStoreProviderProd,
10683
+ DynamicIcon,
10684
+ ICON_CATEGORIES,
10685
+ ICON_METADATA,
10686
+ IconPicker,
9011
10687
  Link2 as Link,
9012
10688
  MarkdownText,
9013
10689
  Route,
@@ -9021,8 +10697,10 @@ export {
9021
10697
  Tooltip,
9022
10698
  YaContainer,
9023
10699
  YaEmbed,
10700
+ YaIcon,
9024
10701
  YaImage,
9025
10702
  YaLink,
10703
+ YaProtectedMedia,
9026
10704
  YaText,
9027
10705
  YaVideo,
9028
10706
  background,
@@ -9040,6 +10718,11 @@ export {
9040
10718
  getAllContent,
9041
10719
  getCollectionClient,
9042
10720
  getContent,
10721
+ getIcon,
10722
+ getIconLabel,
10723
+ getIconMeta,
10724
+ getIconPickerLabel,
10725
+ getIconsByCategory,
9043
10726
  getLocalCartItemCount,
9044
10727
  getLocalCartItems,
9045
10728
  getSessionId,
@@ -9048,13 +10731,20 @@ export {
9048
10731
  image,
9049
10732
  imageCrossfadeStrategy,
9050
10733
  initBuilderSelection,
10734
+ isIconLoaded,
10735
+ link,
9051
10736
  linkTransitionStrategy,
10737
+ loadIcon,
9052
10738
  parseBackgroundConfig,
9053
10739
  parseEmbedUrl,
9054
10740
  parseFieldValue,
10741
+ preloadIcons,
9055
10742
  registerContent,
10743
+ registerIcon,
10744
+ registerIcons,
9056
10745
  resetCollectionClient,
9057
10746
  resolveAssetUrl,
10747
+ searchIcons,
9058
10748
  serializeBackgroundConfig,
9059
10749
  serializeEmbedValue,
9060
10750
  serializeImageValue,