@ohhwells/bridge 0.1.68-next.205 → 0.1.68

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,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React11, { useCallback as useCallback8, useEffect as useEffect13, useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState12 } from "react";
4
+ import React11, { useCallback as useCallback7, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
5
5
  import { createRoot as createRoot2 } from "react-dom/client";
6
6
  import { flushSync as flushSync2 } from "react-dom";
7
7
 
@@ -83,12 +83,7 @@ function parseAiSectionsState(raw) {
83
83
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
84
84
  }));
85
85
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
86
- return {
87
- v: 1,
88
- sections,
89
- ...removed.length ? { removed } : {},
90
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
91
- };
86
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
92
87
  } catch {
93
88
  return EMPTY_AI_SECTIONS;
94
89
  }
@@ -101,7 +96,6 @@ function applyTreeToState(state, payload) {
101
96
  const entry = {
102
97
  id: payload.id,
103
98
  label: payload.label ?? "Generated section",
104
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
105
99
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
106
100
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
107
101
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -124,317 +118,6 @@ function deleteSectionFromState(state, sectionId) {
124
118
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
125
119
  }
126
120
 
127
- // src/lib/brand-chrome.ts
128
- var BRAND_NAME_KEY = "__ohw_brand_name";
129
- var BRAND_TITLE_KEY = "__ohw_site_title";
130
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
131
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
132
- BRAND_NAME_KEY,
133
- BRAND_TITLE_KEY,
134
- BRAND_FAVICON_LETTER_KEY
135
- ]);
136
- function upsertMeta(selector, attr, token, value) {
137
- let el = document.head.querySelector(selector);
138
- if (!el) {
139
- el = document.createElement("meta");
140
- el.setAttribute(attr, token);
141
- document.head.appendChild(el);
142
- }
143
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
144
- }
145
- function escapeXml(value) {
146
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
147
- }
148
- function applyLetterFavicon(letter) {
149
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
150
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
151
- let link = document.head.querySelector('link[rel="icon"]');
152
- if (!link) {
153
- link = document.createElement("link");
154
- link.rel = "icon";
155
- document.head.appendChild(link);
156
- }
157
- link.type = "image/svg+xml";
158
- if (link.href !== href) link.href = href;
159
- }
160
- function applyBrandChrome(content) {
161
- const name = content[BRAND_NAME_KEY];
162
- if (typeof name === "string" && name.length > 0) {
163
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
164
- if (el.textContent !== name) el.textContent = name;
165
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
166
- });
167
- }
168
- const title = content[BRAND_TITLE_KEY];
169
- if (typeof title === "string" && title.length > 0) {
170
- if (document.title !== title) document.title = title;
171
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
172
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
173
- }
174
- const letter = content[BRAND_FAVICON_LETTER_KEY];
175
- if (typeof letter === "string" && letter.length > 0) {
176
- applyLetterFavicon(letter);
177
- }
178
- }
179
-
180
- // src/lib/brand-kit.ts
181
- var BRAND_KIT_KEY = "__ohw_brand";
182
- var BRAND_VAR_PREFIX = "--ohw-brand-";
183
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
184
- (role) => `${BRAND_VAR_PREFIX}${role}`
185
- );
186
- var FONT_VARS = {
187
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
188
- body: ["--font-body", "--brand-font-body"]
189
- };
190
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
191
- function brandColorVars(kit) {
192
- const { dark, primary, accent, light } = kit.palette;
193
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
194
- return {
195
- [`${BRAND_VAR_PREFIX}primary`]: primary,
196
- [`${BRAND_VAR_PREFIX}accent`]: accent,
197
- [`${BRAND_VAR_PREFIX}light`]: light,
198
- [`${BRAND_VAR_PREFIX}dark`]: dark,
199
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
200
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
201
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
202
- };
203
- }
204
- function parseBrandKit(raw) {
205
- if (!raw) return null;
206
- try {
207
- const parsed = JSON.parse(raw);
208
- const p = parsed?.palette;
209
- const f = parsed?.fonts;
210
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
211
- return null;
212
- }
213
- return {
214
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
215
- fonts: { heading: f.heading, body: f.body }
216
- };
217
- } catch {
218
- return null;
219
- }
220
- }
221
- function familyOf(stack) {
222
- const first = stack.split(",")[0]?.trim() ?? "";
223
- return first.replace(/^['"]|['"]$/g, "");
224
- }
225
- function loadBrandFonts(families) {
226
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
227
- if (unique.length === 0) return;
228
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
229
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
230
- let link = document.getElementById(BRAND_FONT_LINK_ID);
231
- if (!link) {
232
- link = document.createElement("link");
233
- link.id = BRAND_FONT_LINK_ID;
234
- link.rel = "stylesheet";
235
- document.head.appendChild(link);
236
- }
237
- if (link.href !== href) link.href = href;
238
- }
239
- function applyBrandToDom(kit) {
240
- const root = document.documentElement;
241
- if (!kit) {
242
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
243
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
244
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
245
- return;
246
- }
247
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
248
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
249
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
250
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
251
- }
252
-
253
- // src/lib/section-styles.ts
254
- var STYLE_STORE_KEY = "__ohw_styles";
255
- var STYLE_SHEET_ID = "ohw-section-styles";
256
- function parseStyleStore(raw) {
257
- if (!raw) return null;
258
- try {
259
- const parsed = JSON.parse(raw);
260
- if (parsed?.v !== 1) return null;
261
- return {
262
- v: 1,
263
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
264
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
265
- };
266
- } catch {
267
- return null;
268
- }
269
- }
270
- var BG_VALUES = {
271
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
272
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
273
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
274
- };
275
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
276
- function styleSheetCss() {
277
- const rules = [];
278
- for (const [tone, value] of Object.entries(BG_VALUES)) {
279
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
280
- }
281
- rules.push(
282
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
283
- );
284
- rules.push(
285
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
286
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
287
- );
288
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
289
- rules.push(
290
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
291
- );
292
- }
293
- rules.push(
294
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
295
- );
296
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
297
- rules.push(
298
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
299
- );
300
- }
301
- const pad = { tight: 40, balanced: 64, airy: 96 };
302
- for (const [spacing, px] of Object.entries(pad)) {
303
- rules.push(
304
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
305
- );
306
- }
307
- return rules.join("\n");
308
- }
309
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
310
- function loadStyleFonts(families) {
311
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
312
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
313
- if (unique.length === 0) {
314
- existing?.remove();
315
- return;
316
- }
317
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
318
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
319
- let link = existing;
320
- if (!link) {
321
- link = document.createElement("link");
322
- link.id = STYLE_FONT_LINK_ID;
323
- link.rel = "stylesheet";
324
- document.head.appendChild(link);
325
- }
326
- if (link.href !== href) link.href = href;
327
- }
328
- var SECTION_ATTRS = {
329
- sectionBackground: "data-ohw-style-bg",
330
- textDistribution: "data-ohw-style-distribution",
331
- headlineScale: "data-ohw-style-headline",
332
- imageAspect: "data-ohw-style-aspect",
333
- spacing: "data-ohw-style-spacing"
334
- };
335
- var NODE_WROTE_ATTR = "data-ohw-style-node";
336
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
337
- function saveInline(el, prop) {
338
- const attr = `data-ohw-style-prev-${prop}`;
339
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
340
- }
341
- function restoreInline(el, prop) {
342
- const attr = `data-ohw-style-prev-${prop}`;
343
- if (!el.hasAttribute(attr)) return;
344
- const prev = el.getAttribute(attr) ?? "";
345
- if (prev) el.style.setProperty(prop, prev);
346
- else el.style.removeProperty(prop);
347
- el.removeAttribute(attr);
348
- }
349
- function ensureStyleSheet() {
350
- let el = document.getElementById(STYLE_SHEET_ID);
351
- if (!el) {
352
- el = document.createElement("style");
353
- el.id = STYLE_SHEET_ID;
354
- document.head.appendChild(el);
355
- }
356
- const css = styleSheetCss();
357
- if (el.textContent !== css) el.textContent = css;
358
- }
359
- function clearSectionAttrs(root) {
360
- for (const attr of Object.values(SECTION_ATTRS)) {
361
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
362
- }
363
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
364
- restoreInline(el, "background");
365
- el.removeAttribute("data-ohw-style-bgcolor");
366
- }
367
- }
368
- function clearNodeProps(root) {
369
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
370
- const h = el;
371
- for (const prop of NODE_PROPS) restoreInline(h, prop);
372
- h.removeAttribute(NODE_WROTE_ATTR);
373
- }
374
- }
375
- function buttonSurfaceOf(el) {
376
- return el.closest("a, button") ?? el;
377
- }
378
- function applyStylesToDom(store) {
379
- ensureStyleSheet();
380
- clearSectionAttrs(document);
381
- clearNodeProps(document);
382
- loadStyleFonts(
383
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
384
- );
385
- if (!store) return;
386
- for (const [sectionId, override] of Object.entries(store.sections)) {
387
- const sections = document.querySelectorAll(
388
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
389
- );
390
- for (const section of Array.from(sections)) {
391
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
392
- const value = override[prop];
393
- if (value === void 0) continue;
394
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
395
- section.setAttribute(attr, String(value).replace(":", "-"));
396
- }
397
- if (override.sectionBackgroundColor !== void 0) {
398
- saveInline(section, "background");
399
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
400
- section.setAttribute("data-ohw-style-bgcolor", "");
401
- }
402
- }
403
- }
404
- for (const [key, override] of Object.entries(store.nodes)) {
405
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
406
- for (const el of Array.from(nodes)) {
407
- if (override.color !== void 0) {
408
- saveInline(el, "color");
409
- el.style.setProperty("color", override.color, "important");
410
- el.setAttribute(NODE_WROTE_ATTR, "");
411
- }
412
- if (override.fontFamily !== void 0) {
413
- saveInline(el, "font-family");
414
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
415
- el.setAttribute(NODE_WROTE_ATTR, "");
416
- }
417
- if (override.fontSize !== void 0) {
418
- saveInline(el, "font-size");
419
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
420
- el.setAttribute(NODE_WROTE_ATTR, "");
421
- }
422
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
423
- const surface = buttonSurfaceOf(el);
424
- if (override.buttonBackground !== void 0) {
425
- saveInline(surface, "background");
426
- surface.style.setProperty("background", override.buttonBackground, "important");
427
- }
428
- if (override.buttonText !== void 0) {
429
- saveInline(surface, "color");
430
- surface.style.setProperty("color", override.buttonText, "important");
431
- }
432
- surface.setAttribute(NODE_WROTE_ATTR, "");
433
- }
434
- }
435
- }
436
- }
437
-
438
121
  // src/ui/ai-tree/aiSectionsManager.tsx
439
122
  import { flushSync } from "react-dom";
440
123
  import { createRoot } from "react-dom/client";
@@ -449,8 +132,7 @@ function lucideByName(name) {
449
132
  }
450
133
  var typeStyle = (spec, font) => ({
451
134
  fontFamily: font,
452
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
453
- fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
135
+ fontSize: spec.size,
454
136
  lineHeight: spec.line,
455
137
  fontWeight: spec.weight
456
138
  });
@@ -465,36 +147,6 @@ var FEATURE_LINE_CSS = [
465
147
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
466
148
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
467
149
  ].join("");
468
- function hexLuminance(color) {
469
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
470
- if (!m) return null;
471
- const [r2, g, b] = [0, 2, 4].map((i) => {
472
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
473
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
474
- });
475
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
476
- }
477
- function hexContrast(a, b) {
478
- const la = hexLuminance(a);
479
- const lb = hexLuminance(b);
480
- if (la === null || lb === null) return null;
481
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
482
- return (hi + 0.05) / (lo + 0.05);
483
- }
484
- function accentBandContext(brand) {
485
- const p = brand.palette;
486
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
487
- if (lightWins) {
488
- return {
489
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
490
- buttonLabel: p.primary
491
- };
492
- }
493
- return {
494
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
495
- buttonLabel: p.light
496
- };
497
- }
498
150
  function textAttrs(ctx, path) {
499
151
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
500
152
  }
@@ -507,8 +159,6 @@ var AI_RESPONSIVE_CSS = [
507
159
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
508
160
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
509
161
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
510
- " [data-ai-responsive] { overflow-x: hidden; }",
511
- " [data-ai-responsive] img { max-width: 100%; }",
512
162
  "}"
513
163
  ].join("\n");
514
164
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -586,7 +236,7 @@ function ButtonEl({
586
236
  }) {
587
237
  const secondary = slots.variant === "secondary";
588
238
  const href = str(slots.href);
589
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
239
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
590
240
  return /* @__PURE__ */ jsx(
591
241
  "a",
592
242
  {
@@ -602,7 +252,7 @@ function ButtonEl({
602
252
  textDecoration: "none",
603
253
  cursor: "pointer",
604
254
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
605
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
255
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
606
256
  },
607
257
  children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
608
258
  }
@@ -1504,14 +1154,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1504
1154
  return null;
1505
1155
  }
1506
1156
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1507
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1508
- const blockBrand = band?.brand ?? resolvedBrand;
1509
1157
  const ctx = {
1510
- brand: blockBrand,
1158
+ brand: resolvedBrand,
1511
1159
  resolveMedia: resolveMedia ?? (() => null),
1512
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1513
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1514
- ...band ? { buttonLabel: band.buttonLabel } : {}
1160
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1161
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1515
1162
  };
1516
1163
  const settings = tree.settings ?? {};
1517
1164
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1519,20 +1166,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1519
1166
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1520
1167
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1521
1168
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1522
- const toneBackground = (() => {
1523
- const { dark, primary, light } = resolvedBrand.palette;
1524
- switch (settings.sectionBackground) {
1525
- case "surface":
1526
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1527
- case "accent":
1528
- return primary;
1529
- case "accent-soft":
1530
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1531
- default:
1532
- return void 0;
1533
- }
1534
- })();
1535
- const distributed = !isOverlay && settings.textDistribution;
1536
1169
  return /* @__PURE__ */ jsxs(
1537
1170
  "section",
1538
1171
  {
@@ -1542,11 +1175,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1542
1175
  style: {
1543
1176
  position: "relative",
1544
1177
  padding: `${pad}px 0`,
1545
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1178
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1546
1179
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1547
1180
  backgroundSize: "cover",
1548
- backgroundPosition: "center",
1549
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1181
+ backgroundPosition: "center"
1550
1182
  },
1551
1183
  children: [
1552
1184
  /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
@@ -1570,24 +1202,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1570
1202
  display: "grid",
1571
1203
  gridTemplateColumns: "repeat(12, 1fr)",
1572
1204
  gap: AI_TREE_TOKENS.spacing6,
1573
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1205
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1574
1206
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1575
1207
  },
1576
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
1577
- "div",
1578
- {
1579
- "data-ai-cell": "",
1580
- style: {
1581
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1582
- minWidth: 0,
1583
- // space-between: each column becomes a flex column whose content spreads over
1584
- // the full row height instead of clumping at the top.
1585
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1586
- },
1587
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1588
- },
1589
- b
1590
- ))
1208
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1591
1209
  },
1592
1210
  r2
1593
1211
  ))
@@ -1603,36 +1221,17 @@ import { jsx as jsx2 } from "react/jsx-runtime";
1603
1221
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1604
1222
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1605
1223
  var REMOVED_ATTR = "data-ohw-ai-removed";
1606
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1607
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1608
- function readRootVar(name) {
1609
- if (typeof document === "undefined") return "";
1610
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1611
- }
1612
- function deriveBrandOverride() {
1613
- const dark = readRootVar("--ohw-brand-dark");
1614
- const primary = readRootVar("--ohw-brand-primary");
1615
- const light = readRootVar("--ohw-brand-light");
1616
- if (!dark || !primary || !light) return null;
1617
- const accent = readRootVar("--ohw-brand-accent");
1618
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1619
- const body = readRootVar("--font-body");
1620
- return {
1621
- palette: { dark, primary, accent: accent || dark, light },
1622
- fonts: {
1623
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1624
- body: body || AI_DEFAULT_BRAND.fonts.body
1625
- }
1626
- };
1627
- }
1628
1224
  function deriveTemplateBrand() {
1629
- const dark = readRootVar("--color-dark");
1630
- const primary = readRootVar("--color-primary");
1631
- const light = readRootVar("--color-light");
1225
+ if (typeof document === "undefined") return null;
1226
+ const cs = getComputedStyle(document.documentElement);
1227
+ const read = (name) => cs.getPropertyValue(name).trim();
1228
+ const dark = read("--color-dark");
1229
+ const primary = read("--color-primary");
1230
+ const light = read("--color-light");
1632
1231
  if (!dark || !primary || !light) return null;
1633
- const accent = readRootVar("--color-accent");
1634
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1635
- const body = readRootVar("--font-body");
1232
+ const accent = read("--color-accent");
1233
+ const heading = read("--font-heading") || read("--font-display");
1234
+ const body = read("--font-body");
1636
1235
  return {
1637
1236
  palette: { dark, primary, accent: accent || dark, light },
1638
1237
  fonts: {
@@ -1704,24 +1303,6 @@ function syncRemovedSections(state) {
1704
1303
  }
1705
1304
  }
1706
1305
  }
1707
- function syncTemplateHidden(state, pageHasSections) {
1708
- const hide = state.hideTemplate === true && pageHasSections;
1709
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1710
- if (!hide) {
1711
- el.style.removeProperty("display");
1712
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1713
- }
1714
- }
1715
- if (!hide) return;
1716
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1717
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1718
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1719
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1720
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1721
- el.style.display = "none";
1722
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1723
- }
1724
- }
1725
1306
  function syncReplacedOriginals(state) {
1726
1307
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1727
1308
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1742,12 +1323,8 @@ function syncReplacedOriginals(state) {
1742
1323
  }
1743
1324
  function applyAiSectionsToDom(state, options) {
1744
1325
  if (typeof document === "undefined") return;
1745
- const brandOverride = deriveBrandOverride();
1746
1326
  const templateBrand = deriveTemplateBrand();
1747
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1748
- const pagePath = window.location.pathname;
1749
- const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
1750
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1327
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1751
1328
  for (const [id, section] of mounted) {
1752
1329
  if (!activeIds.has(id)) {
1753
1330
  section.root.unmount();
@@ -1755,8 +1332,8 @@ function applyAiSectionsToDom(state, options) {
1755
1332
  mounted.delete(id);
1756
1333
  }
1757
1334
  }
1758
- for (const entry of pageSections) {
1759
- const serialized = JSON.stringify(entry) + brandKey;
1335
+ for (const entry of state.sections) {
1336
+ const serialized = JSON.stringify(entry);
1760
1337
  const existing = mounted.get(entry.id);
1761
1338
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1762
1339
  continue;
@@ -1770,7 +1347,6 @@ function applyAiSectionsToDom(state, options) {
1770
1347
  mounted.delete(entry.id);
1771
1348
  }
1772
1349
  container.setAttribute("data-ohw-section", entry.id);
1773
- container.setAttribute("data-ohw-instance", entry.id);
1774
1350
  container.setAttribute("data-ohw-section-label", entry.label);
1775
1351
  placeContainer(container, entry);
1776
1352
  const root = mounted.get(entry.id)?.root ?? createRoot(container);
@@ -1781,7 +1357,7 @@ function applyAiSectionsToDom(state, options) {
1781
1357
  AiTreeRenderer,
1782
1358
  {
1783
1359
  tree: entry.tree,
1784
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1360
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1785
1361
  resolveMedia,
1786
1362
  editKeyPrefix: `ai.${entry.id}`
1787
1363
  }
@@ -1792,7 +1368,6 @@ function applyAiSectionsToDom(state, options) {
1792
1368
  }
1793
1369
  syncReplacedOriginals(state);
1794
1370
  syncRemovedSections(state);
1795
- syncTemplateHidden(state, pageSections.length > 0);
1796
1371
  }
1797
1372
 
1798
1373
  // src/useLinkHrefGuardian.ts
@@ -2399,7 +1974,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2399
1974
  const autoId = useId();
2400
1975
  const insertAfter = insertAfterProp ?? autoId;
2401
1976
  const [schedule, setSchedule] = useState2(null);
2402
- const [loading, setLoading] = useState2(initialScheduleId !== null);
1977
+ const [loading, setLoading] = useState2(true);
2403
1978
  const [inEditor, setInEditor] = useState2(false);
2404
1979
  const [isHovered, setIsHovered] = useState2(false);
2405
1980
  const [modalState, setModalState] = useState2(null);
@@ -2573,10 +2148,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2573
2148
  "*"
2574
2149
  );
2575
2150
  };
2151
+ if (!inEditor && !loading && !schedule) return null;
2576
2152
  const sectionId = `scheduling-${insertAfter}`;
2577
- if (!inEditor && !loading && !schedule) {
2578
- return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2579
- }
2580
2153
  return /* @__PURE__ */ jsxs3(
2581
2154
  "section",
2582
2155
  {
@@ -7484,17 +7057,13 @@ function MediaOverlay({
7484
7057
  hover,
7485
7058
  isUploading,
7486
7059
  fadingOut = false,
7487
- selected = false,
7488
- hovered = false,
7489
7060
  onFadeOutComplete,
7490
7061
  onReplace,
7491
- onSelect,
7492
7062
  onVideoSettingsChange
7493
7063
  }) {
7494
7064
  const { rect } = hover;
7495
7065
  const skeletonRef = React7.useRef(null);
7496
7066
  const isVideo = hover.elementType === "video";
7497
- const showChrome = !selected || hovered;
7498
7067
  const autoplay = hover.videoAutoplay ?? true;
7499
7068
  const muted = hover.videoMuted ?? true;
7500
7069
  const box = {
@@ -7529,7 +7098,7 @@ function MediaOverlay({
7529
7098
  }
7530
7099
  );
7531
7100
  }
7532
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ jsxs7(
7101
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
7533
7102
  "div",
7534
7103
  {
7535
7104
  "data-ohw-bridge": "",
@@ -7599,13 +7168,11 @@ function MediaOverlay({
7599
7168
  // in-document, pointer-events does it natively. The button below opts back in, so
7600
7169
  // Replace still works.
7601
7170
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7602
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7603
- // than hovered. Hover keeps the existing tinted preview.
7604
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7605
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7171
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7172
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7606
7173
  },
7607
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7608
- children: showChrome && /* @__PURE__ */ jsxs7(
7174
+ onClick: () => onReplace(hover.key),
7175
+ children: /* @__PURE__ */ jsxs7(
7609
7176
  Button,
7610
7177
  {
7611
7178
  "data-ohw-media-overlay": "",
@@ -7694,9 +7261,6 @@ import { Check, X } from "lucide-react";
7694
7261
 
7695
7262
  // src/lib/sections.ts
7696
7263
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7697
- function isChromeSection(el) {
7698
- return el.matches("header, nav, footer, aside");
7699
- }
7700
7264
  function titleCaseSectionId(id) {
7701
7265
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7702
7266
  }
@@ -7707,8 +7271,6 @@ function parseSectionsFromRoot(root) {
7707
7271
  const id = el.getAttribute("data-ohw-section") ?? "";
7708
7272
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7709
7273
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7710
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7711
- continue;
7712
7274
  seen.add(id);
7713
7275
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7714
7276
  sections.push({ id, label });
@@ -7726,12 +7288,8 @@ function parseSectionsFromHtml(html) {
7726
7288
 
7727
7289
  // src/ui/ai-section/AiSectionOverlay.tsx
7728
7290
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
7729
- function findSectionElement(instanceId) {
7730
- const escaped = CSS.escape(instanceId);
7731
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7732
- }
7733
- function readRect(instanceId) {
7734
- const el = findSectionElement(instanceId);
7291
+ function readRect(sectionId) {
7292
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7735
7293
  if (!el) return null;
7736
7294
  const r2 = el.getBoundingClientRect();
7737
7295
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7754,7 +7312,7 @@ function useLiveSectionRect(sectionId) {
7754
7312
  const opts = { capture: true, passive: true };
7755
7313
  window.addEventListener("scroll", update, opts);
7756
7314
  window.addEventListener("resize", update);
7757
- const el = findSectionElement(sectionId);
7315
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7758
7316
  const ro = el ? new ResizeObserver(update) : null;
7759
7317
  if (el && ro) ro.observe(el);
7760
7318
  const interval = setInterval(update, 500);
@@ -7767,14 +7325,6 @@ function useLiveSectionRect(sectionId) {
7767
7325
  }, [sectionId]);
7768
7326
  return rect;
7769
7327
  }
7770
- function computeSectionBoundaryFlags(instanceId) {
7771
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7772
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7773
- );
7774
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7775
- if (index === -1) return { isFirst: true, isLast: true };
7776
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7777
- }
7778
7328
  var PRIMARY2 = "#0885FE";
7779
7329
  function edgeAwareRadius(rect) {
7780
7330
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7848,7 +7398,6 @@ function AiSectionOverlay({
7848
7398
  }) {
7849
7399
  const [selectedId, setSelectedId] = useState4(null);
7850
7400
  const [reviewId, setReviewId] = useState4(null);
7851
- const [reviewButtonsHidden, setReviewButtonsHidden] = useState4(false);
7852
7401
  const reviewIdRef = useRef4(null);
7853
7402
  reviewIdRef.current = reviewId;
7854
7403
  const selectedIdRef = useRef4(null);
@@ -7857,7 +7406,7 @@ function AiSectionOverlay({
7857
7406
  (el) => {
7858
7407
  postToParent2({
7859
7408
  type: "ow:section-selected",
7860
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7409
+ sectionId: el?.dataset.ohwSection ?? null,
7861
7410
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7862
7411
  });
7863
7412
  },
@@ -7866,7 +7415,7 @@ function AiSectionOverlay({
7866
7415
  const selectFromElement = useCallback2(
7867
7416
  (el, options) => {
7868
7417
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7869
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7418
+ const id = sectionEl?.dataset.ohwSection ?? null;
7870
7419
  if (id === selectedIdRef.current) return;
7871
7420
  setSelectedId(id);
7872
7421
  if (options?.report !== false) report(sectionEl);
@@ -7907,10 +7456,9 @@ function AiSectionOverlay({
7907
7456
  }
7908
7457
  const found = readRect(sectionId) != null;
7909
7458
  setReviewId(found ? sectionId : null);
7910
- setReviewButtonsHidden(e.data.hideButtons === true);
7911
7459
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7912
7460
  if (found) {
7913
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7461
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7914
7462
  }
7915
7463
  }
7916
7464
  };
@@ -7929,7 +7477,7 @@ function AiSectionOverlay({
7929
7477
  return;
7930
7478
  }
7931
7479
  const sec = t.closest("[data-ohw-section]");
7932
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7480
+ setHoveredId(sec?.dataset.ohwSection ?? null);
7933
7481
  };
7934
7482
  const onLeave = () => setHoveredId(null);
7935
7483
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -7961,30 +7509,9 @@ function AiSectionOverlay({
7961
7509
  },
7962
7510
  [postToParent2]
7963
7511
  );
7964
- const activeSelectionId = reviewId ? null : selectedId;
7965
- const selectionRect = useLiveSectionRect(activeSelectionId);
7512
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
7966
7513
  const reviewRect = useLiveSectionRect(reviewId);
7967
7514
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
7968
- useEffect4(() => {
7969
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
7970
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
7971
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
7972
- return;
7973
- }
7974
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
7975
- postToParent2({
7976
- type: "ow:section-rect",
7977
- instanceId: activeSelectionId,
7978
- rect: {
7979
- top: selectionRect.top + window.scrollY,
7980
- left: selectionRect.left + window.scrollX,
7981
- width: selectionRect.width,
7982
- height: selectionRect.height
7983
- },
7984
- isFirst,
7985
- isLast
7986
- });
7987
- }, [activeSelectionId, selectionRect, postToParent2]);
7988
7515
  return /* @__PURE__ */ jsxs9(Fragment5, { children: [
7989
7516
  hoverRect && /* @__PURE__ */ jsx17(
7990
7517
  "div",
@@ -8035,16 +7562,13 @@ function AiSectionOverlay({
8035
7562
  border: `2px solid ${PRIMARY2}`,
8036
7563
  borderRadius: edgeAwareRadius(reviewRect),
8037
7564
  zIndex: 2147483200,
8038
- // The veil itself: swallows clicks so the section stays locked until decided. This
8039
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8040
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8041
- // Accept/Discard resolves to the media beneath and opens the file picker.
7565
+ // The veil itself: swallows clicks so the section stays locked until decided.
8042
7566
  background: "rgba(8, 133, 254, 0.04)",
8043
7567
  pointerEvents: "auto",
8044
7568
  cursor: "default"
8045
7569
  },
8046
7570
  onClick: (e) => e.stopPropagation(),
8047
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
7571
+ children: /* @__PURE__ */ jsxs9(
8048
7572
  "div",
8049
7573
  {
8050
7574
  style: {
@@ -8069,58 +7593,6 @@ function AiSectionOverlay({
8069
7593
 
8070
7594
  // src/lib/section-instances.ts
8071
7595
  var SECTION_ORDER_KEY = "__ohw_section_order";
8072
- function topLevelSections() {
8073
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8074
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8075
- );
8076
- }
8077
- function instanceIdOf(el) {
8078
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8079
- }
8080
- function planSectionMove(instanceId, targetIndex, currentPath) {
8081
- const sections = topLevelSections();
8082
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8083
- if (index === -1) return null;
8084
- const dragged = sections[index];
8085
- const others = sections.filter((_, i) => i !== index);
8086
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8087
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8088
- return reordered.map((el, order) => ({
8089
- instanceId: instanceIdOf(el),
8090
- type: el.getAttribute("data-ohw-section") ?? "",
8091
- order,
8092
- pagePath: currentPath
8093
- }));
8094
- }
8095
- function moveSectionInstance(instanceId, direction, currentPath) {
8096
- const sections = topLevelSections();
8097
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8098
- if (index === -1) return null;
8099
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8100
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8101
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8102
- if (!entries) return null;
8103
- applyPersistedOrder(entries);
8104
- return entries;
8105
- }
8106
- function applyPersistedOrder(entries) {
8107
- if (entries.length === 0) return;
8108
- const sections = topLevelSections();
8109
- if (sections.length === 0) return;
8110
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8111
- const ordered = [...sections].sort((a, b) => {
8112
- const aOrder = orderIndex.get(instanceIdOf(a));
8113
- const bOrder = orderIndex.get(instanceIdOf(b));
8114
- if (aOrder === void 0 && bOrder === void 0) return 0;
8115
- if (aOrder === void 0) return 1;
8116
- if (bOrder === void 0) return -1;
8117
- return aOrder - bOrder;
8118
- });
8119
- const parent = sections[0].parentElement;
8120
- if (!parent) return;
8121
- const anchor = sections[sections.length - 1].nextSibling;
8122
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8123
- }
8124
7596
  function getPageSectionOrderEntries(raw, currentPath) {
8125
7597
  if (!raw) return [];
8126
7598
  try {
@@ -8158,7 +7630,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8158
7630
  rekeySectionSubtree(clone, entry.instanceId);
8159
7631
  original.insertAdjacentElement("afterend", clone);
8160
7632
  }
8161
- applyPersistedOrder(entries);
8162
7633
  }
8163
7634
 
8164
7635
  // src/OhhwellsBridge.tsx
@@ -10783,8 +10254,7 @@ function findSocialsRow(el) {
10783
10254
  }
10784
10255
  function isSocialsRow(el) {
10785
10256
  const anchors = Array.from(el.querySelectorAll("a"));
10786
- if (!anchors.length || !anchors.some((anchor) => isSocialItem(anchor))) return false;
10787
- return findSocialsRow(anchors[0]) === el;
10257
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
10788
10258
  }
10789
10259
  var MAX_SOCIAL_ITEMS_PER_ROW = 7;
10790
10260
  function canAddSocialItem(row) {
@@ -10822,7 +10292,6 @@ function markSocialsRows(root = document) {
10822
10292
  });
10823
10293
  listSocialsRows(root).forEach((row) => {
10824
10294
  row.setAttribute(SOCIALS_ROW_ATTR, "");
10825
- allowRowToWrap(row);
10826
10295
  const items = listSocialItems(row);
10827
10296
  const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
10828
10297
  if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
@@ -11117,29 +10586,7 @@ function applySocialsDisplayToRow(row, display) {
11117
10586
  const icon = item.querySelector(ICON_SELECTOR);
11118
10587
  if (label) label.style.display = display.text ? "" : "none";
11119
10588
  if (icon) icon.style.display = display.icon ? "" : "none";
11120
- layOutIconAndLabel(item, Boolean(display.text && display.icon));
11121
10589
  });
11122
- allowRowToWrap(row);
11123
- }
11124
- function layOutIconAndLabel(item, on) {
11125
- const hasBoth = Boolean(item.querySelector(ICON_SELECTOR)) && Boolean(socialLabelElement(item));
11126
- if (!hasBoth) {
11127
- item.style.display = "";
11128
- item.style.alignItems = "";
11129
- item.style.gap = "";
11130
- item.style.whiteSpace = "";
11131
- item.style.flex = "";
11132
- return;
11133
- }
11134
- item.style.display = on ? "inline-flex" : "";
11135
- item.style.alignItems = on ? "center" : "";
11136
- item.style.gap = on ? "8px" : "";
11137
- item.style.whiteSpace = on ? "nowrap" : "";
11138
- item.style.flex = on ? "0 0 auto" : "";
11139
- }
11140
- function allowRowToWrap(row) {
11141
- const display = row.ownerDocument.defaultView?.getComputedStyle(row).display ?? "";
11142
- if (display === "flex" || display === "inline-flex") row.style.flexWrap = "wrap";
11143
10590
  }
11144
10591
  function applySocialsDisplayFromContent(content, root = document) {
11145
10592
  const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
@@ -12349,7 +11796,6 @@ function readLogoSizeState(content, placement) {
12349
11796
  function getLogoElement(el) {
12350
11797
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12351
11798
  if (marked) return marked;
12352
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12353
11799
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12354
11800
  if (!root) return null;
12355
11801
  const anchor = el.closest("a");
@@ -13229,449 +12675,122 @@ function useNavItemDrag({
13229
12675
  };
13230
12676
  }
13231
12677
 
13232
- // src/useSectionDrag.ts
13233
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef9, useState as useState10 } from "react";
12678
+ // src/ui/footer-container-chrome.tsx
12679
+ import { Plus as Plus2 } from "lucide-react";
12680
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
12681
+ function FooterContainerChrome({
12682
+ rect,
12683
+ onAdd,
12684
+ addDisabled = false
12685
+ }) {
12686
+ const chromeGap = 6;
12687
+ const buttonMargin = 7;
12688
+ return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
12689
+ "div",
12690
+ {
12691
+ "data-ohw-footer-container-chrome": "",
12692
+ "data-ohw-bridge": "",
12693
+ className: "pointer-events-none fixed z-[2147483647]",
12694
+ style: {
12695
+ top: rect.top - chromeGap,
12696
+ left: rect.left - chromeGap,
12697
+ width: rect.width + chromeGap * 2,
12698
+ height: rect.height + chromeGap * 2
12699
+ },
12700
+ children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
12701
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
12702
+ "button",
12703
+ {
12704
+ type: "button",
12705
+ "data-ohw-footer-add-button": "",
12706
+ disabled: addDisabled,
12707
+ className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80 disabled:pointer-events-none disabled:opacity-40",
12708
+ style: { top: chromeGap - buttonMargin },
12709
+ "aria-label": "Add item",
12710
+ onMouseDown: (e) => {
12711
+ e.preventDefault();
12712
+ e.stopPropagation();
12713
+ },
12714
+ onClick: (e) => {
12715
+ e.preventDefault();
12716
+ e.stopPropagation();
12717
+ if (addDisabled) return;
12718
+ onAdd();
12719
+ },
12720
+ children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12721
+ }
12722
+ ) }),
12723
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12724
+ ] })
12725
+ }
12726
+ ) });
12727
+ }
13234
12728
 
13235
- // src/lib/section-dnd.ts
13236
- function isFooterSection(el) {
13237
- return el.dataset.ohwSection === "footer";
12729
+ // src/lib/carousel.ts
12730
+ import { useEffect as useEffect11, useState as useState10 } from "react";
12731
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12732
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12733
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12734
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12735
+ function listCarouselKeys() {
12736
+ const keys = /* @__PURE__ */ new Set();
12737
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12738
+ const key = el.getAttribute("data-ohw-key");
12739
+ if (key) keys.add(key);
12740
+ });
12741
+ return [...keys];
13238
12742
  }
13239
- function buildSectionDropSlots(draggedInstanceId) {
13240
- const sections = topLevelSections().filter(
13241
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12743
+ function containersForKey(key) {
12744
+ return Array.from(
12745
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13242
12746
  );
13243
- const slots = [];
13244
- if (sections.length === 0) return slots;
13245
- const left = 0;
13246
- const width = document.documentElement.clientWidth;
13247
- for (let i = 0; i <= sections.length; i++) {
13248
- let y;
13249
- if (i === 0) {
13250
- y = sections[0].getBoundingClientRect().top;
13251
- } else if (i === sections.length) {
13252
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13253
- } else {
13254
- const prev = sections[i - 1].getBoundingClientRect();
13255
- const next = sections[i].getBoundingClientRect();
13256
- y = (prev.bottom + next.top) / 2;
13257
- }
13258
- slots.push({ insertIndex: i, y, left, width });
12747
+ }
12748
+ function isCarouselKey(key) {
12749
+ return containersForKey(key).length > 0;
12750
+ }
12751
+ function parseSlides(raw) {
12752
+ if (!raw) return [];
12753
+ try {
12754
+ const parsed = JSON.parse(raw);
12755
+ if (!Array.isArray(parsed)) return [];
12756
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12757
+ } catch {
12758
+ return [];
13259
12759
  }
13260
- return slots;
13261
12760
  }
13262
- function hitTestSectionDropSlot(y, slots) {
13263
- let best = null;
13264
- for (const slot of slots) {
13265
- const dist = Math.abs(y - slot.y);
13266
- if (!best || dist < best.dist) best = { slot, dist };
12761
+ function readCarouselValue(key) {
12762
+ const container = containersForKey(key)[0];
12763
+ if (!container) return [];
12764
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
12765
+ if (fromAttr.length > 0) return fromAttr;
12766
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
12767
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
12768
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
12769
+ });
12770
+ }
12771
+ function slideIndex(el) {
12772
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
12773
+ const n = raw ? parseInt(raw, 10) : NaN;
12774
+ return Number.isFinite(n) ? n : 0;
12775
+ }
12776
+ function applyCarouselValue(key, slides) {
12777
+ const value = JSON.stringify(slides);
12778
+ for (const container of containersForKey(key)) {
12779
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
12780
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
12781
+ container.dispatchEvent(
12782
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
12783
+ );
13267
12784
  }
13268
- return best?.slot ?? null;
13269
12785
  }
13270
-
13271
- // src/useSectionDrag.ts
13272
- var PRESS_THRESHOLD = 10;
13273
- var EDGE_ZONE = 60;
13274
- var MAX_AUTO_SCROLL_SPEED = 18;
13275
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13276
- "[data-ohw-toolbar]",
13277
- "[data-ohw-edit-chrome]",
13278
- "[data-ohw-item-interaction]",
13279
- "[data-ohw-drag-handle-container]",
13280
- '[data-slot="drag-handle"]',
13281
- "[data-ohw-item-toolbar-anchor]",
13282
- "[data-ohw-item-drag-surface]",
13283
- "[data-ohw-more-menu]",
13284
- '[data-slot="dropdown-menu-content"]',
13285
- '[data-slot="dropdown-menu-item"]',
13286
- "[data-ohw-state-toggle]",
13287
- "[data-ohw-max-badge]",
13288
- "[data-ohw-floating-panel]",
13289
- "[data-ohw-section-picker]",
13290
- "[data-ohw-link-popover-root]",
13291
- "[data-ohw-link-modal-root]",
13292
- "[data-ohw-link-page-dropdown]",
13293
- '[data-slot="popover-content"]',
13294
- '[data-slot="dialog-content"]',
13295
- '[data-slot="dialog-overlay"]',
13296
- "[data-ohw-ai-review]",
13297
- "[data-ohw-editable]",
13298
- "[data-ohw-editable-state]",
13299
- "[contenteditable]",
13300
- "[data-ohw-href-key]",
13301
- "[data-ohw-footer-col]",
13302
- "[data-ohw-social-label]",
13303
- "a",
13304
- "button",
13305
- '[role="button"]',
13306
- '[data-ohw-role="navbar-button"]',
13307
- '[data-ohw-role="button"]',
13308
- "[data-ohw-carousel]",
13309
- "[data-ohw-carousel-value]",
13310
- "[data-ohw-carousel-slide]",
13311
- "[data-ohw-carousel-overlay]",
13312
- "[data-ohw-media-chrome]",
13313
- "[data-ohw-media-overlay]",
13314
- "[data-ohw-media-skeleton]"
13315
- ].join(", ");
13316
- function visibleClip(ps) {
13317
- if (!ps) return null;
13318
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13319
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13320
- return { top, bottom: Math.max(top, bottom) };
13321
- }
13322
- function useSectionDrag({
13323
- isEditMode,
13324
- editContentRef,
13325
- postToParentRef,
13326
- parentScrollRef,
13327
- navDragRef,
13328
- footerDragRef,
13329
- suppressNextClickRef,
13330
- suppressClickUntilRef
13331
- }) {
13332
- const sectionDragRef = useRef9(null);
13333
- const [sectionDropSlots, setSectionDropSlots] = useState10([]);
13334
- const [activeSectionDropIndex, setActiveSectionDropIndex] = useState10(null);
13335
- const [isSectionDragging, setIsSectionDragging] = useState10(false);
13336
- const sectionPointerDragRef = useRef9(null);
13337
- const autoScrollRafRef = useRef9(null);
13338
- const autoScrollDeltaRef = useRef9(0);
13339
- const stopAutoScroll = useCallback7(() => {
13340
- if (autoScrollRafRef.current != null) {
13341
- cancelAnimationFrame(autoScrollRafRef.current);
13342
- autoScrollRafRef.current = null;
13343
- }
13344
- autoScrollDeltaRef.current = 0;
13345
- }, []);
13346
- const tickAutoScroll = useCallback7(() => {
13347
- if (!sectionDragRef.current) {
13348
- stopAutoScroll();
13349
- return;
13350
- }
13351
- if (autoScrollDeltaRef.current !== 0) {
13352
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13353
- }
13354
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13355
- }, [postToParentRef, stopAutoScroll]);
13356
- const updateAutoScroll = useCallback7(
13357
- (clientY) => {
13358
- const clip = visibleClip(parentScrollRef.current);
13359
- let delta = 0;
13360
- if (clip) {
13361
- const distTop = clientY - clip.top;
13362
- const distBottom = clip.bottom - clientY;
13363
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13364
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13365
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13366
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13367
- }
13368
- }
13369
- autoScrollDeltaRef.current = delta;
13370
- if (delta !== 0 && autoScrollRafRef.current == null) {
13371
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13372
- } else if (delta === 0) {
13373
- stopAutoScroll();
13374
- }
13375
- },
13376
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13377
- );
13378
- const clearSectionDragVisuals = useCallback7(() => {
13379
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13380
- sectionDragRef.current = null;
13381
- setSectionDropSlots([]);
13382
- setActiveSectionDropIndex(null);
13383
- setIsSectionDragging(false);
13384
- stopAutoScroll();
13385
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13386
- unlockItemDragInteraction();
13387
- }, [stopAutoScroll]);
13388
- const refreshSectionDragVisuals = useCallback7(
13389
- (session, clientX, clientY) => {
13390
- session.lastClientX = clientX;
13391
- session.lastClientY = clientY;
13392
- const slots = buildSectionDropSlots(session.instanceId);
13393
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13394
- session.activeSlot = activeSlot;
13395
- setSectionDropSlots(slots);
13396
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13397
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13398
- updateAutoScroll(clientY);
13399
- },
13400
- [updateAutoScroll]
13401
- );
13402
- const beginSectionDrag = useCallback7(
13403
- (session) => {
13404
- sectionDragRef.current = session;
13405
- setIsSectionDragging(true);
13406
- lockItemDuringDrag();
13407
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13408
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13409
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13410
- },
13411
- [refreshSectionDragVisuals]
13412
- );
13413
- const commitSectionDrag = useCallback7(() => {
13414
- const session = sectionDragRef.current;
13415
- if (!session) {
13416
- clearSectionDragVisuals();
13417
- return;
13418
- }
13419
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13420
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13421
- if (!entries) {
13422
- clearSectionDragVisuals();
13423
- return;
13424
- }
13425
- const orderJson = JSON.stringify(entries);
13426
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13427
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13428
- applyPersistedOrder(entries);
13429
- clearSectionDragVisuals();
13430
- requestAnimationFrame(() => {
13431
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13432
- applyPersistedOrder(entries);
13433
- }
13434
- requestAnimationFrame(() => {
13435
- window.dispatchEvent(new Event("resize"));
13436
- });
13437
- });
13438
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13439
- const startSectionPressDrag = useCallback7(
13440
- (el, clientX, clientY, pointerId) => {
13441
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13442
- const instanceId = instanceIdOf(el);
13443
- if (!instanceId) return false;
13444
- sectionPointerDragRef.current = {
13445
- el,
13446
- instanceId,
13447
- startX: clientX,
13448
- startY: clientY,
13449
- pointerId,
13450
- started: false
13451
- };
13452
- return true;
13453
- },
13454
- [footerDragRef, navDragRef]
13455
- );
13456
- useEffect11(() => {
13457
- if (!isEditMode) return;
13458
- const onPointerDown = (e) => {
13459
- if (e.button !== 0) return;
13460
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13461
- if (sectionPointerDragRef.current) return;
13462
- const target = e.target;
13463
- if (!(target instanceof HTMLElement)) return;
13464
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13465
- const sectionEl = target.closest("[data-ohw-section]");
13466
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13467
- if (!topLevelSections().includes(sectionEl)) return;
13468
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13469
- };
13470
- const onPointerMove = (e) => {
13471
- const pending = sectionPointerDragRef.current;
13472
- if (!pending) return;
13473
- if (pending.started) {
13474
- e.preventDefault();
13475
- clearTextSelection();
13476
- const session = sectionDragRef.current;
13477
- if (!session) return;
13478
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13479
- return;
13480
- }
13481
- const dx = e.clientX - pending.startX;
13482
- const dy = e.clientY - pending.startY;
13483
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13484
- e.preventDefault();
13485
- pending.started = true;
13486
- armItemPressDrag();
13487
- clearTextSelection();
13488
- try {
13489
- document.body.setPointerCapture(pending.pointerId);
13490
- } catch {
13491
- }
13492
- beginSectionDrag({
13493
- instanceId: pending.instanceId,
13494
- draggedEl: pending.el,
13495
- lastClientX: e.clientX,
13496
- lastClientY: e.clientY,
13497
- activeSlot: null
13498
- });
13499
- };
13500
- const endPointerDrag = (e) => {
13501
- const pending = sectionPointerDragRef.current;
13502
- sectionPointerDragRef.current = null;
13503
- try {
13504
- if (document.body.hasPointerCapture(e.pointerId)) {
13505
- document.body.releasePointerCapture(e.pointerId);
13506
- }
13507
- } catch {
13508
- }
13509
- if (!pending) return;
13510
- if (!pending.started) {
13511
- unlockItemDragInteraction();
13512
- return;
13513
- }
13514
- suppressNextClickRef.current = true;
13515
- suppressClickUntilRef.current = Date.now() + 500;
13516
- commitSectionDrag();
13517
- };
13518
- const onKeyDown = (e) => {
13519
- if (e.key !== "Escape") return;
13520
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13521
- sectionPointerDragRef.current = null;
13522
- clearSectionDragVisuals();
13523
- };
13524
- document.addEventListener("pointerdown", onPointerDown, true);
13525
- document.addEventListener("pointermove", onPointerMove, true);
13526
- document.addEventListener("pointerup", endPointerDrag, true);
13527
- document.addEventListener("pointercancel", endPointerDrag, true);
13528
- document.addEventListener("keydown", onKeyDown, true);
13529
- return () => {
13530
- document.removeEventListener("pointerdown", onPointerDown, true);
13531
- document.removeEventListener("pointermove", onPointerMove, true);
13532
- document.removeEventListener("pointerup", endPointerDrag, true);
13533
- document.removeEventListener("pointercancel", endPointerDrag, true);
13534
- document.removeEventListener("keydown", onKeyDown, true);
13535
- unlockItemDragInteraction();
13536
- stopAutoScroll();
13537
- };
13538
- }, [
13539
- beginSectionDrag,
13540
- clearSectionDragVisuals,
13541
- commitSectionDrag,
13542
- footerDragRef,
13543
- isEditMode,
13544
- navDragRef,
13545
- refreshSectionDragVisuals,
13546
- startSectionPressDrag,
13547
- stopAutoScroll,
13548
- suppressClickUntilRef,
13549
- suppressNextClickRef
13550
- ]);
13551
- return {
13552
- sectionDragRef,
13553
- sectionDropSlots,
13554
- activeSectionDropIndex,
13555
- isSectionDragging
13556
- };
13557
- }
13558
-
13559
- // src/ui/footer-container-chrome.tsx
13560
- import { Plus as Plus2 } from "lucide-react";
13561
- import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
13562
- function FooterContainerChrome({
13563
- rect,
13564
- onAdd,
13565
- addDisabled = false
13566
- }) {
13567
- const chromeGap = 6;
13568
- const buttonMargin = 7;
13569
- return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
13570
- "div",
13571
- {
13572
- "data-ohw-footer-container-chrome": "",
13573
- "data-ohw-bridge": "",
13574
- className: "pointer-events-none fixed z-[2147483647]",
13575
- style: {
13576
- top: rect.top - chromeGap,
13577
- left: rect.left - chromeGap,
13578
- width: rect.width + chromeGap * 2,
13579
- height: rect.height + chromeGap * 2
13580
- },
13581
- children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
13582
- /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
13583
- "button",
13584
- {
13585
- type: "button",
13586
- "data-ohw-footer-add-button": "",
13587
- disabled: addDisabled,
13588
- className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80 disabled:pointer-events-none disabled:opacity-40",
13589
- style: { top: chromeGap - buttonMargin },
13590
- "aria-label": "Add item",
13591
- onMouseDown: (e) => {
13592
- e.preventDefault();
13593
- e.stopPropagation();
13594
- },
13595
- onClick: (e) => {
13596
- e.preventDefault();
13597
- e.stopPropagation();
13598
- if (addDisabled) return;
13599
- onAdd();
13600
- },
13601
- children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13602
- }
13603
- ) }),
13604
- /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13605
- ] })
13606
- }
13607
- ) });
13608
- }
13609
-
13610
- // src/lib/carousel.ts
13611
- import { useEffect as useEffect12, useState as useState11 } from "react";
13612
- var CAROUSEL_ATTR = "data-ohw-carousel";
13613
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13614
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13615
- var CAROUSEL_EVENT = "ohw:carousel-change";
13616
- function listCarouselKeys() {
13617
- const keys = /* @__PURE__ */ new Set();
13618
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13619
- const key = el.getAttribute("data-ohw-key");
13620
- if (key) keys.add(key);
13621
- });
13622
- return [...keys];
13623
- }
13624
- function containersForKey(key) {
13625
- return Array.from(
13626
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13627
- );
13628
- }
13629
- function isCarouselKey(key) {
13630
- return containersForKey(key).length > 0;
13631
- }
13632
- function parseSlides(raw) {
13633
- if (!raw) return [];
13634
- try {
13635
- const parsed = JSON.parse(raw);
13636
- if (!Array.isArray(parsed)) return [];
13637
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13638
- } catch {
13639
- return [];
13640
- }
13641
- }
13642
- function readCarouselValue(key) {
13643
- const container = containersForKey(key)[0];
13644
- if (!container) return [];
13645
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
13646
- if (fromAttr.length > 0) return fromAttr;
13647
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
13648
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
13649
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
13650
- });
13651
- }
13652
- function slideIndex(el) {
13653
- const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
13654
- const n = raw ? parseInt(raw, 10) : NaN;
13655
- return Number.isFinite(n) ? n : 0;
13656
- }
13657
- function applyCarouselValue(key, slides) {
13658
- const value = JSON.stringify(slides);
13659
- for (const container of containersForKey(key)) {
13660
- if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
13661
- container.setAttribute(CAROUSEL_VALUE_ATTR, value);
13662
- container.dispatchEvent(
13663
- new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
13664
- );
13665
- }
13666
- }
13667
- function applyCarouselNode(key, val) {
13668
- if (!isCarouselKey(key)) return false;
13669
- applyCarouselValue(key, parseSlides(val));
13670
- return true;
12786
+ function applyCarouselNode(key, val) {
12787
+ if (!isCarouselKey(key)) return false;
12788
+ applyCarouselValue(key, parseSlides(val));
12789
+ return true;
13671
12790
  }
13672
12791
  function useOhwCarousel(key, initial) {
13673
- const [images, setImages] = useState11(initial);
13674
- useEffect12(() => {
12792
+ const [images, setImages] = useState10(initial);
12793
+ useEffect11(() => {
13675
12794
  const el = document.querySelector(
13676
12795
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13677
12796
  );
@@ -13749,7 +12868,7 @@ function collectEditableNodes(extraContent, root = document) {
13749
12868
  nodes.push({ key, type: "link", text: href });
13750
12869
  }
13751
12870
  if (extraContent) {
13752
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12871
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13753
12872
  const text = extraContent[key];
13754
12873
  if (typeof text === "string" && text.length > 0) {
13755
12874
  nodes.push({ key, type: "meta", text });
@@ -13786,18 +12905,6 @@ function collectEditableNodes(extraContent, root = document) {
13786
12905
  }
13787
12906
  if (extraContent && !isScoped) {
13788
12907
  applyNavFooterDeleteOverrides(byKey, extraContent);
13789
- for (const key of LOGO_IMAGE_KEYS) {
13790
- if (!(key in extraContent)) continue;
13791
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13792
- }
13793
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13794
- if (!(key in extraContent)) continue;
13795
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13796
- }
13797
- for (const key of LOGO_SIZE_KEYS) {
13798
- if (!(key in extraContent)) continue;
13799
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13800
- }
13801
12908
  }
13802
12909
  return Array.from(byKey.values());
13803
12910
  }
@@ -14202,7 +13309,6 @@ function fadeInImageElement(img, onReady) {
14202
13309
  function applyEditableImageSrc(img, url) {
14203
13310
  img.removeAttribute("srcset");
14204
13311
  img.removeAttribute("sizes");
14205
- if (img.loading === "lazy") img.loading = "eager";
14206
13312
  img.src = url;
14207
13313
  }
14208
13314
  function fadeInBgImage(el, url, onReady) {
@@ -14267,10 +13373,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14267
13373
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14268
13374
  };
14269
13375
  }
14270
- function resolveEntryAnchor(entry) {
14271
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14272
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14273
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13376
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13377
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13378
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13379
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13380
+ return { effectiveInsertAfter, insertBefore };
13381
+ }
13382
+ function getSchedulingMountPoint(insertAfter) {
13383
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13384
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13385
+ if (!anchorEl && anchor === "scheduling") {
13386
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13387
+ anchorEl = widgets.at(-1) ?? null;
13388
+ }
13389
+ if (!anchorEl) return null;
13390
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14274
13391
  }
14275
13392
  function schedulingMountDepth(insertAfter) {
14276
13393
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14287,7 +13404,8 @@ function getPageSchedulingEntries(raw) {
14287
13404
  }
14288
13405
  }
14289
13406
  function isSchedulingWidgetMissing(entry) {
14290
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13407
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13408
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14291
13409
  }
14292
13410
  function hasMissingSchedulingWidgets(entries) {
14293
13411
  return entries.some(isSchedulingWidgetMissing);
@@ -14317,17 +13435,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14317
13435
  } catch {
14318
13436
  }
14319
13437
  }
14320
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14321
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14322
- const sectionId = schedulingSectionId(widgetId);
13438
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13439
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13440
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14323
13441
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14324
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14325
- if (!anchorEl) return false;
14326
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13442
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13443
+ if (!mountPoint) return false;
14327
13444
  const container = document.createElement("div");
14328
13445
  container.dataset.ohwSectionContainer = "scheduling";
14329
- if (beforeId) {
14330
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13446
+ if (insertBefore) {
13447
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14331
13448
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14332
13449
  if (!beforePoint) return false;
14333
13450
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14338,25 +13455,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14338
13455
  }
14339
13456
  tail.insertAdjacentElement("afterend", container);
14340
13457
  }
14341
- try {
14342
- const root = createRoot2(container);
14343
- flushSync2(() => {
14344
- root.render(
14345
- /* @__PURE__ */ jsx33(
14346
- SchedulingWidget,
14347
- {
14348
- notifyOnConnect,
14349
- initialScheduleId: scheduleId,
14350
- insertAfter: widgetId
14351
- }
14352
- )
14353
- );
14354
- });
14355
- } catch (err) {
14356
- console.error("[ow:scheduling] render threw", err);
14357
- container.remove();
14358
- return false;
14359
- }
13458
+ const root = createRoot2(container);
13459
+ flushSync2(() => {
13460
+ root.render(
13461
+ /* @__PURE__ */ jsx33(
13462
+ SchedulingWidget,
13463
+ {
13464
+ notifyOnConnect,
13465
+ initialScheduleId: scheduleId,
13466
+ insertAfter: effectiveInsertAfter
13467
+ }
13468
+ )
13469
+ );
13470
+ });
14360
13471
  const tracker = getSectionsTracker();
14361
13472
  let sections = [];
14362
13473
  try {
@@ -14364,12 +13475,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14364
13475
  } catch {
14365
13476
  }
14366
13477
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14367
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13478
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14368
13479
  sections.push({
14369
13480
  type: "scheduling",
14370
- insertAfter: widgetId,
14371
- anchorId,
14372
- beforeId: beforeId ?? null,
13481
+ insertAfter: effectiveInsertAfter,
14373
13482
  pagePath: window.location.pathname,
14374
13483
  ...scheduleId ? { scheduleId } : {}
14375
13484
  });
@@ -14383,8 +13492,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14383
13492
  for (let i = pending.length - 1; i >= 0; i--) {
14384
13493
  const entry = pending[i];
14385
13494
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14386
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14387
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13495
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14388
13496
  pending.splice(i, 1);
14389
13497
  }
14390
13498
  }
@@ -14532,13 +13640,6 @@ function isInsideLinkEditor(target) {
14532
13640
  target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
14533
13641
  );
14534
13642
  }
14535
- function isInsideFloatingPanel(target) {
14536
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14537
- }
14538
- function isPointOverFloatingPanel(clientX, clientY) {
14539
- const el = document.elementFromPoint(clientX, clientY);
14540
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14541
- }
14542
13643
  function getHrefKeyFromElement(el) {
14543
13644
  if (!el) return null;
14544
13645
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14784,7 +13885,7 @@ function getNavigationSelectionParent(el) {
14784
13885
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14785
13886
  return getFooterLinksContainer();
14786
13887
  }
14787
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
13888
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14788
13889
  return getNavigationRoot(el);
14789
13890
  }
14790
13891
  return null;
@@ -15377,45 +14478,6 @@ function StateToggle({
15377
14478
  );
15378
14479
  }
15379
14480
  var contentCache = /* @__PURE__ */ new Map();
15380
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15381
- var OHW_LOADER_STYLE = {
15382
- position: "fixed",
15383
- inset: 0,
15384
- background: "#fff",
15385
- zIndex: 2147483646,
15386
- display: "flex",
15387
- alignItems: "center",
15388
- justifyContent: "center"
15389
- };
15390
- function OhwLoaderSpinner() {
15391
- return /* @__PURE__ */ jsxs20("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15392
- /* @__PURE__ */ jsx33("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15393
- /* @__PURE__ */ jsx33(
15394
- "circle",
15395
- {
15396
- cx: "14",
15397
- cy: "14",
15398
- r: "11",
15399
- stroke: "#1C1917",
15400
- strokeWidth: "3",
15401
- strokeDasharray: "17 52",
15402
- strokeLinecap: "round",
15403
- children: /* @__PURE__ */ jsx33(
15404
- "animateTransform",
15405
- {
15406
- attributeName: "transform",
15407
- type: "rotate",
15408
- from: "0 14 14",
15409
- to: "360 14 14",
15410
- dur: "0.7s",
15411
- repeatCount: "indefinite"
15412
- }
15413
- )
15414
- }
15415
- )
15416
- ] });
15417
- }
15418
- var OHW_LOADER_PREHYDRATE_SCRIPT = `(function(){try{var p=location.hostname.split(".");var fromHost=p.length>=3&&p[0]!=="www"?p[0]:"";var fromQuery=new URLSearchParams(location.search).get("subdomain")||"";if(!fromHost&&!fromQuery)return;var e=document.getElementById("ohw-loader");if(e)e.style.display="flex"}catch(e){}})();`;
15419
14481
  function resolveSubdomain(subdomainFromQuery) {
15420
14482
  if (subdomainFromQuery) return subdomainFromQuery;
15421
14483
  if (typeof window !== "undefined") {
@@ -15438,8 +14500,8 @@ function OhhwellsBridge() {
15438
14500
  const router = useRouter3();
15439
14501
  const searchParams = useSearchParams();
15440
14502
  const isEditMode = isEditSessionActive();
15441
- const [bridgeRoot, setBridgeRoot] = useState12(null);
15442
- useEffect13(() => {
14503
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
14504
+ useEffect12(() => {
15443
14505
  const figtreeFontId = "ohw-figtree-font";
15444
14506
  if (!document.getElementById(figtreeFontId)) {
15445
14507
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15468,146 +14530,82 @@ function OhhwellsBridge() {
15468
14530
  const subdomain = resolveSubdomain(subdomainFromQuery);
15469
14531
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15470
14532
  useSavedLinkNavigation(isEditMode);
15471
- const postToParent2 = useCallback8((data) => {
14533
+ const postToParent2 = useCallback7((data) => {
15472
14534
  if (typeof window !== "undefined" && window.parent !== window) {
15473
14535
  window.parent.postMessage(data, "*");
15474
14536
  }
15475
14537
  }, []);
15476
- const [fetchState, setFetchState] = useState12("idle");
15477
- const autoSaveTimers = useRef10(/* @__PURE__ */ new Map());
15478
- const activeElRef = useRef10(null);
15479
- const pointerHeldRef = useRef10(false);
15480
- const selectedElRef = useRef10(null);
15481
- const selectedHrefKeyRef = useRef10(null);
15482
- const selectedFooterColAttrRef = useRef10(null);
15483
- const originalContentRef = useRef10(null);
15484
- const activeStateElRef = useRef10(null);
15485
- const parentScrollRef = useRef10(null);
15486
- const visibleViewportRef = useRef10(null);
15487
- const [dialogPortalContainer, setDialogPortalContainer] = useState12(null);
15488
- const attachVisibleViewport = useCallback8((node) => {
14538
+ const [fetchState, setFetchState] = useState11("idle");
14539
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
14540
+ const activeElRef = useRef9(null);
14541
+ const pointerHeldRef = useRef9(false);
14542
+ const selectedElRef = useRef9(null);
14543
+ const selectedHrefKeyRef = useRef9(null);
14544
+ const selectedFooterColAttrRef = useRef9(null);
14545
+ const originalContentRef = useRef9(null);
14546
+ const activeStateElRef = useRef9(null);
14547
+ const parentScrollRef = useRef9(null);
14548
+ const visibleViewportRef = useRef9(null);
14549
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
14550
+ const attachVisibleViewport = useCallback7((node) => {
15489
14551
  visibleViewportRef.current = node;
15490
14552
  setDialogPortalContainer(node);
15491
14553
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15492
14554
  }, []);
15493
- const toolbarElRef = useRef10(null);
15494
- const glowElRef = useRef10(null);
15495
- const hoveredImageRef = useRef10(null);
15496
- const hoveredImageHasTextOverlapRef = useRef10(false);
15497
- const dragOverElRef = useRef10(null);
15498
- const [mediaHover, setMediaHover] = useState12(null);
15499
- const [selectedMedia, setSelectedMedia] = useState12(null);
15500
- const selectedMediaElRef = useRef10(null);
15501
- const clearMediaSelection = useCallback8(() => {
15502
- const prev = selectedMediaElRef.current;
15503
- selectedMediaElRef.current = null;
15504
- setSelectedMedia(null);
15505
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15506
- if (sectionEl) {
15507
- postToParentRef.current({
15508
- type: "ow:section-selected",
15509
- sectionId: sectionEl.dataset.ohwSection ?? null,
15510
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15511
- key: null
15512
- });
15513
- }
15514
- }, []);
15515
- const clearMediaSelectionRef = useRef10(clearMediaSelection);
15516
- clearMediaSelectionRef.current = clearMediaSelection;
15517
- const selectMediaElement = useCallback8((el) => {
15518
- const r2 = el.getBoundingClientRect();
15519
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15520
- selectedMediaElRef.current = el;
15521
- setSelectedMedia({
15522
- key: el.dataset.ohwKey ?? "",
15523
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15524
- elementType: el.dataset.ohwEditable ?? "image",
15525
- hasTextOverlap: false,
15526
- isDragOver: false,
15527
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15528
- });
15529
- const sectionEl = el.closest("[data-ohw-section]");
15530
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15531
- postToParentRef.current({
15532
- type: "ow:section-selected",
15533
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15534
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15535
- key: el.dataset.ohwKey ?? null,
15536
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15537
- // bridge knows what the node IS, so it names it.
15538
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : "Image"
15539
- });
15540
- }, []);
15541
- const selectMediaElementRef = useRef10(selectMediaElement);
15542
- selectMediaElementRef.current = selectMediaElement;
15543
- useEffect13(() => {
15544
- if (!selectedMedia) return;
15545
- const update = () => {
15546
- const el = selectedMediaElRef.current;
15547
- if (!el || !el.isConnected) {
15548
- clearMediaSelection();
15549
- return;
15550
- }
15551
- const r2 = el.getBoundingClientRect();
15552
- setSelectedMedia(
15553
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15554
- );
15555
- };
15556
- window.addEventListener("scroll", update, true);
15557
- window.addEventListener("resize", update);
15558
- return () => {
15559
- window.removeEventListener("scroll", update, true);
15560
- window.removeEventListener("resize", update);
15561
- };
15562
- }, [selectedMedia !== null]);
15563
- const [carouselHover, setCarouselHover] = useState12(null);
15564
- const [uploadingRects, setUploadingRects] = useState12({});
15565
- const hoveredGapRef = useRef10(null);
15566
- const imageUnhoverTimerRef = useRef10(null);
15567
- const imageShowTimerRef = useRef10(null);
15568
- const editStylesRef = useRef10(null);
15569
- const activateRef = useRef10(() => {
14555
+ const toolbarElRef = useRef9(null);
14556
+ const glowElRef = useRef9(null);
14557
+ const hoveredImageRef = useRef9(null);
14558
+ const hoveredImageHasTextOverlapRef = useRef9(false);
14559
+ const dragOverElRef = useRef9(null);
14560
+ const [mediaHover, setMediaHover] = useState11(null);
14561
+ const [carouselHover, setCarouselHover] = useState11(null);
14562
+ const [uploadingRects, setUploadingRects] = useState11({});
14563
+ const hoveredGapRef = useRef9(null);
14564
+ const imageUnhoverTimerRef = useRef9(null);
14565
+ const imageShowTimerRef = useRef9(null);
14566
+ const editStylesRef = useRef9(null);
14567
+ const activateRef = useRef9(() => {
15570
14568
  });
15571
- const deactivateRef = useRef10(() => {
14569
+ const deactivateRef = useRef9(() => {
15572
14570
  });
15573
- const selectRef = useRef10(() => {
14571
+ const selectRef = useRef9(() => {
15574
14572
  });
15575
- const selectFrameRef = useRef10(() => {
14573
+ const selectFrameRef = useRef9(() => {
15576
14574
  });
15577
- const selectLogoRef = useRef10(() => {
14575
+ const selectLogoRef = useRef9(() => {
15578
14576
  });
15579
- const openLogoSizePanelRef = useRef10(() => {
14577
+ const openLogoSizePanelRef = useRef9(() => {
15580
14578
  });
15581
- const deselectRef = useRef10(() => {
14579
+ const deselectRef = useRef9(() => {
15582
14580
  });
15583
- const closeFloatingPanelOnlyRef = useRef10(() => {
14581
+ const closeFloatingPanelOnlyRef = useRef9(() => {
15584
14582
  });
15585
- const reselectNavigationItemRef = useRef10(() => {
14583
+ const reselectNavigationItemRef = useRef9(() => {
15586
14584
  });
15587
- const commitNavigationTextEditRef = useRef10(() => {
14585
+ const commitNavigationTextEditRef = useRef9(() => {
15588
14586
  });
15589
- const handleDeleteSelectedRef = useRef10(() => false);
15590
- const runPendingDeleteUndoRef = useRef10(() => false);
15591
- const isFooterFrameSelectionRef = useRef10(false);
15592
- const refreshActiveCommandsRef = useRef10(() => {
14587
+ const handleDeleteSelectedRef = useRef9(() => false);
14588
+ const runPendingDeleteUndoRef = useRef9(() => false);
14589
+ const isFooterFrameSelectionRef = useRef9(false);
14590
+ const refreshActiveCommandsRef = useRef9(() => {
15593
14591
  });
15594
- const postToParentRef = useRef10(postToParent2);
14592
+ const postToParentRef = useRef9(postToParent2);
15595
14593
  postToParentRef.current = postToParent2;
15596
- const aiSectionApiRef = useRef10(null);
15597
- const sectionsLoadedRef = useRef10(false);
15598
- const pendingScheduleConfigRequests = useRef10([]);
15599
- const [toolbarRect, setToolbarRect] = useState12(null);
15600
- const [formPickRect, setFormPickRect] = useState12(null);
15601
- const formPickElRef = useRef10(null);
15602
- const [formViewState, setFormViewStateUi] = useState12("default");
15603
- const [formPickCount, setFormPickCount] = useState12(null);
15604
- const [formHoverRect, setFormHoverRect] = useState12(null);
15605
- const formHoverElRef = useRef10(null);
15606
- const [fieldPickRect, setFieldPickRect] = useState12(null);
15607
- const fieldPickElRef = useRef10(null);
15608
- const [fieldPickState, setFieldPickState] = useState12(null);
15609
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState12(false);
15610
- const clearFormPick = useCallback8(() => {
14594
+ const aiSectionApiRef = useRef9(null);
14595
+ const sectionsLoadedRef = useRef9(false);
14596
+ const pendingScheduleConfigRequests = useRef9([]);
14597
+ const [toolbarRect, setToolbarRect] = useState11(null);
14598
+ const [formPickRect, setFormPickRect] = useState11(null);
14599
+ const formPickElRef = useRef9(null);
14600
+ const [formViewState, setFormViewStateUi] = useState11("default");
14601
+ const [formPickCount, setFormPickCount] = useState11(null);
14602
+ const [formHoverRect, setFormHoverRect] = useState11(null);
14603
+ const formHoverElRef = useRef9(null);
14604
+ const [fieldPickRect, setFieldPickRect] = useState11(null);
14605
+ const fieldPickElRef = useRef9(null);
14606
+ const [fieldPickState, setFieldPickState] = useState11(null);
14607
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState11(false);
14608
+ const clearFormPick = useCallback7(() => {
15611
14609
  const form = formPickElRef.current;
15612
14610
  const editing = fieldPickElRef.current;
15613
14611
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15627,7 +14625,7 @@ function OhhwellsBridge() {
15627
14625
  formPickElRef.current = null;
15628
14626
  setFormPickRect(null);
15629
14627
  }, []);
15630
- const clearFieldPick = useCallback8(() => {
14628
+ const clearFieldPick = useCallback7(() => {
15631
14629
  const wrapper = fieldPickElRef.current;
15632
14630
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15633
14631
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15637,9 +14635,9 @@ function OhhwellsBridge() {
15637
14635
  setFieldPickRect(null);
15638
14636
  setFieldPickState(null);
15639
14637
  }, []);
15640
- const persistFieldsRef = useRef10(() => {
14638
+ const persistFieldsRef = useRef9(() => {
15641
14639
  });
15642
- const persistFields = useCallback8(
14640
+ const persistFields = useCallback7(
15643
14641
  (form) => {
15644
14642
  const key = formKeyOf(form);
15645
14643
  if (!key) return;
@@ -15650,7 +14648,7 @@ function OhhwellsBridge() {
15650
14648
  []
15651
14649
  );
15652
14650
  persistFieldsRef.current = persistFields;
15653
- const selectField = useCallback8((wrapper) => {
14651
+ const selectField = useCallback7((wrapper) => {
15654
14652
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15655
14653
  commitPlaceholderEdit(fieldPickElRef.current);
15656
14654
  }
@@ -15663,7 +14661,7 @@ function OhhwellsBridge() {
15663
14661
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15664
14662
  setFieldTypePickerOpen(false);
15665
14663
  }, []);
15666
- const withSelectedField = useCallback8(
14664
+ const withSelectedField = useCallback7(
15667
14665
  (run) => {
15668
14666
  const wrapper = fieldPickElRef.current;
15669
14667
  const form = formPickElRef.current;
@@ -15676,28 +14674,28 @@ function OhhwellsBridge() {
15676
14674
  },
15677
14675
  [persistFields]
15678
14676
  );
15679
- const handleFieldTypeChange = useCallback8(
14677
+ const handleFieldTypeChange = useCallback7(
15680
14678
  (type) => withSelectedField((_form, wrapper) => {
15681
14679
  applyFieldType(wrapper, type);
15682
14680
  selectField(wrapper);
15683
14681
  }),
15684
14682
  [selectField, withSelectedField]
15685
14683
  );
15686
- const handleFieldRequiredToggle = useCallback8(
14684
+ const handleFieldRequiredToggle = useCallback7(
15687
14685
  () => withSelectedField((_form, wrapper) => {
15688
14686
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15689
14687
  selectField(wrapper);
15690
14688
  }),
15691
14689
  [selectField, withSelectedField]
15692
14690
  );
15693
- const handleFieldDuplicate = useCallback8(
14691
+ const handleFieldDuplicate = useCallback7(
15694
14692
  () => withSelectedField((form, wrapper) => {
15695
14693
  const copy = duplicateField(form, wrapper);
15696
14694
  selectField(copy);
15697
14695
  }),
15698
14696
  [selectField, withSelectedField]
15699
14697
  );
15700
- const handleFieldDelete = useCallback8(
14698
+ const handleFieldDelete = useCallback7(
15701
14699
  () => withSelectedField((_form, wrapper) => {
15702
14700
  removeField(wrapper);
15703
14701
  clearFieldPick();
@@ -15705,7 +14703,7 @@ function OhhwellsBridge() {
15705
14703
  }),
15706
14704
  [clearFieldPick, withSelectedField]
15707
14705
  );
15708
- const handleAddField = useCallback8(
14706
+ const handleAddField = useCallback7(
15709
14707
  (type) => {
15710
14708
  const form = formPickElRef.current;
15711
14709
  if (!form) return;
@@ -15721,8 +14719,8 @@ function OhhwellsBridge() {
15721
14719
  },
15722
14720
  [persistFields, selectField]
15723
14721
  );
15724
- const fieldDragRef = useRef10(null);
15725
- const buildFieldDropSlots = useCallback8((form, draggedKey) => {
14722
+ const fieldDragRef = useRef9(null);
14723
+ const buildFieldDropSlots = useCallback7((form, draggedKey) => {
15726
14724
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15727
14725
  const slots = others.map((el) => {
15728
14726
  const rect = el.getBoundingClientRect();
@@ -15735,7 +14733,7 @@ function OhhwellsBridge() {
15735
14733
  }
15736
14734
  return slots;
15737
14735
  }, []);
15738
- const handleFieldDragStart = useCallback8(() => {
14736
+ const handleFieldDragStart = useCallback7(() => {
15739
14737
  const wrapper = fieldPickElRef.current;
15740
14738
  const form = formPickElRef.current;
15741
14739
  if (!wrapper || !form) return;
@@ -15744,18 +14742,18 @@ function OhhwellsBridge() {
15744
14742
  setFieldDragging(true);
15745
14743
  setFieldDropSlots(buildFieldDropSlots(form, key));
15746
14744
  }, [buildFieldDropSlots]);
15747
- const handleFieldDragEnd = useCallback8(() => {
14745
+ const handleFieldDragEnd = useCallback7(() => {
15748
14746
  fieldDragRef.current = null;
15749
14747
  setFieldDropIndex(null);
15750
14748
  setFieldDropSlots([]);
15751
14749
  setFieldDragging(false);
15752
14750
  }, []);
15753
- const [fieldDropIndex, setFieldDropIndex] = useState12(null);
15754
- const [fieldDropSlots, setFieldDropSlots] = useState12([]);
15755
- const [fieldDragging, setFieldDragging] = useState12(false);
15756
- const clearFormPickRef = useRef10(clearFormPick);
14751
+ const [fieldDropIndex, setFieldDropIndex] = useState11(null);
14752
+ const [fieldDropSlots, setFieldDropSlots] = useState11([]);
14753
+ const [fieldDragging, setFieldDragging] = useState11(false);
14754
+ const clearFormPickRef = useRef9(clearFormPick);
15757
14755
  clearFormPickRef.current = clearFormPick;
15758
- useEffect13(() => {
14756
+ useEffect12(() => {
15759
14757
  const el = fieldPickElRef.current;
15760
14758
  if (!el || fieldPickRect === null) return;
15761
14759
  const observer = new ResizeObserver(() => {
@@ -15764,7 +14762,7 @@ function OhhwellsBridge() {
15764
14762
  observer.observe(el);
15765
14763
  return () => observer.disconnect();
15766
14764
  }, [fieldPickRect !== null, fieldPickState]);
15767
- useEffect13(() => {
14765
+ useEffect12(() => {
15768
14766
  const el = formPickElRef.current;
15769
14767
  if (!el || formPickRect === null) return;
15770
14768
  const observer = new ResizeObserver(() => {
@@ -15773,25 +14771,25 @@ function OhhwellsBridge() {
15773
14771
  observer.observe(el);
15774
14772
  return () => observer.disconnect();
15775
14773
  }, [formPickRect !== null, formViewState]);
15776
- const [toolbarVariant, setToolbarVariant] = useState12("none");
15777
- const toolbarVariantRef = useRef10("none");
14774
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
14775
+ const toolbarVariantRef = useRef9("none");
15778
14776
  toolbarVariantRef.current = toolbarVariant;
15779
- const [selectedIsCta, setSelectedIsCta] = useState12(false);
15780
- const [selectedIsSocial, setSelectedIsSocial] = useState12(false);
15781
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState12(false);
15782
- const [reorderHrefKey, setReorderHrefKey] = useState12(null);
15783
- const [reorderDragDisabled, setReorderDragDisabled] = useState12(false);
15784
- const [toggleState, setToggleState] = useState12(null);
15785
- const [maxBadge, setMaxBadge] = useState12(null);
15786
- const [activeCommands, setActiveCommands] = useState12(/* @__PURE__ */ new Set());
15787
- const [sectionGap, setSectionGap] = useState12(null);
15788
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState12(false);
15789
- const hoveredNavContainerRef = useRef10(null);
15790
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState12(null);
15791
- const hoveredItemElRef = useRef10(null);
15792
- const [hoveredItemRect, setHoveredItemRect] = useState12(null);
15793
- const [hoveredTextRect, setHoveredTextRect] = useState12(null);
15794
- useEffect13(() => {
14777
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
14778
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
14779
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
14780
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
14781
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
14782
+ const [toggleState, setToggleState] = useState11(null);
14783
+ const [maxBadge, setMaxBadge] = useState11(null);
14784
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
14785
+ const [sectionGap, setSectionGap] = useState11(null);
14786
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
14787
+ const hoveredNavContainerRef = useRef9(null);
14788
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
14789
+ const hoveredItemElRef = useRef9(null);
14790
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
14791
+ const [hoveredTextRect, setHoveredTextRect] = useState11(null);
14792
+ useEffect12(() => {
15795
14793
  const sync = () => {
15796
14794
  const el = document.querySelector(
15797
14795
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15812,56 +14810,43 @@ function OhhwellsBridge() {
15812
14810
  });
15813
14811
  return () => observer.disconnect();
15814
14812
  }, []);
15815
- const siblingHintElRef = useRef10(null);
15816
- const [siblingHintRect, setSiblingHintRect] = useState12(null);
15817
- const [siblingHintRects, setSiblingHintRects] = useState12([]);
15818
- const [isItemDragging, setIsItemDragging] = useState12(false);
15819
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState12(false);
14813
+ const siblingHintElRef = useRef9(null);
14814
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
14815
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
14816
+ const [isItemDragging, setIsItemDragging] = useState11(false);
14817
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
15820
14818
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15821
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState12(null);
15822
- const [footerHeadingVisible, setFooterHeadingVisible] = useState12(null);
15823
- const footerDragRef = useRef10(null);
15824
- const [footerDropSlots, setFooterDropSlots] = useState12([]);
15825
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState12(null);
15826
- const [draggedItemRect, setDraggedItemRect] = useState12(null);
15827
- const footerPointerDragRef = useRef10(null);
15828
- const suppressNextClickRef = useRef10(false);
15829
- const suppressClickUntilRef = useRef10(0);
15830
- const [linkPopover, setLinkPopover] = useState12(null);
15831
- const linkPopoverSessionRef = useRef10(null);
15832
- const addNavAfterAnchorRef = useRef10(null);
15833
- const editContentRef = useRef10({});
15834
- const aiSectionsRef = useRef10("");
15835
- const brandKitRef = useRef10("");
15836
- const stylesRef = useRef10("");
15837
- const pendingDeleteUndoRef = useRef10(null);
15838
- const [floatingPanel, setFloatingPanel] = useState12(null);
15839
- const floatingPanelOpenRef = useRef10(false);
15840
- const setFloatingPanelRef = useRef10(setFloatingPanel);
15841
- const [floatingPanelPos, setFloatingPanelPos] = useState12(null);
15842
- const [logoSizeDraft, setLogoSizeDraft] = useState12(null);
15843
- const [editorViewport, setEditorViewport] = useState12("desktop");
15844
- const [parentScrollSnap, setParentScrollSnap] = useState12(null);
15845
- const [sitePages, setSitePages] = useState12([]);
15846
- const [sectionsByPath, setSectionsByPath] = useState12({});
15847
- const sectionsPrefetchGenRef = useRef10(0);
15848
- const setLinkPopoverRef = useRef10(setLinkPopover);
15849
- const linkPopoverPanelRef = useRef10(null);
15850
- const linkPopoverOpenRef = useRef10(false);
15851
- const linkPopoverGraceUntilRef = useRef10(0);
14819
+ const [floatingPanel, setFloatingPanel] = useState11(null);
14820
+ const floatingPanelOpenRef = useRef9(false);
14821
+ floatingPanelOpenRef.current = floatingPanel !== null;
14822
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
14823
+ const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
14824
+ const [editorViewport, setEditorViewport] = useState11("desktop");
14825
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
14826
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
14827
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
14828
+ const footerDragRef = useRef9(null);
14829
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
14830
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
14831
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
14832
+ const footerPointerDragRef = useRef9(null);
14833
+ const suppressNextClickRef = useRef9(false);
14834
+ const suppressClickUntilRef = useRef9(0);
14835
+ const [linkPopover, setLinkPopover] = useState11(null);
14836
+ const linkPopoverSessionRef = useRef9(null);
14837
+ const addNavAfterAnchorRef = useRef9(null);
14838
+ const editContentRef = useRef9({});
14839
+ const aiSectionsRef = useRef9("");
14840
+ const pendingDeleteUndoRef = useRef9(null);
14841
+ const [sitePages, setSitePages] = useState11([]);
14842
+ const [sectionsByPath, setSectionsByPath] = useState11({});
14843
+ const sectionsPrefetchGenRef = useRef9(0);
14844
+ const setLinkPopoverRef = useRef9(setLinkPopover);
14845
+ const linkPopoverPanelRef = useRef9(null);
14846
+ const linkPopoverOpenRef = useRef9(false);
14847
+ const linkPopoverGraceUntilRef = useRef9(0);
15852
14848
  setLinkPopoverRef.current = setLinkPopover;
15853
- setFloatingPanelRef.current = setFloatingPanel;
15854
14849
  linkPopoverSessionRef.current = linkPopover;
15855
- floatingPanelOpenRef.current = Boolean(floatingPanel);
15856
- useEffect13(() => {
15857
- const syncViewport = () => {
15858
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
15859
- setEditorViewport((prev) => prev === next ? prev : next);
15860
- };
15861
- syncViewport();
15862
- window.addEventListener("resize", syncViewport);
15863
- return () => window.removeEventListener("resize", syncViewport);
15864
- }, []);
15865
14850
  const {
15866
14851
  navDragRef,
15867
14852
  navDropSlots,
@@ -15894,20 +14879,10 @@ function OhhwellsBridge() {
15894
14879
  getNavigationItemAnchor,
15895
14880
  isDragHandleDisabled
15896
14881
  });
15897
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15898
- isEditMode,
15899
- editContentRef,
15900
- postToParentRef,
15901
- parentScrollRef,
15902
- navDragRef,
15903
- footerDragRef,
15904
- suppressNextClickRef,
15905
- suppressClickUntilRef
15906
- });
15907
14882
  const bumpLinkPopoverGrace = () => {
15908
14883
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15909
14884
  };
15910
- const runSectionsPrefetch = useCallback8((pages) => {
14885
+ const runSectionsPrefetch = useCallback7((pages) => {
15911
14886
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15912
14887
  const gen = ++sectionsPrefetchGenRef.current;
15913
14888
  const paths = pages.map((p) => p.path);
@@ -15926,9 +14901,9 @@ function OhhwellsBridge() {
15926
14901
  );
15927
14902
  });
15928
14903
  }, [isEditMode, pathname]);
15929
- const runSectionsPrefetchRef = useRef10(runSectionsPrefetch);
14904
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
15930
14905
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15931
- useEffect13(() => {
14906
+ useEffect12(() => {
15932
14907
  if (!linkPopover) {
15933
14908
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15934
14909
  return;
@@ -15956,7 +14931,7 @@ function OhhwellsBridge() {
15956
14931
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15957
14932
  };
15958
14933
  }, [linkPopover, postToParent2]);
15959
- useEffect13(() => {
14934
+ useEffect12(() => {
15960
14935
  if (!isEditMode) return;
15961
14936
  const useFixtures = shouldUseDevFixtures();
15962
14937
  if (useFixtures) {
@@ -15980,14 +14955,14 @@ function OhhwellsBridge() {
15980
14955
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
15981
14956
  return () => window.removeEventListener("message", onSitePages);
15982
14957
  }, [isEditMode, postToParent2]);
15983
- useEffect13(() => {
14958
+ useEffect12(() => {
15984
14959
  if (!isEditMode || shouldUseDevFixtures()) return;
15985
14960
  void loadAllSectionsManifest().then((manifest) => {
15986
14961
  if (Object.keys(manifest).length === 0) return;
15987
14962
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
15988
14963
  });
15989
14964
  }, [isEditMode]);
15990
- useEffect13(() => {
14965
+ useEffect12(() => {
15991
14966
  const update = () => {
15992
14967
  const el = activeElRef.current ?? selectedElRef.current;
15993
14968
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -16011,10 +14986,10 @@ function OhhwellsBridge() {
16011
14986
  vvp.removeEventListener("resize", update);
16012
14987
  };
16013
14988
  }, []);
16014
- const refreshStateRules = useCallback8(() => {
14989
+ const refreshStateRules = useCallback7(() => {
16015
14990
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
16016
14991
  }, []);
16017
- const processConfigRequest = useCallback8((insertAfterVal) => {
14992
+ const processConfigRequest = useCallback7((insertAfterVal) => {
16018
14993
  const tracker = getSectionsTracker();
16019
14994
  let entries = [];
16020
14995
  try {
@@ -16037,7 +15012,7 @@ function OhhwellsBridge() {
16037
15012
  }
16038
15013
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
16039
15014
  }, [isEditMode]);
16040
- const deactivate = useCallback8(() => {
15015
+ const deactivate = useCallback7(() => {
16041
15016
  const el = activeElRef.current;
16042
15017
  if (!el) return;
16043
15018
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16078,12 +15053,12 @@ function OhhwellsBridge() {
16078
15053
  setToolbarShowEditLink(false);
16079
15054
  postToParent2({ type: "ow:exit-edit" });
16080
15055
  }, [postToParent2]);
16081
- const clearSelectedAttr = useCallback8(() => {
15056
+ const clearSelectedAttr = useCallback7(() => {
16082
15057
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16083
15058
  el.removeAttribute("data-ohw-selected");
16084
15059
  });
16085
15060
  }, []);
16086
- const deselect = useCallback8(() => {
15061
+ const deselect = useCallback7(() => {
16087
15062
  clearSelectedAttr();
16088
15063
  selectedElRef.current = null;
16089
15064
  selectedHrefKeyRef.current = null;
@@ -16112,12 +15087,11 @@ function OhhwellsBridge() {
16112
15087
  setToolbarVariant("none");
16113
15088
  }
16114
15089
  }, [clearSelectedAttr]);
16115
- const markSelected = useCallback8((el) => {
15090
+ const markSelected = useCallback7((el) => {
16116
15091
  clearSelectedAttr();
16117
- el.removeAttribute("data-ohw-hovered");
16118
15092
  el.setAttribute("data-ohw-selected", "");
16119
15093
  }, [clearSelectedAttr]);
16120
- const resolveHrefKeyElement = useCallback8((hrefKey) => {
15094
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
16121
15095
  if (isFooterHrefKey(hrefKey)) {
16122
15096
  return document.querySelector(
16123
15097
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16132,7 +15106,7 @@ function OhhwellsBridge() {
16132
15106
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16133
15107
  );
16134
15108
  }, []);
16135
- const resyncSelectedNavigationItem = useCallback8(() => {
15109
+ const resyncSelectedNavigationItem = useCallback7(() => {
16136
15110
  const hrefKey = selectedHrefKeyRef.current;
16137
15111
  if (hrefKey) {
16138
15112
  const link = resolveHrefKeyElement(hrefKey);
@@ -16170,7 +15144,7 @@ function OhhwellsBridge() {
16170
15144
  );
16171
15145
  }
16172
15146
  }, [resolveHrefKeyElement]);
16173
- const reselectNavigationItem = useCallback8((navAnchor) => {
15147
+ const reselectNavigationItem = useCallback7((navAnchor) => {
16174
15148
  selectedElRef.current = navAnchor;
16175
15149
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16176
15150
  selectedFooterColAttrRef.current = null;
@@ -16201,7 +15175,7 @@ function OhhwellsBridge() {
16201
15175
  setToolbarShowEditLink(false);
16202
15176
  setActiveCommands(/* @__PURE__ */ new Set());
16203
15177
  }, [markSelected]);
16204
- const commitNavigationTextEdit = useCallback8((navAnchor) => {
15178
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
16205
15179
  const el = activeElRef.current;
16206
15180
  if (!el) return;
16207
15181
  const key = el.dataset.ohwKey;
@@ -16234,7 +15208,7 @@ function OhhwellsBridge() {
16234
15208
  postToParent2({ type: "ow:exit-edit" });
16235
15209
  reselectNavigationItem(navAnchor);
16236
15210
  }, [postToParent2, reselectNavigationItem]);
16237
- const handleAddTopLevelNavItem = useCallback8(() => {
15211
+ const handleAddTopLevelNavItem = useCallback7(() => {
16238
15212
  const items = listNavbarRootItems();
16239
15213
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16240
15214
  deselectRef.current();
@@ -16246,7 +15220,7 @@ function OhhwellsBridge() {
16246
15220
  intent: "add-nav"
16247
15221
  });
16248
15222
  }, []);
16249
- const maybeWarnNavLinkDropdownConflict = useCallback8(
15223
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
16250
15224
  (anchor) => {
16251
15225
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16252
15226
  if (!navDropdownsOpenOnClick()) return;
@@ -16259,7 +15233,7 @@ function OhhwellsBridge() {
16259
15233
  },
16260
15234
  [postToParent2]
16261
15235
  );
16262
- const handleNavDropdownOpenChange = useCallback8((open) => {
15236
+ const handleNavDropdownOpenChange = useCallback7((open) => {
16263
15237
  const selected = selectedElRef.current;
16264
15238
  if (!selected || !isNavigationItem2(selected)) return;
16265
15239
  setNavGroupForceOpen(selected, open);
@@ -16271,7 +15245,7 @@ function OhhwellsBridge() {
16271
15245
  }
16272
15246
  });
16273
15247
  }, []);
16274
- const handleFooterHeadingVisibleChange = useCallback8(
15248
+ const handleFooterHeadingVisibleChange = useCallback7(
16275
15249
  (visible) => {
16276
15250
  const selected = selectedElRef.current;
16277
15251
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16295,7 +15269,7 @@ function OhhwellsBridge() {
16295
15269
  },
16296
15270
  [postToParent2]
16297
15271
  );
16298
- const enterEditOnNewItem = useCallback8((anchor) => {
15272
+ const enterEditOnNewItem = useCallback7((anchor) => {
16299
15273
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16300
15274
  if (!label) {
16301
15275
  selectRef.current(anchor);
@@ -16304,7 +15278,7 @@ function OhhwellsBridge() {
16304
15278
  setNavGroupForceOpen(anchor, true);
16305
15279
  activateRef.current(label);
16306
15280
  }, []);
16307
- const handleAddChildItem = useCallback8(() => {
15281
+ const handleAddChildItem = useCallback7(() => {
16308
15282
  const selected = selectedElRef.current;
16309
15283
  if (!selected) return;
16310
15284
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16416,7 +15390,7 @@ function OhhwellsBridge() {
16416
15390
  enterEditOnNewItem(result.anchor);
16417
15391
  });
16418
15392
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16419
- const handleAddFooterColumn = useCallback8(() => {
15393
+ const handleAddFooterColumn = useCallback7(() => {
16420
15394
  if (!canAddFooterColumn()) {
16421
15395
  postToParent2({
16422
15396
  type: "ow:toast",
@@ -16437,7 +15411,7 @@ function OhhwellsBridge() {
16437
15411
  selectRef.current(result.firstLink);
16438
15412
  });
16439
15413
  }, [postToParent2]);
16440
- const clearFooterDragVisuals = useCallback8(() => {
15414
+ const clearFooterDragVisuals = useCallback7(() => {
16441
15415
  footerDragRef.current = null;
16442
15416
  setSiblingHintRects([]);
16443
15417
  setFooterDropSlots([]);
@@ -16446,7 +15420,7 @@ function OhhwellsBridge() {
16446
15420
  setIsItemDragging(false);
16447
15421
  unlockFooterDragInteraction();
16448
15422
  }, []);
16449
- const refreshFooterDragVisuals = useCallback8((session, activeSlot, clientX, clientY) => {
15423
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
16450
15424
  const dragged = session.draggedEl;
16451
15425
  setDraggedItemRect(dragged.getBoundingClientRect());
16452
15426
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16478,13 +15452,13 @@ function OhhwellsBridge() {
16478
15452
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16479
15453
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16480
15454
  }, []);
16481
- const refreshFooterDragVisualsRef = useRef10(refreshFooterDragVisuals);
15455
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
16482
15456
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16483
- const commitFooterDragRef = useRef10(() => {
15457
+ const commitFooterDragRef = useRef9(() => {
16484
15458
  });
16485
- const beginFooterDragRef = useRef10(() => {
15459
+ const beginFooterDragRef = useRef9(() => {
16486
15460
  });
16487
- const beginFooterDrag = useCallback8(
15461
+ const beginFooterDrag = useCallback7(
16488
15462
  (session) => {
16489
15463
  const rect = session.draggedEl.getBoundingClientRect();
16490
15464
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16504,7 +15478,7 @@ function OhhwellsBridge() {
16504
15478
  [refreshFooterDragVisuals]
16505
15479
  );
16506
15480
  beginFooterDragRef.current = beginFooterDrag;
16507
- const commitFooterDrag = useCallback8(
15481
+ const commitFooterDrag = useCallback7(
16508
15482
  (clientX, clientY) => {
16509
15483
  const session = footerDragRef.current;
16510
15484
  if (!session) {
@@ -16632,7 +15606,7 @@ function OhhwellsBridge() {
16632
15606
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16633
15607
  );
16634
15608
  commitFooterDragRef.current = commitFooterDrag;
16635
- const startFooterLinkDrag = useCallback8(
15609
+ const startFooterLinkDrag = useCallback7(
16636
15610
  (anchor, clientX, clientY, wasSelected) => {
16637
15611
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16638
15612
  if (!hrefKey) return false;
@@ -16668,7 +15642,7 @@ function OhhwellsBridge() {
16668
15642
  },
16669
15643
  [beginFooterDrag]
16670
15644
  );
16671
- const startFooterColumnDrag = useCallback8(
15645
+ const startFooterColumnDrag = useCallback7(
16672
15646
  (columnEl, clientX, clientY, wasSelected) => {
16673
15647
  const columns = listFooterColumns();
16674
15648
  const idx = columns.indexOf(columnEl);
@@ -16688,7 +15662,7 @@ function OhhwellsBridge() {
16688
15662
  },
16689
15663
  [beginFooterDrag]
16690
15664
  );
16691
- const handleItemDragStart = useCallback8(
15665
+ const handleItemDragStart = useCallback7(
16692
15666
  (e) => {
16693
15667
  const selected = selectedElRef.current;
16694
15668
  if (!selected) {
@@ -16708,7 +15682,7 @@ function OhhwellsBridge() {
16708
15682
  },
16709
15683
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16710
15684
  );
16711
- const handleItemDragEnd = useCallback8(
15685
+ const handleItemDragEnd = useCallback7(
16712
15686
  (e) => {
16713
15687
  if (footerDragRef.current) {
16714
15688
  const x = e?.clientX;
@@ -16734,7 +15708,7 @@ function OhhwellsBridge() {
16734
15708
  },
16735
15709
  [commitFooterDrag, commitNavDrag, navDragRef]
16736
15710
  );
16737
- const handleItemChromePointerDown = useCallback8((e) => {
15711
+ const handleItemChromePointerDown = useCallback7((e) => {
16738
15712
  if (e.button !== 0) return;
16739
15713
  const selected = selectedElRef.current;
16740
15714
  if (!selected) return;
@@ -16765,7 +15739,7 @@ function OhhwellsBridge() {
16765
15739
  }
16766
15740
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16767
15741
  }, [armNavPressFromChrome]);
16768
- const handleItemChromeClick = useCallback8((clientX, clientY) => {
15742
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
16769
15743
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16770
15744
  suppressNextClickRef.current = false;
16771
15745
  return;
@@ -16778,7 +15752,7 @@ function OhhwellsBridge() {
16778
15752
  }, []);
16779
15753
  reselectNavigationItemRef.current = reselectNavigationItem;
16780
15754
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16781
- const select = useCallback8((anchor) => {
15755
+ const select = useCallback7((anchor) => {
16782
15756
  if (!isNavigationItem2(anchor)) return;
16783
15757
  if (activeElRef.current) deactivate();
16784
15758
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16821,7 +15795,7 @@ function OhhwellsBridge() {
16821
15795
  setFloatingPanel(null);
16822
15796
  setLogoSizeDraft(null);
16823
15797
  }, [deactivate, markSelected]);
16824
- const selectFrame = useCallback8((el) => {
15798
+ const selectFrame = useCallback7((el) => {
16825
15799
  if (!isNavigationContainer(el)) return;
16826
15800
  if (activeElRef.current) deactivate();
16827
15801
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16872,7 +15846,7 @@ function OhhwellsBridge() {
16872
15846
  setFloatingPanel(null);
16873
15847
  setLogoSizeDraft(null);
16874
15848
  }, [deactivate, markSelected, postToParent2]);
16875
- const selectLogo = useCallback8(
15849
+ const selectLogo = useCallback7(
16876
15850
  (logoEl) => {
16877
15851
  if (activeElRef.current) deactivate();
16878
15852
  selectedElRef.current = logoEl;
@@ -16901,7 +15875,7 @@ function OhhwellsBridge() {
16901
15875
  },
16902
15876
  [deactivate, markSelected]
16903
15877
  );
16904
- const openLogoSizePanel = useCallback8((logoEl) => {
15878
+ const openLogoSizePanel = useCallback7((logoEl) => {
16905
15879
  const placement = getLogoPlacement(logoEl);
16906
15880
  const draft = readLogoSizeState(editContentRef.current, placement);
16907
15881
  setLogoSizeDraft(draft);
@@ -16914,7 +15888,7 @@ function OhhwellsBridge() {
16914
15888
  placement
16915
15889
  });
16916
15890
  }, []);
16917
- const openSocialsDisplayPanel = useCallback8((row) => {
15891
+ const openSocialsDisplayPanel = useCallback7((row) => {
16918
15892
  setParentScrollSnap(parentScrollRef.current);
16919
15893
  setFloatingPanel({
16920
15894
  key: "socials-display",
@@ -16924,7 +15898,7 @@ function OhhwellsBridge() {
16924
15898
  row
16925
15899
  });
16926
15900
  }, []);
16927
- const changeSocialsDisplay = useCallback8(
15901
+ const changeSocialsDisplay = useCallback7(
16928
15902
  (row, next) => {
16929
15903
  if (next.icon) {
16930
15904
  const missing = socialsMissingIcons(row);
@@ -16947,17 +15921,17 @@ function OhhwellsBridge() {
16947
15921
  },
16948
15922
  []
16949
15923
  );
16950
- const closeFloatingPanelOnly = useCallback8(() => {
15924
+ const closeFloatingPanelOnly = useCallback7(() => {
16951
15925
  setFloatingPanel(null);
16952
15926
  setLogoSizeDraft(null);
16953
15927
  }, []);
16954
15928
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16955
- const closeFloatingPanelAndDeselect = useCallback8(() => {
15929
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
16956
15930
  setFloatingPanel(null);
16957
15931
  setLogoSizeDraft(null);
16958
15932
  deselectRef.current();
16959
15933
  }, []);
16960
- useEffect13(() => {
15934
+ useEffect12(() => {
16961
15935
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
16962
15936
  if (!session || !logoSizeDraft) {
16963
15937
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -16976,7 +15950,7 @@ function OhhwellsBridge() {
16976
15950
  max: LOGO_SIZE_MAX
16977
15951
  });
16978
15952
  }, [floatingPanel, logoSizeDraft, editorViewport]);
16979
- const persistLogoSizeDraft = useCallback8(
15953
+ const persistLogoSizeDraft = useCallback7(
16980
15954
  (placement, draft) => {
16981
15955
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
16982
15956
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -17016,7 +15990,7 @@ function OhhwellsBridge() {
17016
15990
  },
17017
15991
  [postToParent2]
17018
15992
  );
17019
- const activate = useCallback8((el, options) => {
15993
+ const activate = useCallback7((el, options) => {
17020
15994
  if (activeElRef.current === el) return;
17021
15995
  if (isIconEditable(el)) return;
17022
15996
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17100,8 +16074,8 @@ function OhhwellsBridge() {
17100
16074
  openLogoSizePanelRef.current = openLogoSizePanel;
17101
16075
  deselectRef.current = deselect;
17102
16076
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17103
- const lastSiteWideScopeRef = useRef10(null);
17104
- useEffect13(() => {
16077
+ const lastSiteWideScopeRef = useRef9(null);
16078
+ useEffect12(() => {
17105
16079
  if (!isEditMode) {
17106
16080
  if (lastSiteWideScopeRef.current !== false) {
17107
16081
  lastSiteWideScopeRef.current = false;
@@ -17134,27 +16108,15 @@ function OhhwellsBridge() {
17134
16108
  }
17135
16109
  const applyContent = (content) => {
17136
16110
  const imageLoads = [];
17137
- if (typeof content[BRAND_KIT_KEY] === "string") {
17138
- brandKitRef.current = content[BRAND_KIT_KEY];
17139
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17140
- }
17141
16111
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17142
16112
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17143
16113
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17144
16114
  }
17145
- if (typeof content[STYLE_STORE_KEY] === "string") {
17146
- stylesRef.current = content[STYLE_STORE_KEY];
17147
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17148
- }
17149
- applyBrandChrome(content);
17150
16115
  for (const [key, val] of Object.entries(content)) {
17151
16116
  if (key === "__ohw_sections") continue;
17152
16117
  if (key === AI_SECTIONS_KEY) continue;
17153
16118
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17154
16119
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17155
- if (key === BRAND_KIT_KEY) continue;
17156
- if (key === STYLE_STORE_KEY) continue;
17157
- if (BRAND_CHROME_KEYS.has(key)) continue;
17158
16120
  if (applyVideoSettingNode(key, val)) continue;
17159
16121
  if (applyCarouselNode(key, val)) continue;
17160
16122
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17212,9 +16174,7 @@ function OhhwellsBridge() {
17212
16174
  let cancelled = false;
17213
16175
  setFetchState("loading");
17214
16176
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17215
- const initialPath = pathname;
17216
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17217
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16177
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17218
16178
  if (cancelled) return;
17219
16179
  const content = data?.content ?? {};
17220
16180
  contentCache.set(subdomain, content);
@@ -17227,7 +16187,7 @@ function OhhwellsBridge() {
17227
16187
  cancelled = true;
17228
16188
  };
17229
16189
  }, [subdomain, isEditMode]);
17230
- useEffect13(() => {
16190
+ useEffect12(() => {
17231
16191
  if (!isEditMode) return;
17232
16192
  const resolveIndex = (form, clientY) => {
17233
16193
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17268,7 +16228,7 @@ function OhhwellsBridge() {
17268
16228
  window.removeEventListener("drop", onDrop, true);
17269
16229
  };
17270
16230
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17271
- useEffect13(() => {
16231
+ useEffect12(() => {
17272
16232
  if (!isEditMode) return;
17273
16233
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17274
16234
  markFormFields(form);
@@ -17280,7 +16240,7 @@ function OhhwellsBridge() {
17280
16240
  });
17281
16241
  return () => observer.disconnect();
17282
16242
  }, [isEditMode, fetchState, pathname]);
17283
- useEffect13(() => {
16243
+ useEffect12(() => {
17284
16244
  if (!isEditMode) return;
17285
16245
  let saveTimer = null;
17286
16246
  const onInput = (e) => {
@@ -17302,14 +16262,14 @@ function OhhwellsBridge() {
17302
16262
  document.addEventListener("input", onInput, true);
17303
16263
  return () => document.removeEventListener("input", onInput, true);
17304
16264
  }, [isEditMode, persistFields]);
17305
- useEffect13(() => {
16265
+ useEffect12(() => {
17306
16266
  if (isEditMode || fetchState !== "done") return;
17307
16267
  const content = contentCache.get(subdomain) ?? {};
17308
16268
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17309
16269
  reconcileFieldsFromContent(form, content);
17310
16270
  });
17311
16271
  }, [isEditMode, fetchState, subdomain]);
17312
- useEffect13(() => {
16272
+ useEffect12(() => {
17313
16273
  if (!isEditMode) return;
17314
16274
  const swallow = (e) => {
17315
16275
  const target = e.target;
@@ -17318,12 +16278,12 @@ function OhhwellsBridge() {
17318
16278
  document.addEventListener("submit", swallow, true);
17319
16279
  return () => document.removeEventListener("submit", swallow, true);
17320
16280
  }, [isEditMode]);
17321
- useEffect13(() => {
16281
+ useEffect12(() => {
17322
16282
  if (isEditMode || fetchState !== "done") return;
17323
16283
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17324
16284
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17325
16285
  }, [isEditMode, fetchState, subdomain]);
17326
- useEffect13(() => {
16286
+ useEffect12(() => {
17327
16287
  if (!subdomain || isEditMode) return;
17328
16288
  let debounceTimer = null;
17329
16289
  let observer = null;
@@ -17334,21 +16294,10 @@ function OhhwellsBridge() {
17334
16294
  initSectionInstancesFromContent(content, window.location.pathname);
17335
16295
  observer?.disconnect();
17336
16296
  try {
17337
- applyBrandChrome(content);
17338
- if (typeof content[BRAND_KIT_KEY] === "string") {
17339
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17340
- }
17341
- if (typeof content[STYLE_STORE_KEY] === "string") {
17342
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17343
- }
17344
16297
  for (const [key, val] of Object.entries(content)) {
17345
16298
  if (key === "__ohw_sections") continue;
17346
16299
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17347
16300
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17348
- if (key === BRAND_KIT_KEY) continue;
17349
- if (key === STYLE_STORE_KEY) continue;
17350
- if (key === STYLE_STORE_KEY) continue;
17351
- if (BRAND_CHROME_KEYS.has(key)) continue;
17352
16301
  if (applyVideoSettingNode(key, val)) continue;
17353
16302
  if (applyCarouselNode(key, val)) continue;
17354
16303
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17391,17 +16340,6 @@ function OhhwellsBridge() {
17391
16340
  debounceTimer = setTimeout(applyFromCache, 150);
17392
16341
  };
17393
16342
  applyFromCache();
17394
- const pathCacheKey = `${subdomain}::${pathname}`;
17395
- if (!fetchedContentPaths.has(pathCacheKey)) {
17396
- fetchedContentPaths.add(pathCacheKey);
17397
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17398
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17399
- if (!data?.content) return;
17400
- contentCache.set(subdomain, data.content);
17401
- applyFromCache();
17402
- }).catch(() => {
17403
- });
17404
- }
17405
16343
  observer = new MutationObserver(scheduleApply);
17406
16344
  observer.observe(document.body, { childList: true, subtree: true });
17407
16345
  return () => {
@@ -17415,10 +16353,10 @@ function OhhwellsBridge() {
17415
16353
  const visible = Boolean(subdomain) && fetchState !== "done";
17416
16354
  el.style.display = visible ? "flex" : "none";
17417
16355
  }, [subdomain, fetchState]);
17418
- useEffect13(() => {
16356
+ useEffect12(() => {
17419
16357
  postToParent2({ type: "ow:navigation", path: pathname });
17420
16358
  }, [pathname, postToParent2]);
17421
- useEffect13(() => {
16359
+ useEffect12(() => {
17422
16360
  if (!isEditMode) return;
17423
16361
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17424
16362
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17426,7 +16364,7 @@ function OhhwellsBridge() {
17426
16364
  deselectRef.current();
17427
16365
  deactivateRef.current();
17428
16366
  }, [pathname, isEditMode]);
17429
- useEffect13(() => {
16367
+ useEffect12(() => {
17430
16368
  const contentForNav = () => {
17431
16369
  if (isEditMode) return editContentRef.current;
17432
16370
  if (!subdomain) return {};
@@ -17493,36 +16431,31 @@ function OhhwellsBridge() {
17493
16431
  observer?.disconnect();
17494
16432
  };
17495
16433
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17496
- useEffect13(() => {
16434
+ useEffect12(() => {
17497
16435
  if (!isEditMode) return;
17498
- let lastPosted = 0;
17499
16436
  const measure = () => {
17500
16437
  const h = document.body.scrollHeight;
17501
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17502
- lastPosted = h;
17503
- postToParent2({ type: "ow:height", height: h });
17504
- }
17505
- };
17506
- let raf = null;
17507
- const schedule = () => {
17508
- if (raf != null) return;
17509
- raf = requestAnimationFrame(() => {
17510
- raf = null;
17511
- measure();
17512
- });
16438
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17513
16439
  };
17514
16440
  const t1 = setTimeout(measure, 50);
17515
16441
  const t2 = setTimeout(measure, 500);
17516
- const ro = new ResizeObserver(schedule);
17517
- ro.observe(document.body);
16442
+ let lastWidth = window.innerWidth;
16443
+ let resizeTimer = null;
16444
+ const handleResize = () => {
16445
+ if (window.innerWidth === lastWidth) return;
16446
+ lastWidth = window.innerWidth;
16447
+ if (resizeTimer) clearTimeout(resizeTimer);
16448
+ resizeTimer = setTimeout(measure, 150);
16449
+ };
16450
+ window.addEventListener("resize", handleResize);
17518
16451
  return () => {
17519
16452
  clearTimeout(t1);
17520
16453
  clearTimeout(t2);
17521
- if (raf != null) cancelAnimationFrame(raf);
17522
- ro.disconnect();
16454
+ if (resizeTimer) clearTimeout(resizeTimer);
16455
+ window.removeEventListener("resize", handleResize);
17523
16456
  };
17524
16457
  }, [pathname, isEditMode, postToParent2]);
17525
- useEffect13(() => {
16458
+ useEffect12(() => {
17526
16459
  if (!subdomainFromQuery || isEditMode) return;
17527
16460
  const handleClick = (e) => {
17528
16461
  const anchor = e.target.closest("a");
@@ -17538,7 +16471,7 @@ function OhhwellsBridge() {
17538
16471
  document.addEventListener("click", handleClick, true);
17539
16472
  return () => document.removeEventListener("click", handleClick, true);
17540
16473
  }, [subdomainFromQuery, isEditMode, router]);
17541
- useEffect13(() => {
16474
+ useEffect12(() => {
17542
16475
  if (!isEditMode) {
17543
16476
  editStylesRef.current?.base.remove();
17544
16477
  editStylesRef.current?.forceHover.remove();
@@ -17700,21 +16633,16 @@ function OhhwellsBridge() {
17700
16633
  return;
17701
16634
  }
17702
16635
  const target = e.target;
17703
- if (target.closest("[data-ohw-ai-review]")) return;
17704
16636
  if (target.closest("[data-ohw-toolbar]")) return;
17705
16637
  if (target.closest("[data-ohw-state-toggle]")) return;
17706
16638
  if (target.closest("[data-ohw-max-badge]")) return;
17707
16639
  if (isInsideLinkEditor(target)) return;
17708
- if (isInsideFloatingPanel(target)) return;
17709
16640
  if (target.closest("[data-ohw-form-toolbar]")) return;
17710
16641
  if (target.closest(
17711
16642
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17712
16643
  )) {
17713
16644
  return;
17714
16645
  }
17715
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
17716
- clearMediaSelectionRef.current();
17717
- }
17718
16646
  {
17719
16647
  const formEl = getFormElement(target);
17720
16648
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -17862,11 +16790,8 @@ function OhhwellsBridge() {
17862
16790
  if (isMediaEditable(editable) && !buttonOnMedia) {
17863
16791
  e.preventDefault();
17864
16792
  e.stopPropagation();
17865
- if (selectedMediaElRef.current === editable) {
17866
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17867
- } else {
17868
- selectMediaElementRef.current(editable);
17869
- }
16793
+ aiSectionApiRef.current?.selectFromElement(editable);
16794
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17870
16795
  return;
17871
16796
  }
17872
16797
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
@@ -17985,12 +16910,10 @@ function OhhwellsBridge() {
17985
16910
  };
17986
16911
  const handleDblClick = (e) => {
17987
16912
  const target = e.target;
17988
- if (target.closest("[data-ohw-ai-review]")) return;
17989
16913
  if (target.closest("[data-ohw-toolbar]")) return;
17990
16914
  if (target.closest("[data-ohw-state-toggle]")) return;
17991
16915
  if (target.closest("[data-ohw-max-badge]")) return;
17992
16916
  if (isInsideLinkEditor(target)) return;
17993
- if (isInsideFloatingPanel(target)) return;
17994
16917
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
17995
16918
  return;
17996
16919
  }
@@ -18031,14 +16954,11 @@ function OhhwellsBridge() {
18031
16954
  setSiblingHintRects([]);
18032
16955
  return;
18033
16956
  }
18034
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16957
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
18035
16958
  hoveredItemElRef.current = null;
18036
16959
  setHoveredItemRect(null);
18037
16960
  hoveredNavContainerRef.current = null;
18038
16961
  setHoveredNavContainerRect(null);
18039
- siblingHintElRef.current = null;
18040
- setSiblingHintRect(null);
18041
- setSiblingHintRects([]);
18042
16962
  return;
18043
16963
  }
18044
16964
  {
@@ -18056,16 +16976,6 @@ function OhhwellsBridge() {
18056
16976
  return;
18057
16977
  }
18058
16978
  }
18059
- if (allowNavContainerHover) {
18060
- const socialsRow = isSocialsRow(target) ? target : null;
18061
- if (socialsRow && !getSocialItem(target) && selected2 !== socialsRow) {
18062
- hoveredNavContainerRef.current = socialsRow;
18063
- setHoveredNavContainerRect(socialsRow.getBoundingClientRect());
18064
- hoveredItemElRef.current = null;
18065
- setHoveredItemRect(null);
18066
- return;
18067
- }
18068
- }
18069
16979
  if (allowFooterLinksHover) {
18070
16980
  const navContainer = target.closest("[data-ohw-nav-container]");
18071
16981
  if (!navContainer) {
@@ -18151,12 +17061,13 @@ function OhhwellsBridge() {
18151
17061
  clearHrefKeyHover(hoverTarget);
18152
17062
  hoveredItemElRef.current = hoverTarget;
18153
17063
  setHoveredItemRect(hoverTarget.getBoundingClientRect());
18154
- } else if (!isInsideNavigationItem(editable) && hoverTarget !== selectedElRef.current) {
17064
+ } else if (!isInsideNavigationItem(editable)) {
18155
17065
  hoverTarget.setAttribute("data-ohw-hovered", "");
18156
17066
  if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
18157
17067
  hoveredNavContainerRef.current = null;
18158
17068
  setHoveredNavContainerRect(null);
18159
17069
  hoveredItemElRef.current = editable;
17070
+ setHoveredItemRect(editable.getBoundingClientRect());
18160
17071
  }
18161
17072
  }
18162
17073
  }
@@ -18453,7 +17364,7 @@ function OhhwellsBridge() {
18453
17364
  }
18454
17365
  };
18455
17366
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18456
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17367
+ if (linkPopoverOpenRef.current) {
18457
17368
  if (hoveredImageRef.current) {
18458
17369
  hoveredImageRef.current = null;
18459
17370
  hoveredImageHasTextOverlapRef.current = false;
@@ -18712,7 +17623,7 @@ function OhhwellsBridge() {
18712
17623
  }
18713
17624
  };
18714
17625
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18715
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17626
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18716
17627
  if (activeStateElRef.current) {
18717
17628
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18718
17629
  activeStateElRef.current = null;
@@ -18749,35 +17660,6 @@ function OhhwellsBridge() {
18749
17660
  }
18750
17661
  }
18751
17662
  };
18752
- const probeSocialsRowAt = (clientX, clientY, fromParentViewport = false) => {
18753
- const wasSocialsRow = Boolean(hoveredNavContainerRef.current?.hasAttribute(SOCIALS_ROW_ATTR));
18754
- const clear = () => {
18755
- if (!wasSocialsRow) return false;
18756
- hoveredNavContainerRef.current = null;
18757
- setHoveredNavContainerRect(null);
18758
- return false;
18759
- };
18760
- if (linkPopoverOpenRef.current || toolbarVariantRef.current === "select-frame") return clear();
18761
- const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
18762
- const SLACK = 6;
18763
- for (const row of Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`))) {
18764
- const rect = row.getBoundingClientRect();
18765
- const inside = x >= rect.left - SLACK && x <= rect.right + SLACK && y >= rect.top - SLACK && y <= rect.bottom + SLACK;
18766
- if (!inside) continue;
18767
- if (selectedElRef.current === row) return clear();
18768
- const overItem = listSocialItems(row).some((item) => {
18769
- const box = item.getBoundingClientRect();
18770
- return x >= box.left && x <= box.right && y >= box.top && y <= box.bottom;
18771
- });
18772
- if (overItem) return clear();
18773
- hoveredNavContainerRef.current = row;
18774
- setHoveredNavContainerRect(rect);
18775
- hoveredItemElRef.current = null;
18776
- setHoveredItemRect(null);
18777
- return true;
18778
- }
18779
- return clear();
18780
- };
18781
17663
  const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
18782
17664
  if (linkPopoverOpenRef.current) {
18783
17665
  if (hoveredGapRef.current) {
@@ -18787,9 +17669,7 @@ function OhhwellsBridge() {
18787
17669
  return;
18788
17670
  }
18789
17671
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
18790
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
18791
- (el) => !el.hasAttribute("data-ohw-ai-template-hidden") && !el.hasAttribute("data-ohw-ai-removed") && !el.hasAttribute("data-ohw-ai-replaced-by") && el.getBoundingClientRect().height > 0
18792
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
17672
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18793
17673
  const ZONE = 20;
18794
17674
  for (let i = 0; i < sections.length; i++) {
18795
17675
  const a = sections[i];
@@ -18818,7 +17698,8 @@ function OhhwellsBridge() {
18818
17698
  };
18819
17699
  const handleMouseMove = (e) => {
18820
17700
  const { clientX, clientY } = e;
18821
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17701
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17702
+ if (isOverEditorChrome(clientX, clientY)) {
18822
17703
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18823
17704
  formHoverElRef.current = null;
18824
17705
  setFormHoverRect(null);
@@ -18826,15 +17707,8 @@ function OhhwellsBridge() {
18826
17707
  setHoveredItemRect(null);
18827
17708
  hoveredNavContainerRef.current = null;
18828
17709
  setHoveredNavContainerRect(null);
18829
- siblingHintElRef.current = null;
18830
- setSiblingHintRect(null);
18831
- setSiblingHintRects([]);
18832
- dismissImageHover();
18833
- clearImageHover();
18834
- setSectionGap(null);
18835
17710
  return;
18836
17711
  }
18837
- if (probeSocialsRowAt(clientX, clientY)) return;
18838
17712
  probeSectionGapAt(clientX, clientY);
18839
17713
  probeImageAt(clientX, clientY);
18840
17714
  probeHoverCardsAt(clientX, clientY);
@@ -18843,12 +17717,7 @@ function OhhwellsBridge() {
18843
17717
  if (e.data?.type !== "ow:pointer-sync") return;
18844
17718
  const { clientX, clientY } = e.data;
18845
17719
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18846
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18847
- dismissImageHover();
18848
- clearImageHover();
18849
- return;
18850
- }
18851
- if (probeSocialsRowAt(clientX, clientY)) return;
17720
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18852
17721
  probeSectionGapAt(clientX, clientY);
18853
17722
  probeImageAt(clientX, clientY);
18854
17723
  probeHoverCardsAt(clientX, clientY);
@@ -19094,19 +17963,10 @@ function OhhwellsBridge() {
19094
17963
  if (e.data?.type !== "ow:hydrate") return;
19095
17964
  const content = e.data.content;
19096
17965
  if (!content) return;
19097
- if (typeof content[BRAND_KIT_KEY] === "string") {
19098
- brandKitRef.current = content[BRAND_KIT_KEY];
19099
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19100
- }
19101
17966
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19102
17967
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19103
17968
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19104
17969
  }
19105
- if (typeof content[STYLE_STORE_KEY] === "string") {
19106
- stylesRef.current = content[STYLE_STORE_KEY];
19107
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19108
- }
19109
- applyBrandChrome(content);
19110
17970
  let sectionsJson = null;
19111
17971
  for (const [key, val] of Object.entries(content)) {
19112
17972
  if (key === "__ohw_sections") {
@@ -19116,9 +17976,6 @@ function OhhwellsBridge() {
19116
17976
  if (key === AI_SECTIONS_KEY) continue;
19117
17977
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19118
17978
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19119
- if (key === BRAND_KIT_KEY) continue;
19120
- if (key === STYLE_STORE_KEY) continue;
19121
- if (BRAND_CHROME_KEYS.has(key)) continue;
19122
17979
  if (applyVideoSettingNode(key, val)) continue;
19123
17980
  if (applyCarouselNode(key, val)) continue;
19124
17981
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19215,21 +18072,12 @@ function OhhwellsBridge() {
19215
18072
  nodes: collectEditableNodes(editContentRef.current)
19216
18073
  });
19217
18074
  };
19218
- const clearInteractionChrome = () => {
19219
- deactivateRef.current();
19220
- deselectRef.current();
19221
- clearMediaSelectionRef.current();
19222
- };
19223
18075
  const handleAiApplyTree = (e) => {
19224
18076
  if (e.data?.type !== "ow:ai-apply-tree") return;
19225
18077
  const payload = e.data.payload;
19226
18078
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19227
- clearInteractionChrome();
19228
18079
  const previous = aiSectionsRef.current;
19229
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19230
- ...payload,
19231
- path: payload.path ?? window.location.pathname
19232
- });
18080
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19233
18081
  const nextValue = serializeAiSectionsState(nextState);
19234
18082
  aiSectionsRef.current = nextValue;
19235
18083
  applyAiSectionsToDom(nextState);
@@ -19249,7 +18097,6 @@ function OhhwellsBridge() {
19249
18097
  if (!sectionId || sectionId === "navbar" || sectionId === "footer") return;
19250
18098
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
19251
18099
  if (!exists) return;
19252
- clearInteractionChrome();
19253
18100
  const previous = aiSectionsRef.current;
19254
18101
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
19255
18102
  const nextValue = serializeAiSectionsState(nextState);
@@ -19265,58 +18112,14 @@ function OhhwellsBridge() {
19265
18112
  const handleAiSetSections = (e) => {
19266
18113
  if (e.data?.type !== "ow:ai-set-sections") return;
19267
18114
  const value = typeof e.data.value === "string" ? e.data.value : "";
19268
- clearInteractionChrome();
19269
18115
  aiSectionsRef.current = value;
19270
18116
  applyAiSectionsToDom(parseAiSectionsState(value));
19271
- applyStylesToDom(parseStyleStore(stylesRef.current));
19272
18117
  const restoredHeight = document.documentElement.scrollHeight;
19273
18118
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19274
18119
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19275
18120
  postAiSectionsChanged();
19276
18121
  };
19277
18122
  window.addEventListener("message", handleAiSetSections);
19278
- const handleMoveSection = (e) => {
19279
- if (e.data?.type !== "ow:move-section") return;
19280
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19281
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19282
- if (!instanceId || !direction) return;
19283
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19284
- if (!entries) return;
19285
- const orderJson = JSON.stringify(entries);
19286
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19287
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19288
- window.dispatchEvent(new Event("resize"));
19289
- };
19290
- window.addEventListener("message", handleMoveSection);
19291
- const handleAiSetBrand = (e) => {
19292
- if (e.data?.type !== "ow:ai-set-brand") return;
19293
- const value = typeof e.data.value === "string" ? e.data.value : "";
19294
- const previous = brandKitRef.current;
19295
- brandKitRef.current = value;
19296
- applyBrandToDom(parseBrandKit(value));
19297
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19298
- applyStylesToDom(parseStyleStore(stylesRef.current));
19299
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19300
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19301
- };
19302
- window.addEventListener("message", handleAiSetBrand);
19303
- const handleAiSetStyles = (e) => {
19304
- if (e.data?.type !== "ow:ai-set-styles") return;
19305
- const value = typeof e.data.value === "string" ? e.data.value : "";
19306
- const previous = stylesRef.current;
19307
- stylesRef.current = value;
19308
- applyStylesToDom(parseStyleStore(value));
19309
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19310
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19311
- };
19312
- window.addEventListener("message", handleAiSetStyles);
19313
- const handleGetBrand = (e) => {
19314
- if (e.data?.type !== "ow:get-brand") return;
19315
- const template = deriveTemplateBrand();
19316
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19317
- postToParentRef.current({ type: "ow:brand-value", value });
19318
- };
19319
- window.addEventListener("message", handleGetBrand);
19320
18123
  const handlePanelDragging = (e) => {
19321
18124
  if (e.data?.type !== "ow:panel-dragging") return;
19322
18125
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
@@ -19332,12 +18135,6 @@ function OhhwellsBridge() {
19332
18135
  closeLinkPopoverRef.current();
19333
18136
  return;
19334
18137
  }
19335
- if (floatingPanelOpenRef.current) {
19336
- setFloatingPanelRef.current(null);
19337
- deselectRef.current();
19338
- deactivateRef.current();
19339
- return;
19340
- }
19341
18138
  deselectRef.current();
19342
18139
  deactivateRef.current();
19343
18140
  };
@@ -19425,10 +18222,6 @@ function OhhwellsBridge() {
19425
18222
  const handleKeyDown = (e) => {
19426
18223
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19427
18224
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19428
- if (e.key === "Escape" && selectedMediaElRef.current) {
19429
- clearMediaSelectionRef.current();
19430
- return;
19431
- }
19432
18225
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19433
18226
  e.preventDefault();
19434
18227
  selectAllTextInEditable(activeElRef.current);
@@ -19588,12 +18381,6 @@ function OhhwellsBridge() {
19588
18381
  if (aiSectionsRef.current) {
19589
18382
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19590
18383
  }
19591
- if (stylesRef.current) {
19592
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19593
- }
19594
- if (brandKitRef.current) {
19595
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19596
- }
19597
18384
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19598
18385
  const formKey = formKeyOf(form);
19599
18386
  if (!formKey) return;
@@ -19611,12 +18398,8 @@ function OhhwellsBridge() {
19611
18398
  if (inserted) {
19612
18399
  const tracker = getSectionsTracker();
19613
18400
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19614
- const reportHeight = () => {
19615
- const h = document.body.scrollHeight;
19616
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19617
- };
19618
- reportHeight();
19619
- setTimeout(reportHeight, 500);
18401
+ const h = document.documentElement.scrollHeight;
18402
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19620
18403
  }
19621
18404
  };
19622
18405
  const handleSwitchSchedule = (e) => {
@@ -20003,23 +18786,19 @@ function OhhwellsBridge() {
20003
18786
  window.removeEventListener("message", handleAiApplyTree);
20004
18787
  window.removeEventListener("message", handleAiDeleteSection);
20005
18788
  window.removeEventListener("message", handleAiSetSections);
20006
- window.removeEventListener("message", handleMoveSection);
20007
- window.removeEventListener("message", handleAiSetBrand);
20008
- window.removeEventListener("message", handleAiSetStyles);
20009
- window.removeEventListener("message", handleGetBrand);
20010
18789
  window.removeEventListener("message", handlePanelDragging);
20011
18790
  window.removeEventListener("message", handleDeactivate);
18791
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
20012
18792
  window.removeEventListener("message", handleToastAction);
20013
18793
  window.removeEventListener("message", handleFormCount);
20014
18794
  window.removeEventListener("message", handleUiEscape);
20015
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
20016
18795
  autoSaveTimers.current.forEach(clearTimeout);
20017
18796
  autoSaveTimers.current.clear();
20018
18797
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
20019
18798
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
20020
18799
  };
20021
18800
  }, [isEditMode, refreshStateRules]);
20022
- useEffect13(() => {
18801
+ useEffect12(() => {
20023
18802
  if (!isEditMode) return;
20024
18803
  const THRESHOLD = 10;
20025
18804
  const resolveWasSelected = (el) => {
@@ -20175,7 +18954,7 @@ function OhhwellsBridge() {
20175
18954
  unlockFooterDragInteraction();
20176
18955
  };
20177
18956
  }, [isEditMode]);
20178
- useEffect13(() => {
18957
+ useEffect12(() => {
20179
18958
  const handler = (e) => {
20180
18959
  if (e.data?.type !== "ow:request-schedule-config") return;
20181
18960
  const insertAfterVal = e.data.insertAfter;
@@ -20191,7 +18970,7 @@ function OhhwellsBridge() {
20191
18970
  window.addEventListener("message", handler);
20192
18971
  return () => window.removeEventListener("message", handler);
20193
18972
  }, [processConfigRequest]);
20194
- useEffect13(() => {
18973
+ useEffect12(() => {
20195
18974
  if (!isEditMode) return;
20196
18975
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20197
18976
  el.removeAttribute("data-ohw-active-state");
@@ -20215,7 +18994,7 @@ function OhhwellsBridge() {
20215
18994
  postToParent2({
20216
18995
  type: "ow:ready",
20217
18996
  version: "1",
20218
- bridgeVersion: "0.1.68",
18997
+ bridgeVersion: "0.1.67",
20219
18998
  path: pathname,
20220
18999
  nodes: collectEditableNodes(editContentRef.current),
20221
19000
  sections
@@ -20227,13 +19006,13 @@ function OhhwellsBridge() {
20227
19006
  clearTimeout(timer);
20228
19007
  };
20229
19008
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20230
- useEffect13(() => {
19009
+ useEffect12(() => {
20231
19010
  scrollToHashSectionWhenReady();
20232
19011
  const onHashChange = () => scrollToHashSectionWhenReady();
20233
19012
  window.addEventListener("hashchange", onHashChange);
20234
19013
  return () => window.removeEventListener("hashchange", onHashChange);
20235
19014
  }, [pathname]);
20236
- const handleCommand = useCallback8((cmd) => {
19015
+ const handleCommand = useCallback7((cmd) => {
20237
19016
  const el = activeElRef.current;
20238
19017
  const selBefore = window.getSelection();
20239
19018
  let savedOffsets = null;
@@ -20269,7 +19048,7 @@ function OhhwellsBridge() {
20269
19048
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20270
19049
  refreshActiveCommandsRef.current();
20271
19050
  }, []);
20272
- useEffect13(() => {
19051
+ useEffect12(() => {
20273
19052
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20274
19053
  if (!session || !logoSizeDraft) return;
20275
19054
  const onPanelAction = (e) => {
@@ -20307,7 +19086,7 @@ function OhhwellsBridge() {
20307
19086
  window.addEventListener("message", onPanelAction);
20308
19087
  return () => window.removeEventListener("message", onPanelAction);
20309
19088
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20310
- const handleStateChange = useCallback8((state) => {
19089
+ const handleStateChange = useCallback7((state) => {
20311
19090
  if (!activeStateElRef.current) return;
20312
19091
  const el = activeStateElRef.current;
20313
19092
  if (state === "Default") {
@@ -20320,7 +19099,7 @@ function OhhwellsBridge() {
20320
19099
  }
20321
19100
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20322
19101
  }, [deactivate]);
20323
- const reselectAfterLinkPopover = useCallback8(
19102
+ const reselectAfterLinkPopover = useCallback7(
20324
19103
  (hrefKey) => {
20325
19104
  requestAnimationFrame(() => {
20326
19105
  const el = resolveHrefKeyElement(hrefKey);
@@ -20329,7 +19108,7 @@ function OhhwellsBridge() {
20329
19108
  },
20330
19109
  [resolveHrefKeyElement]
20331
19110
  );
20332
- const closeLinkPopover = useCallback8(() => {
19111
+ const closeLinkPopover = useCallback7(() => {
20333
19112
  const session = linkPopoverSessionRef.current;
20334
19113
  addNavAfterAnchorRef.current = null;
20335
19114
  setLinkPopover(null);
@@ -20337,9 +19116,9 @@ function OhhwellsBridge() {
20337
19116
  reselectAfterLinkPopover(session.key);
20338
19117
  }
20339
19118
  }, [reselectAfterLinkPopover]);
20340
- const closeLinkPopoverRef = useRef10(closeLinkPopover);
19119
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
20341
19120
  closeLinkPopoverRef.current = closeLinkPopover;
20342
- const openLinkPopoverForActive = useCallback8(() => {
19121
+ const openLinkPopoverForActive = useCallback7(() => {
20343
19122
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20344
19123
  if (!hrefCtx) return;
20345
19124
  bumpLinkPopoverGrace();
@@ -20350,7 +19129,7 @@ function OhhwellsBridge() {
20350
19129
  });
20351
19130
  deactivate();
20352
19131
  }, [deactivate]);
20353
- const openLinkPopoverForSelected = useCallback8(() => {
19132
+ const openLinkPopoverForSelected = useCallback7(() => {
20354
19133
  const anchor = selectedElRef.current;
20355
19134
  if (!anchor) return;
20356
19135
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20367,7 +19146,7 @@ function OhhwellsBridge() {
20367
19146
  });
20368
19147
  deselect();
20369
19148
  }, [deselect]);
20370
- const handleSelectParent = useCallback8(() => {
19149
+ const handleSelectParent = useCallback7(() => {
20371
19150
  const selected = selectedElRef.current;
20372
19151
  if (!selected) return;
20373
19152
  if (toolbarVariantRef.current === "select-frame") {
@@ -20394,7 +19173,7 @@ function OhhwellsBridge() {
20394
19173
  }
20395
19174
  deselectRef.current();
20396
19175
  }, []);
20397
- const handleDuplicateSelected = useCallback8(() => {
19176
+ const handleDuplicateSelected = useCallback7(() => {
20398
19177
  const selected = selectedElRef.current;
20399
19178
  if (!selected || !isNavigationItem2(selected)) return;
20400
19179
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20510,7 +19289,7 @@ function OhhwellsBridge() {
20510
19289
  });
20511
19290
  }
20512
19291
  }, [postToParent2]);
20513
- const runPendingDeleteUndo = useCallback8(() => {
19292
+ const runPendingDeleteUndo = useCallback7(() => {
20514
19293
  const pending = pendingDeleteUndoRef.current;
20515
19294
  if (!pending) return false;
20516
19295
  pendingDeleteUndoRef.current = null;
@@ -20518,7 +19297,7 @@ function OhhwellsBridge() {
20518
19297
  enforceLinkHrefs();
20519
19298
  return true;
20520
19299
  }, []);
20521
- const handleDeleteSelected = useCallback8(() => {
19300
+ const handleDeleteSelected = useCallback7(() => {
20522
19301
  const selected = selectedElRef.current;
20523
19302
  if (!selected) return false;
20524
19303
  return deleteSelectedNavFooterItem({
@@ -20539,7 +19318,7 @@ function OhhwellsBridge() {
20539
19318
  }, [postToParent2]);
20540
19319
  handleDeleteSelectedRef.current = handleDeleteSelected;
20541
19320
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20542
- const handleLinkPopoverSubmit = useCallback8(
19321
+ const handleLinkPopoverSubmit = useCallback7(
20543
19322
  (target) => {
20544
19323
  const session = linkPopoverSessionRef.current;
20545
19324
  if (!session) return;
@@ -20605,30 +19384,19 @@ function OhhwellsBridge() {
20605
19384
  const showEditLink = toolbarShowEditLink;
20606
19385
  const currentSections = sectionsByPath[pathname] ?? [];
20607
19386
  linkPopoverOpenRef.current = linkPopover !== null;
20608
- const handleMediaSelect = useCallback8((key) => {
20609
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
20610
- (m) => (m.dataset.ohwKey ?? "") === key
20611
- ) ?? null;
20612
- if (!el) return;
20613
- selectMediaElementRef.current(el);
20614
- }, []);
20615
- const handleMediaReplace = useCallback8(
19387
+ const handleMediaReplace = useCallback7(
20616
19388
  (key) => {
20617
- postToParent2({
20618
- type: "ow:image-pick",
20619
- key,
20620
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
20621
- });
19389
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20622
19390
  },
20623
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19391
+ [postToParent2, mediaHover?.elementType]
20624
19392
  );
20625
- const handleEditCarousel = useCallback8(
19393
+ const handleEditCarousel = useCallback7(
20626
19394
  (key) => {
20627
19395
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20628
19396
  },
20629
19397
  [postToParent2]
20630
19398
  );
20631
- const handleMediaFadeOutComplete = useCallback8((key) => {
19399
+ const handleMediaFadeOutComplete = useCallback7((key) => {
20632
19400
  setUploadingRects((prev) => {
20633
19401
  if (!(key in prev)) return prev;
20634
19402
  const next = { ...prev };
@@ -20636,7 +19404,7 @@ function OhhwellsBridge() {
20636
19404
  return next;
20637
19405
  });
20638
19406
  }, []);
20639
- const handleVideoSettingsChange = useCallback8(
19407
+ const handleVideoSettingsChange = useCallback7(
20640
19408
  (key, settings) => {
20641
19409
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20642
19410
  const video = getVideoEl2(el);
@@ -20658,506 +19426,420 @@ function OhhwellsBridge() {
20658
19426
  },
20659
19427
  [postToParent2]
20660
19428
  );
20661
- return /* @__PURE__ */ jsxs20(Fragment8, { children: [
20662
- /* @__PURE__ */ jsx33("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ jsx33(OhwLoaderSpinner, {}) }),
20663
- /* @__PURE__ */ jsx33("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20664
- bridgeRoot ? createPortal2(
20665
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
20666
- /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20667
- isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20668
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20669
- "div",
20670
- {
20671
- className: "pointer-events-none fixed z-2147483646",
20672
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20673
- children: /* @__PURE__ */ jsx33(
20674
- DropIndicator,
20675
- {
20676
- direction: "horizontal",
20677
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20678
- className: "!h-full !w-full"
20679
- }
20680
- )
20681
- },
20682
- `section-drop-${slot.insertIndex}-${i}`
20683
- )),
20684
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
20685
- MediaOverlay,
20686
- {
20687
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20688
- isUploading: true,
20689
- fadingOut,
20690
- onFadeOutComplete: handleMediaFadeOutComplete,
20691
- onReplace: handleMediaReplace
20692
- },
20693
- `uploading-${key}`
20694
- )),
20695
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ jsx33(
20696
- MediaOverlay,
20697
- {
20698
- hover: mediaHover,
20699
- isUploading: false,
20700
- onReplace: handleMediaReplace,
20701
- onSelect: handleMediaSelect,
20702
- onVideoSettingsChange: handleVideoSettingsChange
20703
- }
20704
- ),
20705
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ jsx33(
20706
- MediaOverlay,
20707
- {
20708
- hover: selectedMedia,
20709
- selected: true,
20710
- hovered: mediaHover?.key === selectedMedia.key,
20711
- isUploading: false,
20712
- onReplace: handleMediaReplace,
20713
- onSelect: handleMediaSelect,
20714
- onVideoSettingsChange: handleVideoSettingsChange
20715
- }
20716
- ),
20717
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20718
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20719
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20720
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20721
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20722
- "div",
20723
- {
20724
- className: "pointer-events-none fixed z-2147483646",
20725
- style: {
20726
- left: slot.left,
20727
- top: slot.top,
20728
- width: slot.width,
20729
- height: slot.height
20730
- },
20731
- children: /* @__PURE__ */ jsx33(
20732
- DropIndicator,
20733
- {
20734
- direction: slot.direction,
20735
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20736
- className: "!h-full !w-full"
20737
- }
20738
- )
20739
- },
20740
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20741
- )),
20742
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20743
- "div",
20744
- {
20745
- className: "pointer-events-none fixed z-2147483646",
20746
- style: {
20747
- left: slot.left,
20748
- top: slot.top,
20749
- width: slot.width,
20750
- height: slot.height
20751
- },
20752
- children: /* @__PURE__ */ jsx33(
20753
- DropIndicator,
20754
- {
20755
- direction: slot.direction,
20756
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20757
- className: "!h-full !w-full"
20758
- }
20759
- )
19429
+ return bridgeRoot ? createPortal2(
19430
+ /* @__PURE__ */ jsxs20(Fragment8, { children: [
19431
+ /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19432
+ isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19433
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
19434
+ MediaOverlay,
19435
+ {
19436
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19437
+ isUploading: true,
19438
+ fadingOut,
19439
+ onFadeOutComplete: handleMediaFadeOutComplete,
19440
+ onReplace: handleMediaReplace
19441
+ },
19442
+ `uploading-${key}`
19443
+ )),
19444
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
19445
+ MediaOverlay,
19446
+ {
19447
+ hover: mediaHover,
19448
+ isUploading: false,
19449
+ onReplace: handleMediaReplace,
19450
+ onVideoSettingsChange: handleVideoSettingsChange
19451
+ }
19452
+ ),
19453
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19454
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19455
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19456
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19457
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19458
+ "div",
19459
+ {
19460
+ className: "pointer-events-none fixed z-2147483646",
19461
+ style: {
19462
+ left: slot.left,
19463
+ top: slot.top,
19464
+ width: slot.width,
19465
+ height: slot.height
20760
19466
  },
20761
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20762
- )),
20763
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20764
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20765
- hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20766
- formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
20767
- ItemInteractionLayer,
20768
- {
20769
- rect: formPickRect,
20770
- state: "active-top",
20771
- itemDragSurface: false,
20772
- toolbarAlign: "left",
20773
- chromeGap: 24,
20774
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
20775
- "div",
20776
- {
20777
- "data-ohw-form-toolbar": "",
20778
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20779
- children: [
20780
- /* @__PURE__ */ jsx33(
20781
- "button",
20782
- {
20783
- type: "button",
20784
- "aria-label": "Add field",
20785
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20786
- onClick: () => setFieldTypePickerOpen((open) => !open),
20787
- "data-ohw-add-field": "",
20788
- children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
20789
- }
20790
- ),
20791
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20792
- /* @__PURE__ */ jsxs20(
20793
- "button",
20794
- {
20795
- type: "button",
20796
- className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-semibold text-foreground transition-colors hover:bg-muted/80",
20797
- onClick: () => {
20798
- const form = formPickElRef.current;
20799
- if (!form) return;
20800
- postToParent2({
20801
- type: "ow:form-pick",
20802
- formKey: formKeyOf(form),
20803
- hasLongText: formHasLongText(form)
20804
- });
20805
- },
20806
- children: [
20807
- /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
20808
- "Form settings",
20809
- formPickCount ? (
20810
- // Counter pill, per the design — not a text suffix.
20811
- /* @__PURE__ */ jsx33(
20812
- "span",
20813
- {
20814
- "data-ohw-form-count": "",
20815
- className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
20816
- children: formPickCount
20817
- }
20818
- )
20819
- ) : null
20820
- ]
20821
- }
20822
- ),
20823
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20824
- /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
20825
- "button",
20826
- {
20827
- type: "button",
20828
- "aria-pressed": formViewState === state,
20829
- className: "rounded-md px-2.5 py-1 text-[13px] font-semibold capitalize transition-colors " + (formViewState === state ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
20830
- onClick: () => {
20831
- const form = formPickElRef.current;
20832
- const key = form ? formKeyOf(form) : null;
20833
- if (!form || !key) return;
20834
- const initial = successInitialFor(form, key, editContentRef.current);
20835
- setFormViewState(form, key, state, initial);
20836
- setFormViewStateUi(state);
20837
- setFormPickRect(form.getBoundingClientRect());
20838
- if (state === "success") {
20839
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20840
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20841
- } else {
20842
- deactivateRef.current();
20843
- }
20844
- },
20845
- children: state
20846
- },
20847
- state
20848
- )) })
20849
- ]
20850
- }
20851
- )
20852
- }
20853
- ),
20854
- formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
20855
- ItemInteractionLayer,
20856
- {
20857
- rect: formHoverRect,
20858
- state: "hover",
20859
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20860
- }
20861
- ),
20862
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
20863
- ItemInteractionLayer,
20864
- {
20865
- rect: fieldPickRect,
20866
- state: fieldDragging ? "dragging" : "active-top",
20867
- itemDragSurface: false,
20868
- toolbarAlign: "left",
20869
- chromeGap: 10,
20870
- showHandle: true,
20871
- dragHandleLabel: "Reorder field",
20872
- onDragHandleDragStart: handleFieldDragStart,
20873
- onDragHandleDragEnd: handleFieldDragEnd,
20874
- toolbar: /* @__PURE__ */ jsx33(
20875
- FormFieldToolbar,
20876
- {
20877
- type: fieldPickState.type,
20878
- required: fieldPickState.required,
20879
- onTypeChange: handleFieldTypeChange,
20880
- onRequiredToggle: handleFieldRequiredToggle,
20881
- onDuplicate: handleFieldDuplicate,
20882
- onDelete: handleFieldDelete
20883
- }
20884
- )
20885
- }
20886
- ),
20887
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20888
- "div",
20889
- {
20890
- className: "pointer-events-none fixed z-[2147483644]",
20891
- style: { top: slot.top, left: slot.left, width: slot.width },
20892
- children: /* @__PURE__ */ jsx33(
20893
- DropIndicator,
20894
- {
20895
- direction: "horizontal",
20896
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20897
- className: "!w-full"
20898
- }
20899
- )
19467
+ children: /* @__PURE__ */ jsx33(
19468
+ DropIndicator,
19469
+ {
19470
+ direction: slot.direction,
19471
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19472
+ className: "!h-full !w-full"
19473
+ }
19474
+ )
19475
+ },
19476
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19477
+ )),
19478
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19479
+ "div",
19480
+ {
19481
+ className: "pointer-events-none fixed z-2147483646",
19482
+ style: {
19483
+ left: slot.left,
19484
+ top: slot.top,
19485
+ width: slot.width,
19486
+ height: slot.height
20900
19487
  },
20901
- `field-drop-${i}`
20902
- )) : null,
20903
- fieldTypePickerOpen && formPickRect ? (() => {
20904
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20905
- return /* @__PURE__ */ jsx33(
20906
- "div",
19488
+ children: /* @__PURE__ */ jsx33(
19489
+ DropIndicator,
20907
19490
  {
20908
- className: "pointer-events-none fixed z-[2147483645]",
20909
- style: {
20910
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20911
- left: toolbar ? toolbar.left : formPickRect.left + 24
20912
- },
20913
- children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
19491
+ direction: slot.direction,
19492
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19493
+ className: "!h-full !w-full"
20914
19494
  }
20915
- );
20916
- })() : null,
20917
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20918
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
20919
- FooterContainerChrome,
20920
- {
20921
- rect: toolbarRect,
20922
- onAdd: handleAddFooterColumn,
20923
- addDisabled: !canAddFooterColumn()
20924
- }
20925
- ),
20926
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
20927
- ItemInteractionLayer,
20928
- {
20929
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20930
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20931
- elRef: glowElRef,
20932
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20933
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20934
- dragDisabled: reorderDragDisabled,
20935
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20936
- onDragHandleDragStart: handleItemDragStart,
20937
- onDragHandleDragEnd: handleItemDragEnd,
20938
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20939
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20940
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20941
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
20942
- ItemActionToolbar,
20943
- {
20944
- onEditLink: openLinkPopoverForSelected,
20945
- onStyle: () => {
20946
- const row = selectedElRef.current;
20947
- if (!row) return;
20948
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20949
- else openSocialsDisplayPanel(row);
20950
- },
20951
- showStyle: selectedIsSocialsRow,
20952
- styleActive: floatingPanel?.kind === "socials-display",
20953
- onAddItem: handleAddChildItem,
20954
- onSelectParent: handleSelectParent,
20955
- onDuplicate: handleDuplicateSelected,
20956
- onDelete: handleDeleteSelected,
20957
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20958
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20959
- return row ? !canAddSocialItem(row) : false;
20960
- })(),
20961
- editLinkDisabled: false,
20962
- moreDisabled: false,
20963
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20964
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20965
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20966
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19495
+ )
19496
+ },
19497
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19498
+ )),
19499
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19500
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19501
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19502
+ formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
19503
+ ItemInteractionLayer,
19504
+ {
19505
+ rect: formPickRect,
19506
+ state: "active-top",
19507
+ itemDragSurface: false,
19508
+ toolbarAlign: "left",
19509
+ chromeGap: 24,
19510
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
19511
+ "div",
19512
+ {
19513
+ "data-ohw-form-toolbar": "",
19514
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19515
+ children: [
19516
+ /* @__PURE__ */ jsx33(
19517
+ "button",
19518
+ {
19519
+ type: "button",
19520
+ "aria-label": "Add field",
19521
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19522
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19523
+ "data-ohw-add-field": "",
19524
+ children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
19525
+ }
20967
19526
  ),
20968
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20969
- dropdownOpen: navDropdownPreviewOpen,
20970
- onDropdownOpenChange: handleNavDropdownOpenChange,
20971
- headingVisible: footerHeadingVisible,
20972
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20973
- }
20974
- ) : void 0
20975
- }
20976
- ),
20977
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
20978
- /* @__PURE__ */ jsx33(
20979
- EditGlowChrome,
19527
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19528
+ /* @__PURE__ */ jsxs20(
19529
+ "button",
19530
+ {
19531
+ type: "button",
19532
+ className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-semibold text-foreground transition-colors hover:bg-muted/80",
19533
+ onClick: () => {
19534
+ const form = formPickElRef.current;
19535
+ if (!form) return;
19536
+ postToParent2({
19537
+ type: "ow:form-pick",
19538
+ formKey: formKeyOf(form),
19539
+ hasLongText: formHasLongText(form)
19540
+ });
19541
+ },
19542
+ children: [
19543
+ /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
19544
+ "Form settings",
19545
+ formPickCount ? (
19546
+ // Counter pill, per the design — not a text suffix.
19547
+ /* @__PURE__ */ jsx33(
19548
+ "span",
19549
+ {
19550
+ "data-ohw-form-count": "",
19551
+ className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
19552
+ children: formPickCount
19553
+ }
19554
+ )
19555
+ ) : null
19556
+ ]
19557
+ }
19558
+ ),
19559
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19560
+ /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
19561
+ "button",
19562
+ {
19563
+ type: "button",
19564
+ "aria-pressed": formViewState === state,
19565
+ className: "rounded-md px-2.5 py-1 text-[13px] font-semibold capitalize transition-colors " + (formViewState === state ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
19566
+ onClick: () => {
19567
+ const form = formPickElRef.current;
19568
+ const key = form ? formKeyOf(form) : null;
19569
+ if (!form || !key) return;
19570
+ const initial = successInitialFor(form, key, editContentRef.current);
19571
+ setFormViewState(form, key, state, initial);
19572
+ setFormViewStateUi(state);
19573
+ setFormPickRect(form.getBoundingClientRect());
19574
+ if (state === "success") {
19575
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19576
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19577
+ } else {
19578
+ deactivateRef.current();
19579
+ }
19580
+ },
19581
+ children: state
19582
+ },
19583
+ state
19584
+ )) })
19585
+ ]
19586
+ }
19587
+ )
19588
+ }
19589
+ ),
19590
+ formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
19591
+ ItemInteractionLayer,
19592
+ {
19593
+ rect: formHoverRect,
19594
+ state: "hover",
19595
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19596
+ }
19597
+ ),
19598
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
19599
+ ItemInteractionLayer,
19600
+ {
19601
+ rect: fieldPickRect,
19602
+ state: fieldDragging ? "dragging" : "active-top",
19603
+ itemDragSurface: false,
19604
+ toolbarAlign: "left",
19605
+ chromeGap: 10,
19606
+ showHandle: true,
19607
+ dragHandleLabel: "Reorder field",
19608
+ onDragHandleDragStart: handleFieldDragStart,
19609
+ onDragHandleDragEnd: handleFieldDragEnd,
19610
+ toolbar: /* @__PURE__ */ jsx33(
19611
+ FormFieldToolbar,
20980
19612
  {
20981
- rect: toolbarRect,
20982
- elRef: glowElRef,
20983
- reorderHrefKey,
20984
- dragDisabled: reorderDragDisabled,
20985
- hideHandle: isItemDragging
19613
+ type: fieldPickState.type,
19614
+ required: fieldPickState.required,
19615
+ onTypeChange: handleFieldTypeChange,
19616
+ onRequiredToggle: handleFieldRequiredToggle,
19617
+ onDuplicate: handleFieldDuplicate,
19618
+ onDelete: handleFieldDelete
20986
19619
  }
20987
- ),
20988
- /* @__PURE__ */ jsx33(
20989
- FloatingToolbar,
19620
+ )
19621
+ }
19622
+ ),
19623
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19624
+ "div",
19625
+ {
19626
+ className: "pointer-events-none fixed z-[2147483644]",
19627
+ style: { top: slot.top, left: slot.left, width: slot.width },
19628
+ children: /* @__PURE__ */ jsx33(
19629
+ DropIndicator,
20990
19630
  {
20991
- rect: toolbarRect,
20992
- parentScroll: parentScrollRef.current,
20993
- elRef: toolbarElRef,
20994
- onCommand: handleCommand,
20995
- activeCommands,
20996
- showEditLink,
20997
- onEditLink: openLinkPopoverForActive
19631
+ direction: "horizontal",
19632
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19633
+ className: "!w-full"
20998
19634
  }
20999
19635
  )
21000
- ] }),
21001
- maxBadge && /* @__PURE__ */ jsxs20(
19636
+ },
19637
+ `field-drop-${i}`
19638
+ )) : null,
19639
+ fieldTypePickerOpen && formPickRect ? (() => {
19640
+ const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
19641
+ return /* @__PURE__ */ jsx33(
21002
19642
  "div",
21003
19643
  {
21004
- "data-ohw-max-badge": "",
19644
+ className: "pointer-events-none fixed z-[2147483645]",
21005
19645
  style: {
21006
- position: "fixed",
21007
- top: maxBadge.rect.bottom + 4,
21008
- left: maxBadge.rect.right,
21009
- transform: "translateX(-100%)",
21010
- zIndex: 2147483647,
21011
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
21012
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
21013
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
21014
- borderRadius: 4,
21015
- padding: "2px 6px",
21016
- fontSize: 11,
21017
- fontWeight: 500,
21018
- pointerEvents: "none"
19646
+ top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
19647
+ left: toolbar ? toolbar.left : formPickRect.left + 24
21019
19648
  },
21020
- children: [
21021
- maxBadge.current,
21022
- "/",
21023
- maxBadge.max
21024
- ]
19649
+ children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
21025
19650
  }
21026
- ),
21027
- toggleState && !linkPopover && /* @__PURE__ */ jsx33(
21028
- StateToggle,
19651
+ );
19652
+ })() : null,
19653
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19654
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
19655
+ FooterContainerChrome,
19656
+ {
19657
+ rect: toolbarRect,
19658
+ onAdd: handleAddFooterColumn,
19659
+ addDisabled: !canAddFooterColumn()
19660
+ }
19661
+ ),
19662
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
19663
+ ItemInteractionLayer,
19664
+ {
19665
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19666
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19667
+ elRef: glowElRef,
19668
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19669
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19670
+ dragDisabled: reorderDragDisabled,
19671
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19672
+ onDragHandleDragStart: handleItemDragStart,
19673
+ onDragHandleDragEnd: handleItemDragEnd,
19674
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19675
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19676
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19677
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
19678
+ ItemActionToolbar,
19679
+ {
19680
+ onEditLink: openLinkPopoverForSelected,
19681
+ onStyle: () => {
19682
+ const row = selectedElRef.current;
19683
+ if (!row) return;
19684
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19685
+ else openSocialsDisplayPanel(row);
19686
+ },
19687
+ showStyle: selectedIsSocialsRow,
19688
+ styleActive: floatingPanel?.kind === "socials-display",
19689
+ onAddItem: handleAddChildItem,
19690
+ onSelectParent: handleSelectParent,
19691
+ onDuplicate: handleDuplicateSelected,
19692
+ onDelete: handleDeleteSelected,
19693
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19694
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19695
+ return row ? !canAddSocialItem(row) : false;
19696
+ })(),
19697
+ editLinkDisabled: false,
19698
+ moreDisabled: false,
19699
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19700
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19701
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19702
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19703
+ ),
19704
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19705
+ dropdownOpen: navDropdownPreviewOpen,
19706
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19707
+ headingVisible: footerHeadingVisible,
19708
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19709
+ }
19710
+ ) : void 0
19711
+ }
19712
+ ),
19713
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
19714
+ /* @__PURE__ */ jsx33(
19715
+ EditGlowChrome,
21029
19716
  {
21030
- rect: toggleState.rect,
21031
- activeState: toggleState.activeState,
21032
- states: toggleState.states,
21033
- onStateChange: handleStateChange
19717
+ rect: toolbarRect,
19718
+ elRef: glowElRef,
19719
+ reorderHrefKey,
19720
+ dragDisabled: reorderDragDisabled,
19721
+ hideHandle: isItemDragging
21034
19722
  }
21035
19723
  ),
21036
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
21037
- "div",
19724
+ /* @__PURE__ */ jsx33(
19725
+ FloatingToolbar,
21038
19726
  {
21039
- "data-ohw-section-insert-line": "",
21040
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
21041
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
21042
- children: [
21043
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
21044
- /* @__PURE__ */ jsx33(
21045
- Badge,
21046
- {
21047
- className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
21048
- onClick: () => {
21049
- window.parent.postMessage(
21050
- {
21051
- type: "ow:add-section",
21052
- insertAfter: sectionGap.insertAfter,
21053
- insertBefore: sectionGap.insertBefore
21054
- },
21055
- "*"
21056
- );
21057
- },
21058
- children: "Add Section"
21059
- }
21060
- ),
21061
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
21062
- ]
19727
+ rect: toolbarRect,
19728
+ parentScroll: parentScrollRef.current,
19729
+ elRef: toolbarElRef,
19730
+ onCommand: handleCommand,
19731
+ activeCommands,
19732
+ showEditLink,
19733
+ onEditLink: openLinkPopoverForActive
21063
19734
  }
21064
- ),
21065
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
21066
- LinkPopover,
21067
- {
21068
- panelRef: linkPopoverPanelRef,
21069
- portalContainer: dialogPortalContainer,
21070
- open: true,
21071
- mode: linkPopover.mode ?? "edit",
21072
- pages: sitePages,
21073
- sections: currentSections,
21074
- sectionsByPath,
21075
- initialTarget: linkPopover.target,
21076
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21077
- onClose: closeLinkPopover,
21078
- onSubmit: handleLinkPopoverSubmit
19735
+ )
19736
+ ] }),
19737
+ maxBadge && /* @__PURE__ */ jsxs20(
19738
+ "div",
19739
+ {
19740
+ "data-ohw-max-badge": "",
19741
+ style: {
19742
+ position: "fixed",
19743
+ top: maxBadge.rect.bottom + 4,
19744
+ left: maxBadge.rect.right,
19745
+ transform: "translateX(-100%)",
19746
+ zIndex: 2147483647,
19747
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19748
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19749
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19750
+ borderRadius: 4,
19751
+ padding: "2px 6px",
19752
+ fontSize: 11,
19753
+ fontWeight: 500,
19754
+ pointerEvents: "none"
21079
19755
  },
21080
- linkPopover.key
21081
- ) : null,
21082
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
21083
- FloatingPanel,
21084
- {
21085
- open: true,
21086
- title: floatingPanel.title,
21087
- context: floatingPanel.context,
21088
- position: floatingPanelPos,
21089
- onPositionChange: setFloatingPanelPos,
21090
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21091
- onClose: closeFloatingPanelOnly,
21092
- children: /* @__PURE__ */ jsx33(
21093
- SocialsDisplayPanel,
19756
+ children: [
19757
+ maxBadge.current,
19758
+ "/",
19759
+ maxBadge.max
19760
+ ]
19761
+ }
19762
+ ),
19763
+ toggleState && !linkPopover && /* @__PURE__ */ jsx33(
19764
+ StateToggle,
19765
+ {
19766
+ rect: toggleState.rect,
19767
+ activeState: toggleState.activeState,
19768
+ states: toggleState.states,
19769
+ onStateChange: handleStateChange
19770
+ }
19771
+ ),
19772
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
19773
+ "div",
19774
+ {
19775
+ "data-ohw-section-insert-line": "",
19776
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19777
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19778
+ children: [
19779
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19780
+ /* @__PURE__ */ jsx33(
19781
+ Badge,
21094
19782
  {
21095
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21096
- onChange: (next) => {
21097
- changeSocialsDisplay(floatingPanel.row, next);
21098
- setFloatingPanel({ ...floatingPanel });
21099
- }
19783
+ className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
19784
+ onClick: () => {
19785
+ window.parent.postMessage(
19786
+ {
19787
+ type: "ow:add-section",
19788
+ insertAfter: sectionGap.insertAfter,
19789
+ insertBefore: sectionGap.insertBefore
19790
+ },
19791
+ "*"
19792
+ );
19793
+ },
19794
+ children: "Add Section"
21100
19795
  }
21101
- )
21102
- }
21103
- ) : null
21104
- ] }),
21105
- bridgeRoot
21106
- ) : null
21107
- ] });
21108
- }
21109
-
21110
- // src/ui/EmptySection.tsx
21111
- import Link3 from "next/link";
21112
- import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
21113
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21114
- return /* @__PURE__ */ jsxs21(Fragment9, { children: [
21115
- /* @__PURE__ */ jsx34(
21116
- "p",
21117
- {
21118
- style: {
21119
- fontFamily: "var(--brand-font-body)",
21120
- fontSize: "0.75rem",
21121
- fontWeight: 500,
21122
- letterSpacing: "0.15em",
21123
- textTransform: "uppercase",
21124
- color: "var(--brand-accent)",
21125
- marginBottom: "1.5rem"
21126
- },
21127
- children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
21128
- }
21129
- ),
21130
- /* @__PURE__ */ jsx34(
21131
- "h1",
21132
- {
21133
- style: {
21134
- fontFamily: "var(--brand-font-heading)",
21135
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21136
- lineHeight: 1.1,
21137
- letterSpacing: "-0.025em",
21138
- color: "var(--brand-text)",
21139
- marginBottom: "1rem"
21140
- },
21141
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21142
- children: title
21143
- }
21144
- ),
21145
- /* @__PURE__ */ jsx34(
21146
- "p",
21147
- {
21148
- style: {
21149
- fontFamily: "var(--brand-font-body)",
21150
- fontSize: "1rem",
21151
- lineHeight: 1.7,
21152
- fontWeight: 300,
21153
- color: "var(--brand-text-muted)",
21154
- maxWidth: "340px"
19796
+ ),
19797
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19798
+ ]
19799
+ }
19800
+ ),
19801
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
19802
+ LinkPopover,
19803
+ {
19804
+ panelRef: linkPopoverPanelRef,
19805
+ portalContainer: dialogPortalContainer,
19806
+ open: true,
19807
+ mode: linkPopover.mode ?? "edit",
19808
+ pages: sitePages,
19809
+ sections: currentSections,
19810
+ sectionsByPath,
19811
+ initialTarget: linkPopover.target,
19812
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19813
+ onClose: closeLinkPopover,
19814
+ onSubmit: handleLinkPopoverSubmit
21155
19815
  },
21156
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21157
- children: "This page doesn't have any content yet."
21158
- }
21159
- )
21160
- ] });
19816
+ linkPopover.key
19817
+ ) : null,
19818
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
19819
+ FloatingPanel,
19820
+ {
19821
+ open: true,
19822
+ title: floatingPanel.title,
19823
+ context: floatingPanel.context,
19824
+ position: floatingPanelPos,
19825
+ onPositionChange: setFloatingPanelPos,
19826
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19827
+ onClose: closeFloatingPanelOnly,
19828
+ children: /* @__PURE__ */ jsx33(
19829
+ SocialsDisplayPanel,
19830
+ {
19831
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19832
+ onChange: (next) => {
19833
+ changeSocialsDisplay(floatingPanel.row, next);
19834
+ setFloatingPanel({ ...floatingPanel });
19835
+ }
19836
+ }
19837
+ )
19838
+ }
19839
+ ) : null
19840
+ ] }),
19841
+ bridgeRoot
19842
+ ) : null;
21161
19843
  }
21162
19844
  export {
21163
19845
  AI_DEFAULT_BRAND,
@@ -21175,7 +19857,6 @@ export {
21175
19857
  DropdownMenuItem,
21176
19858
  DropdownMenuSeparator,
21177
19859
  DropdownMenuTrigger,
21178
- EmptySection,
21179
19860
  ItemActionToolbar,
21180
19861
  ItemInteractionLayer,
21181
19862
  LinkEditorPanel,