@ohhwells/bridge 0.1.68-next.203 → 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.cjs CHANGED
@@ -46,7 +46,6 @@ __export(index_exports, {
46
46
  DropdownMenuItem: () => DropdownMenuItem,
47
47
  DropdownMenuSeparator: () => DropdownMenuSeparator,
48
48
  DropdownMenuTrigger: () => DropdownMenuTrigger,
49
- EmptySection: () => EmptySection,
50
49
  ItemActionToolbar: () => ItemActionToolbar,
51
50
  ItemInteractionLayer: () => ItemInteractionLayer,
52
51
  LinkEditorPanel: () => LinkEditorPanel,
@@ -75,7 +74,7 @@ __export(index_exports, {
75
74
  module.exports = __toCommonJS(index_exports);
76
75
 
77
76
  // src/OhhwellsBridge.tsx
78
- var import_react17 = __toESM(require("react"), 1);
77
+ var import_react16 = __toESM(require("react"), 1);
79
78
  var import_client2 = require("react-dom/client");
80
79
  var import_react_dom3 = require("react-dom");
81
80
 
@@ -157,12 +156,7 @@ function parseAiSectionsState(raw) {
157
156
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
158
157
  }));
159
158
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
160
- return {
161
- v: 1,
162
- sections,
163
- ...removed.length ? { removed } : {},
164
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
165
- };
159
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
166
160
  } catch {
167
161
  return EMPTY_AI_SECTIONS;
168
162
  }
@@ -175,7 +169,6 @@ function applyTreeToState(state, payload) {
175
169
  const entry = {
176
170
  id: payload.id,
177
171
  label: payload.label ?? "Generated section",
178
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
179
172
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
180
173
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
181
174
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -198,317 +191,6 @@ function deleteSectionFromState(state, sectionId) {
198
191
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
199
192
  }
200
193
 
201
- // src/lib/brand-chrome.ts
202
- var BRAND_NAME_KEY = "__ohw_brand_name";
203
- var BRAND_TITLE_KEY = "__ohw_site_title";
204
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
205
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
206
- BRAND_NAME_KEY,
207
- BRAND_TITLE_KEY,
208
- BRAND_FAVICON_LETTER_KEY
209
- ]);
210
- function upsertMeta(selector, attr, token, value) {
211
- let el = document.head.querySelector(selector);
212
- if (!el) {
213
- el = document.createElement("meta");
214
- el.setAttribute(attr, token);
215
- document.head.appendChild(el);
216
- }
217
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
218
- }
219
- function escapeXml(value) {
220
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
221
- }
222
- function applyLetterFavicon(letter) {
223
- 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>`;
224
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
225
- let link = document.head.querySelector('link[rel="icon"]');
226
- if (!link) {
227
- link = document.createElement("link");
228
- link.rel = "icon";
229
- document.head.appendChild(link);
230
- }
231
- link.type = "image/svg+xml";
232
- if (link.href !== href) link.href = href;
233
- }
234
- function applyBrandChrome(content) {
235
- const name = content[BRAND_NAME_KEY];
236
- if (typeof name === "string" && name.length > 0) {
237
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
238
- if (el.textContent !== name) el.textContent = name;
239
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
240
- });
241
- }
242
- const title = content[BRAND_TITLE_KEY];
243
- if (typeof title === "string" && title.length > 0) {
244
- if (document.title !== title) document.title = title;
245
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
246
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
247
- }
248
- const letter = content[BRAND_FAVICON_LETTER_KEY];
249
- if (typeof letter === "string" && letter.length > 0) {
250
- applyLetterFavicon(letter);
251
- }
252
- }
253
-
254
- // src/lib/brand-kit.ts
255
- var BRAND_KIT_KEY = "__ohw_brand";
256
- var BRAND_VAR_PREFIX = "--ohw-brand-";
257
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
258
- (role) => `${BRAND_VAR_PREFIX}${role}`
259
- );
260
- var FONT_VARS = {
261
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
262
- body: ["--font-body", "--brand-font-body"]
263
- };
264
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
265
- function brandColorVars(kit) {
266
- const { dark, primary, accent, light } = kit.palette;
267
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
268
- return {
269
- [`${BRAND_VAR_PREFIX}primary`]: primary,
270
- [`${BRAND_VAR_PREFIX}accent`]: accent,
271
- [`${BRAND_VAR_PREFIX}light`]: light,
272
- [`${BRAND_VAR_PREFIX}dark`]: dark,
273
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
274
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
275
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
276
- };
277
- }
278
- function parseBrandKit(raw) {
279
- if (!raw) return null;
280
- try {
281
- const parsed = JSON.parse(raw);
282
- const p = parsed?.palette;
283
- const f = parsed?.fonts;
284
- 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") {
285
- return null;
286
- }
287
- return {
288
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
289
- fonts: { heading: f.heading, body: f.body }
290
- };
291
- } catch {
292
- return null;
293
- }
294
- }
295
- function familyOf(stack) {
296
- const first = stack.split(",")[0]?.trim() ?? "";
297
- return first.replace(/^['"]|['"]$/g, "");
298
- }
299
- function loadBrandFonts(families) {
300
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
301
- if (unique.length === 0) return;
302
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
303
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
304
- let link = document.getElementById(BRAND_FONT_LINK_ID);
305
- if (!link) {
306
- link = document.createElement("link");
307
- link.id = BRAND_FONT_LINK_ID;
308
- link.rel = "stylesheet";
309
- document.head.appendChild(link);
310
- }
311
- if (link.href !== href) link.href = href;
312
- }
313
- function applyBrandToDom(kit) {
314
- const root = document.documentElement;
315
- if (!kit) {
316
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
317
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
318
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
319
- return;
320
- }
321
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
322
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
323
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
324
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
325
- }
326
-
327
- // src/lib/section-styles.ts
328
- var STYLE_STORE_KEY = "__ohw_styles";
329
- var STYLE_SHEET_ID = "ohw-section-styles";
330
- function parseStyleStore(raw) {
331
- if (!raw) return null;
332
- try {
333
- const parsed = JSON.parse(raw);
334
- if (parsed?.v !== 1) return null;
335
- return {
336
- v: 1,
337
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
338
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
339
- };
340
- } catch {
341
- return null;
342
- }
343
- }
344
- var BG_VALUES = {
345
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
346
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
347
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
348
- };
349
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
350
- function styleSheetCss() {
351
- const rules = [];
352
- for (const [tone, value] of Object.entries(BG_VALUES)) {
353
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
354
- }
355
- rules.push(
356
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
357
- );
358
- rules.push(
359
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
360
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
361
- );
362
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
363
- rules.push(
364
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
365
- );
366
- }
367
- rules.push(
368
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
369
- );
370
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
371
- rules.push(
372
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
373
- );
374
- }
375
- const pad = { tight: 40, balanced: 64, airy: 96 };
376
- for (const [spacing, px] of Object.entries(pad)) {
377
- rules.push(
378
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
379
- );
380
- }
381
- return rules.join("\n");
382
- }
383
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
384
- function loadStyleFonts(families) {
385
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
386
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
387
- if (unique.length === 0) {
388
- existing?.remove();
389
- return;
390
- }
391
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
392
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
393
- let link = existing;
394
- if (!link) {
395
- link = document.createElement("link");
396
- link.id = STYLE_FONT_LINK_ID;
397
- link.rel = "stylesheet";
398
- document.head.appendChild(link);
399
- }
400
- if (link.href !== href) link.href = href;
401
- }
402
- var SECTION_ATTRS = {
403
- sectionBackground: "data-ohw-style-bg",
404
- textDistribution: "data-ohw-style-distribution",
405
- headlineScale: "data-ohw-style-headline",
406
- imageAspect: "data-ohw-style-aspect",
407
- spacing: "data-ohw-style-spacing"
408
- };
409
- var NODE_WROTE_ATTR = "data-ohw-style-node";
410
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
411
- function saveInline(el, prop) {
412
- const attr = `data-ohw-style-prev-${prop}`;
413
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
414
- }
415
- function restoreInline(el, prop) {
416
- const attr = `data-ohw-style-prev-${prop}`;
417
- if (!el.hasAttribute(attr)) return;
418
- const prev = el.getAttribute(attr) ?? "";
419
- if (prev) el.style.setProperty(prop, prev);
420
- else el.style.removeProperty(prop);
421
- el.removeAttribute(attr);
422
- }
423
- function ensureStyleSheet() {
424
- let el = document.getElementById(STYLE_SHEET_ID);
425
- if (!el) {
426
- el = document.createElement("style");
427
- el.id = STYLE_SHEET_ID;
428
- document.head.appendChild(el);
429
- }
430
- const css = styleSheetCss();
431
- if (el.textContent !== css) el.textContent = css;
432
- }
433
- function clearSectionAttrs(root) {
434
- for (const attr of Object.values(SECTION_ATTRS)) {
435
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
436
- }
437
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
438
- restoreInline(el, "background");
439
- el.removeAttribute("data-ohw-style-bgcolor");
440
- }
441
- }
442
- function clearNodeProps(root) {
443
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
444
- const h = el;
445
- for (const prop of NODE_PROPS) restoreInline(h, prop);
446
- h.removeAttribute(NODE_WROTE_ATTR);
447
- }
448
- }
449
- function buttonSurfaceOf(el) {
450
- return el.closest("a, button") ?? el;
451
- }
452
- function applyStylesToDom(store) {
453
- ensureStyleSheet();
454
- clearSectionAttrs(document);
455
- clearNodeProps(document);
456
- loadStyleFonts(
457
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
458
- );
459
- if (!store) return;
460
- for (const [sectionId, override] of Object.entries(store.sections)) {
461
- const sections = document.querySelectorAll(
462
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
463
- );
464
- for (const section of Array.from(sections)) {
465
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
466
- const value = override[prop];
467
- if (value === void 0) continue;
468
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
469
- section.setAttribute(attr, String(value).replace(":", "-"));
470
- }
471
- if (override.sectionBackgroundColor !== void 0) {
472
- saveInline(section, "background");
473
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
474
- section.setAttribute("data-ohw-style-bgcolor", "");
475
- }
476
- }
477
- }
478
- for (const [key, override] of Object.entries(store.nodes)) {
479
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
480
- for (const el of Array.from(nodes)) {
481
- if (override.color !== void 0) {
482
- saveInline(el, "color");
483
- el.style.setProperty("color", override.color, "important");
484
- el.setAttribute(NODE_WROTE_ATTR, "");
485
- }
486
- if (override.fontFamily !== void 0) {
487
- saveInline(el, "font-family");
488
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
489
- el.setAttribute(NODE_WROTE_ATTR, "");
490
- }
491
- if (override.fontSize !== void 0) {
492
- saveInline(el, "font-size");
493
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
494
- el.setAttribute(NODE_WROTE_ATTR, "");
495
- }
496
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
497
- const surface = buttonSurfaceOf(el);
498
- if (override.buttonBackground !== void 0) {
499
- saveInline(surface, "background");
500
- surface.style.setProperty("background", override.buttonBackground, "important");
501
- }
502
- if (override.buttonText !== void 0) {
503
- saveInline(surface, "color");
504
- surface.style.setProperty("color", override.buttonText, "important");
505
- }
506
- surface.setAttribute(NODE_WROTE_ATTR, "");
507
- }
508
- }
509
- }
510
- }
511
-
512
194
  // src/ui/ai-tree/aiSectionsManager.tsx
513
195
  var import_react_dom = require("react-dom");
514
196
  var import_client = require("react-dom/client");
@@ -523,8 +205,7 @@ function lucideByName(name) {
523
205
  }
524
206
  var typeStyle = (spec, font) => ({
525
207
  fontFamily: font,
526
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
527
- 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,
208
+ fontSize: spec.size,
528
209
  lineHeight: spec.line,
529
210
  fontWeight: spec.weight
530
211
  });
@@ -539,36 +220,6 @@ var FEATURE_LINE_CSS = [
539
220
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
540
221
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
541
222
  ].join("");
542
- function hexLuminance(color) {
543
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
544
- if (!m) return null;
545
- const [r2, g, b] = [0, 2, 4].map((i) => {
546
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
547
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
548
- });
549
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
550
- }
551
- function hexContrast(a, b) {
552
- const la = hexLuminance(a);
553
- const lb = hexLuminance(b);
554
- if (la === null || lb === null) return null;
555
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
556
- return (hi + 0.05) / (lo + 0.05);
557
- }
558
- function accentBandContext(brand) {
559
- const p = brand.palette;
560
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
561
- if (lightWins) {
562
- return {
563
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
564
- buttonLabel: p.primary
565
- };
566
- }
567
- return {
568
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
569
- buttonLabel: p.light
570
- };
571
- }
572
223
  function textAttrs(ctx, path) {
573
224
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
574
225
  }
@@ -581,8 +232,6 @@ var AI_RESPONSIVE_CSS = [
581
232
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
582
233
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
583
234
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
584
- " [data-ai-responsive] { overflow-x: hidden; }",
585
- " [data-ai-responsive] img { max-width: 100%; }",
586
235
  "}"
587
236
  ].join("\n");
588
237
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -660,7 +309,7 @@ function ButtonEl({
660
309
  }) {
661
310
  const secondary = slots.variant === "secondary";
662
311
  const href = str(slots.href);
663
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
312
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
664
313
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
665
314
  "a",
666
315
  {
@@ -676,7 +325,7 @@ function ButtonEl({
676
325
  textDecoration: "none",
677
326
  cursor: "pointer",
678
327
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
679
- ...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 }
328
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
680
329
  },
681
330
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
682
331
  }
@@ -1578,14 +1227,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1578
1227
  return null;
1579
1228
  }
1580
1229
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1581
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1582
- const blockBrand = band?.brand ?? resolvedBrand;
1583
1230
  const ctx = {
1584
- brand: blockBrand,
1231
+ brand: resolvedBrand,
1585
1232
  resolveMedia: resolveMedia ?? (() => null),
1586
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1587
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1588
- ...band ? { buttonLabel: band.buttonLabel } : {}
1233
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1234
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1589
1235
  };
1590
1236
  const settings = tree.settings ?? {};
1591
1237
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1593,20 +1239,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1593
1239
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1594
1240
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1595
1241
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1596
- const toneBackground = (() => {
1597
- const { dark, primary, light } = resolvedBrand.palette;
1598
- switch (settings.sectionBackground) {
1599
- case "surface":
1600
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1601
- case "accent":
1602
- return primary;
1603
- case "accent-soft":
1604
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1605
- default:
1606
- return void 0;
1607
- }
1608
- })();
1609
- const distributed = !isOverlay && settings.textDistribution;
1610
1242
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1611
1243
  "section",
1612
1244
  {
@@ -1616,11 +1248,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1616
1248
  style: {
1617
1249
  position: "relative",
1618
1250
  padding: `${pad}px 0`,
1619
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1251
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1620
1252
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1621
1253
  backgroundSize: "cover",
1622
- backgroundPosition: "center",
1623
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1254
+ backgroundPosition: "center"
1624
1255
  },
1625
1256
  children: [
1626
1257
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
@@ -1644,24 +1275,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1644
1275
  display: "grid",
1645
1276
  gridTemplateColumns: "repeat(12, 1fr)",
1646
1277
  gap: AI_TREE_TOKENS.spacing6,
1647
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1278
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1648
1279
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1649
1280
  },
1650
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1651
- "div",
1652
- {
1653
- "data-ai-cell": "",
1654
- style: {
1655
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1656
- minWidth: 0,
1657
- // space-between: each column becomes a flex column whose content spreads over
1658
- // the full row height instead of clumping at the top.
1659
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1660
- },
1661
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1662
- },
1663
- b
1664
- ))
1281
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1665
1282
  },
1666
1283
  r2
1667
1284
  ))
@@ -1677,36 +1294,17 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1677
1294
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1678
1295
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1679
1296
  var REMOVED_ATTR = "data-ohw-ai-removed";
1680
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1681
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1682
- function readRootVar(name) {
1683
- if (typeof document === "undefined") return "";
1684
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1685
- }
1686
- function deriveBrandOverride() {
1687
- const dark = readRootVar("--ohw-brand-dark");
1688
- const primary = readRootVar("--ohw-brand-primary");
1689
- const light = readRootVar("--ohw-brand-light");
1690
- if (!dark || !primary || !light) return null;
1691
- const accent = readRootVar("--ohw-brand-accent");
1692
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1693
- const body = readRootVar("--font-body");
1694
- return {
1695
- palette: { dark, primary, accent: accent || dark, light },
1696
- fonts: {
1697
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1698
- body: body || AI_DEFAULT_BRAND.fonts.body
1699
- }
1700
- };
1701
- }
1702
1297
  function deriveTemplateBrand() {
1703
- const dark = readRootVar("--color-dark");
1704
- const primary = readRootVar("--color-primary");
1705
- const light = readRootVar("--color-light");
1298
+ if (typeof document === "undefined") return null;
1299
+ const cs = getComputedStyle(document.documentElement);
1300
+ const read = (name) => cs.getPropertyValue(name).trim();
1301
+ const dark = read("--color-dark");
1302
+ const primary = read("--color-primary");
1303
+ const light = read("--color-light");
1706
1304
  if (!dark || !primary || !light) return null;
1707
- const accent = readRootVar("--color-accent");
1708
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1709
- const body = readRootVar("--font-body");
1305
+ const accent = read("--color-accent");
1306
+ const heading = read("--font-heading") || read("--font-display");
1307
+ const body = read("--font-body");
1710
1308
  return {
1711
1309
  palette: { dark, primary, accent: accent || dark, light },
1712
1310
  fonts: {
@@ -1778,24 +1376,6 @@ function syncRemovedSections(state) {
1778
1376
  }
1779
1377
  }
1780
1378
  }
1781
- function syncTemplateHidden(state, pageHasSections) {
1782
- const hide = state.hideTemplate === true && pageHasSections;
1783
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1784
- if (!hide) {
1785
- el.style.removeProperty("display");
1786
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1787
- }
1788
- }
1789
- if (!hide) return;
1790
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1791
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1792
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1793
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1794
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1795
- el.style.display = "none";
1796
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1797
- }
1798
- }
1799
1379
  function syncReplacedOriginals(state) {
1800
1380
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1801
1381
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1816,12 +1396,8 @@ function syncReplacedOriginals(state) {
1816
1396
  }
1817
1397
  function applyAiSectionsToDom(state, options) {
1818
1398
  if (typeof document === "undefined") return;
1819
- const brandOverride = deriveBrandOverride();
1820
1399
  const templateBrand = deriveTemplateBrand();
1821
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1822
- const pagePath = window.location.pathname;
1823
- const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
1824
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1400
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1825
1401
  for (const [id, section] of mounted) {
1826
1402
  if (!activeIds.has(id)) {
1827
1403
  section.root.unmount();
@@ -1829,8 +1405,8 @@ function applyAiSectionsToDom(state, options) {
1829
1405
  mounted.delete(id);
1830
1406
  }
1831
1407
  }
1832
- for (const entry of pageSections) {
1833
- const serialized = JSON.stringify(entry) + brandKey;
1408
+ for (const entry of state.sections) {
1409
+ const serialized = JSON.stringify(entry);
1834
1410
  const existing = mounted.get(entry.id);
1835
1411
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1836
1412
  continue;
@@ -1844,7 +1420,6 @@ function applyAiSectionsToDom(state, options) {
1844
1420
  mounted.delete(entry.id);
1845
1421
  }
1846
1422
  container.setAttribute("data-ohw-section", entry.id);
1847
- container.setAttribute("data-ohw-instance", entry.id);
1848
1423
  container.setAttribute("data-ohw-section-label", entry.label);
1849
1424
  placeContainer(container, entry);
1850
1425
  const root = mounted.get(entry.id)?.root ?? (0, import_client.createRoot)(container);
@@ -1855,7 +1430,7 @@ function applyAiSectionsToDom(state, options) {
1855
1430
  AiTreeRenderer,
1856
1431
  {
1857
1432
  tree: entry.tree,
1858
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1433
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1859
1434
  resolveMedia,
1860
1435
  editKeyPrefix: `ai.${entry.id}`
1861
1436
  }
@@ -1866,7 +1441,6 @@ function applyAiSectionsToDom(state, options) {
1866
1441
  }
1867
1442
  syncReplacedOriginals(state);
1868
1443
  syncRemovedSections(state);
1869
- syncTemplateHidden(state, pageSections.length > 0);
1870
1444
  }
1871
1445
 
1872
1446
  // src/useLinkHrefGuardian.ts
@@ -2473,7 +2047,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2473
2047
  const autoId = (0, import_react5.useId)();
2474
2048
  const insertAfter = insertAfterProp ?? autoId;
2475
2049
  const [schedule, setSchedule] = (0, import_react5.useState)(null);
2476
- const [loading, setLoading] = (0, import_react5.useState)(initialScheduleId !== null);
2050
+ const [loading, setLoading] = (0, import_react5.useState)(true);
2477
2051
  const [inEditor, setInEditor] = (0, import_react5.useState)(false);
2478
2052
  const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
2479
2053
  const [modalState, setModalState] = (0, import_react5.useState)(null);
@@ -2647,10 +2221,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2647
2221
  "*"
2648
2222
  );
2649
2223
  };
2224
+ if (!inEditor && !loading && !schedule) return null;
2650
2225
  const sectionId = `scheduling-${insertAfter}`;
2651
- if (!inEditor && !loading && !schedule) {
2652
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2653
- }
2654
2226
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2655
2227
  "section",
2656
2228
  {
@@ -7558,17 +7130,13 @@ function MediaOverlay({
7558
7130
  hover,
7559
7131
  isUploading,
7560
7132
  fadingOut = false,
7561
- selected = false,
7562
- hovered = false,
7563
7133
  onFadeOutComplete,
7564
7134
  onReplace,
7565
- onSelect,
7566
7135
  onVideoSettingsChange
7567
7136
  }) {
7568
7137
  const { rect } = hover;
7569
7138
  const skeletonRef = React7.useRef(null);
7570
7139
  const isVideo = hover.elementType === "video";
7571
- const showChrome = !selected || hovered;
7572
7140
  const autoplay = hover.videoAutoplay ?? true;
7573
7141
  const muted = hover.videoMuted ?? true;
7574
7142
  const box = {
@@ -7603,7 +7171,7 @@ function MediaOverlay({
7603
7171
  }
7604
7172
  );
7605
7173
  }
7606
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7174
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7607
7175
  "div",
7608
7176
  {
7609
7177
  "data-ohw-bridge": "",
@@ -7673,13 +7241,11 @@ function MediaOverlay({
7673
7241
  // in-document, pointer-events does it natively. The button below opts back in, so
7674
7242
  // Replace still works.
7675
7243
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7676
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7677
- // than hovered. Hover keeps the existing tinted preview.
7678
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7679
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7244
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7245
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7680
7246
  },
7681
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7682
- children: showChrome && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7247
+ onClick: () => onReplace(hover.key),
7248
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7683
7249
  Button,
7684
7250
  {
7685
7251
  "data-ohw-media-overlay": "",
@@ -7768,9 +7334,6 @@ var import_lucide_react7 = require("lucide-react");
7768
7334
 
7769
7335
  // src/lib/sections.ts
7770
7336
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7771
- function isChromeSection(el) {
7772
- return el.matches("header, nav, footer, aside");
7773
- }
7774
7337
  function titleCaseSectionId(id) {
7775
7338
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7776
7339
  }
@@ -7781,8 +7344,6 @@ function parseSectionsFromRoot(root) {
7781
7344
  const id = el.getAttribute("data-ohw-section") ?? "";
7782
7345
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7783
7346
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7784
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7785
- continue;
7786
7347
  seen.add(id);
7787
7348
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7788
7349
  sections.push({ id, label });
@@ -7800,12 +7361,8 @@ function parseSectionsFromHtml(html) {
7800
7361
 
7801
7362
  // src/ui/ai-section/AiSectionOverlay.tsx
7802
7363
  var import_jsx_runtime17 = require("react/jsx-runtime");
7803
- function findSectionElement(instanceId) {
7804
- const escaped = CSS.escape(instanceId);
7805
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7806
- }
7807
- function readRect(instanceId) {
7808
- const el = findSectionElement(instanceId);
7364
+ function readRect(sectionId) {
7365
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7809
7366
  if (!el) return null;
7810
7367
  const r2 = el.getBoundingClientRect();
7811
7368
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7828,7 +7385,7 @@ function useLiveSectionRect(sectionId) {
7828
7385
  const opts = { capture: true, passive: true };
7829
7386
  window.addEventListener("scroll", update, opts);
7830
7387
  window.addEventListener("resize", update);
7831
- const el = findSectionElement(sectionId);
7388
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7832
7389
  const ro = el ? new ResizeObserver(update) : null;
7833
7390
  if (el && ro) ro.observe(el);
7834
7391
  const interval = setInterval(update, 500);
@@ -7841,14 +7398,6 @@ function useLiveSectionRect(sectionId) {
7841
7398
  }, [sectionId]);
7842
7399
  return rect;
7843
7400
  }
7844
- function computeSectionBoundaryFlags(instanceId) {
7845
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7846
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7847
- );
7848
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7849
- if (index === -1) return { isFirst: true, isLast: true };
7850
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7851
- }
7852
7401
  var PRIMARY2 = "#0885FE";
7853
7402
  function edgeAwareRadius(rect) {
7854
7403
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7922,7 +7471,6 @@ function AiSectionOverlay({
7922
7471
  }) {
7923
7472
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
7924
7473
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
7925
- const [reviewButtonsHidden, setReviewButtonsHidden] = (0, import_react8.useState)(false);
7926
7474
  const reviewIdRef = (0, import_react8.useRef)(null);
7927
7475
  reviewIdRef.current = reviewId;
7928
7476
  const selectedIdRef = (0, import_react8.useRef)(null);
@@ -7931,7 +7479,7 @@ function AiSectionOverlay({
7931
7479
  (el) => {
7932
7480
  postToParent2({
7933
7481
  type: "ow:section-selected",
7934
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7482
+ sectionId: el?.dataset.ohwSection ?? null,
7935
7483
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7936
7484
  });
7937
7485
  },
@@ -7940,7 +7488,7 @@ function AiSectionOverlay({
7940
7488
  const selectFromElement = (0, import_react8.useCallback)(
7941
7489
  (el, options) => {
7942
7490
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7943
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7491
+ const id = sectionEl?.dataset.ohwSection ?? null;
7944
7492
  if (id === selectedIdRef.current) return;
7945
7493
  setSelectedId(id);
7946
7494
  if (options?.report !== false) report(sectionEl);
@@ -7981,10 +7529,9 @@ function AiSectionOverlay({
7981
7529
  }
7982
7530
  const found = readRect(sectionId) != null;
7983
7531
  setReviewId(found ? sectionId : null);
7984
- setReviewButtonsHidden(e.data.hideButtons === true);
7985
7532
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7986
7533
  if (found) {
7987
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7534
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7988
7535
  }
7989
7536
  }
7990
7537
  };
@@ -8003,7 +7550,7 @@ function AiSectionOverlay({
8003
7550
  return;
8004
7551
  }
8005
7552
  const sec = t.closest("[data-ohw-section]");
8006
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7553
+ setHoveredId(sec?.dataset.ohwSection ?? null);
8007
7554
  };
8008
7555
  const onLeave = () => setHoveredId(null);
8009
7556
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -8035,30 +7582,9 @@ function AiSectionOverlay({
8035
7582
  },
8036
7583
  [postToParent2]
8037
7584
  );
8038
- const activeSelectionId = reviewId ? null : selectedId;
8039
- const selectionRect = useLiveSectionRect(activeSelectionId);
7585
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
8040
7586
  const reviewRect = useLiveSectionRect(reviewId);
8041
7587
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
8042
- (0, import_react8.useEffect)(() => {
8043
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
8044
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
8045
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
8046
- return;
8047
- }
8048
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
8049
- postToParent2({
8050
- type: "ow:section-rect",
8051
- instanceId: activeSelectionId,
8052
- rect: {
8053
- top: selectionRect.top + window.scrollY,
8054
- left: selectionRect.left + window.scrollX,
8055
- width: selectionRect.width,
8056
- height: selectionRect.height
8057
- },
8058
- isFirst,
8059
- isLast
8060
- });
8061
- }, [activeSelectionId, selectionRect, postToParent2]);
8062
7588
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8063
7589
  hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8064
7590
  "div",
@@ -8109,16 +7635,13 @@ function AiSectionOverlay({
8109
7635
  border: `2px solid ${PRIMARY2}`,
8110
7636
  borderRadius: edgeAwareRadius(reviewRect),
8111
7637
  zIndex: 2147483200,
8112
- // The veil itself: swallows clicks so the section stays locked until decided. This
8113
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8114
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8115
- // Accept/Discard resolves to the media beneath and opens the file picker.
7638
+ // The veil itself: swallows clicks so the section stays locked until decided.
8116
7639
  background: "rgba(8, 133, 254, 0.04)",
8117
7640
  pointerEvents: "auto",
8118
7641
  cursor: "default"
8119
7642
  },
8120
7643
  onClick: (e) => e.stopPropagation(),
8121
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7644
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8122
7645
  "div",
8123
7646
  {
8124
7647
  style: {
@@ -8143,58 +7666,6 @@ function AiSectionOverlay({
8143
7666
 
8144
7667
  // src/lib/section-instances.ts
8145
7668
  var SECTION_ORDER_KEY = "__ohw_section_order";
8146
- function topLevelSections() {
8147
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8148
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8149
- );
8150
- }
8151
- function instanceIdOf(el) {
8152
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8153
- }
8154
- function planSectionMove(instanceId, targetIndex, currentPath) {
8155
- const sections = topLevelSections();
8156
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8157
- if (index === -1) return null;
8158
- const dragged = sections[index];
8159
- const others = sections.filter((_, i) => i !== index);
8160
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8161
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8162
- return reordered.map((el, order) => ({
8163
- instanceId: instanceIdOf(el),
8164
- type: el.getAttribute("data-ohw-section") ?? "",
8165
- order,
8166
- pagePath: currentPath
8167
- }));
8168
- }
8169
- function moveSectionInstance(instanceId, direction, currentPath) {
8170
- const sections = topLevelSections();
8171
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8172
- if (index === -1) return null;
8173
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8174
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8175
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8176
- if (!entries) return null;
8177
- applyPersistedOrder(entries);
8178
- return entries;
8179
- }
8180
- function applyPersistedOrder(entries) {
8181
- if (entries.length === 0) return;
8182
- const sections = topLevelSections();
8183
- if (sections.length === 0) return;
8184
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8185
- const ordered = [...sections].sort((a, b) => {
8186
- const aOrder = orderIndex.get(instanceIdOf(a));
8187
- const bOrder = orderIndex.get(instanceIdOf(b));
8188
- if (aOrder === void 0 && bOrder === void 0) return 0;
8189
- if (aOrder === void 0) return 1;
8190
- if (bOrder === void 0) return -1;
8191
- return aOrder - bOrder;
8192
- });
8193
- const parent = sections[0].parentElement;
8194
- if (!parent) return;
8195
- const anchor = sections[sections.length - 1].nextSibling;
8196
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8197
- }
8198
7669
  function getPageSectionOrderEntries(raw, currentPath) {
8199
7670
  if (!raw) return [];
8200
7671
  try {
@@ -8232,7 +7703,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8232
7703
  rekeySectionSubtree(clone, entry.instanceId);
8233
7704
  original.insertAdjacentElement("afterend", clone);
8234
7705
  }
8235
- applyPersistedOrder(entries);
8236
7706
  }
8237
7707
 
8238
7708
  // src/OhhwellsBridge.tsx
@@ -10857,8 +10327,7 @@ function findSocialsRow(el) {
10857
10327
  }
10858
10328
  function isSocialsRow(el) {
10859
10329
  const anchors = Array.from(el.querySelectorAll("a"));
10860
- if (!anchors.length || !anchors.some((anchor) => isSocialItem(anchor))) return false;
10861
- return findSocialsRow(anchors[0]) === el;
10330
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
10862
10331
  }
10863
10332
  var MAX_SOCIAL_ITEMS_PER_ROW = 7;
10864
10333
  function canAddSocialItem(row) {
@@ -10896,7 +10365,6 @@ function markSocialsRows(root = document) {
10896
10365
  });
10897
10366
  listSocialsRows(root).forEach((row) => {
10898
10367
  row.setAttribute(SOCIALS_ROW_ATTR, "");
10899
- allowRowToWrap(row);
10900
10368
  const items = listSocialItems(row);
10901
10369
  const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
10902
10370
  if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
@@ -11191,29 +10659,7 @@ function applySocialsDisplayToRow(row, display) {
11191
10659
  const icon = item.querySelector(ICON_SELECTOR);
11192
10660
  if (label) label.style.display = display.text ? "" : "none";
11193
10661
  if (icon) icon.style.display = display.icon ? "" : "none";
11194
- layOutIconAndLabel(item, Boolean(display.text && display.icon));
11195
10662
  });
11196
- allowRowToWrap(row);
11197
- }
11198
- function layOutIconAndLabel(item, on) {
11199
- const hasBoth = Boolean(item.querySelector(ICON_SELECTOR)) && Boolean(socialLabelElement(item));
11200
- if (!hasBoth) {
11201
- item.style.display = "";
11202
- item.style.alignItems = "";
11203
- item.style.gap = "";
11204
- item.style.whiteSpace = "";
11205
- item.style.flex = "";
11206
- return;
11207
- }
11208
- item.style.display = on ? "inline-flex" : "";
11209
- item.style.alignItems = on ? "center" : "";
11210
- item.style.gap = on ? "8px" : "";
11211
- item.style.whiteSpace = on ? "nowrap" : "";
11212
- item.style.flex = on ? "0 0 auto" : "";
11213
- }
11214
- function allowRowToWrap(row) {
11215
- const display = row.ownerDocument.defaultView?.getComputedStyle(row).display ?? "";
11216
- if (display === "flex" || display === "inline-flex") row.style.flexWrap = "wrap";
11217
10663
  }
11218
10664
  function applySocialsDisplayFromContent(content, root = document) {
11219
10665
  const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
@@ -12101,12 +11547,17 @@ function deleteFooterColumn(column) {
12101
11547
  }
12102
11548
 
12103
11549
  // src/lib/logo-identity.ts
12104
- var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
12105
- var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
11550
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text", "nav-logo", "logo"];
11551
+ var LOGO_IMAGE_KEYS = [
11552
+ "nav-logo-image",
11553
+ "footer-logo",
11554
+ "footer-logo-image",
11555
+ "logo-image",
11556
+ "footer-logo-img"
11557
+ ];
12106
11558
  var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
12107
11559
  var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
12108
11560
  var LOGO_ALT_KEY = "logo-alt";
12109
- var LOGO_IMAGE_URL_KEY = "nav-logo-image";
12110
11561
  var PLACEHOLDER_BUSINESS_NAME = "Business name";
12111
11562
  function resolveLogoDisplayText(text) {
12112
11563
  const trimmed = (text ?? "").trim();
@@ -12126,6 +11577,21 @@ function ensureLogoHrefKey(root) {
12126
11577
  if (root.hasAttribute("data-ohw-href-key")) return;
12127
11578
  root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
12128
11579
  }
11580
+ function logoTextElement(root) {
11581
+ const SELECTOR = '[data-ohw-editable="plain"], [data-ohw-editable="text"]';
11582
+ if (root.matches(SELECTOR)) return root;
11583
+ const marked = root.querySelector(SELECTOR);
11584
+ if (marked) return marked;
11585
+ const hasOwnText = Array.from(root.childNodes).some(
11586
+ (node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
11587
+ );
11588
+ return hasOwnText ? root : null;
11589
+ }
11590
+ function logoRootImage(root) {
11591
+ const img = root.querySelector("img");
11592
+ const src = img?.getAttribute("src")?.trim() ?? "";
11593
+ return img && src && img.style.display !== "none" ? img : null;
11594
+ }
12129
11595
  function applyLogoIdentity(text, isPlaceholder) {
12130
11596
  const display = resolveLogoDisplayText(text);
12131
11597
  const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
@@ -12143,6 +11609,9 @@ function applyLogoIdentity(text, isPlaceholder) {
12143
11609
  document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
12144
11610
  if (placeholder) el.setAttribute("data-ohw-placeholder", "");
12145
11611
  else el.removeAttribute("data-ohw-placeholder");
11612
+ if (logoRootImage(el)) return;
11613
+ const textEl = logoTextElement(el);
11614
+ if (textEl && textEl.textContent !== display) textEl.textContent = display;
12146
11615
  });
12147
11616
  return display;
12148
11617
  }
@@ -12153,7 +11622,7 @@ function applyLogoImage(url, alt) {
12153
11622
  const imageKey = imageKeyForRoot(root);
12154
11623
  const textKey = textKeyForRoot(root);
12155
11624
  let img = root.querySelector(`img[data-ohw-key="${imageKey}"]`) ?? (root.querySelector(`[data-ohw-key="${imageKey}"]`) instanceof HTMLImageElement ? root.querySelector(`[data-ohw-key="${imageKey}"]`) : null) ?? root.querySelector("img");
12156
- let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
11625
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]') ?? logoTextElement(root);
12157
11626
  if (url) {
12158
11627
  if (!img) {
12159
11628
  img = document.createElement("img");
@@ -12175,7 +11644,11 @@ function applyLogoImage(url, alt) {
12175
11644
  img.src = url;
12176
11645
  img.alt = displayAlt;
12177
11646
  img.style.display = "block";
12178
- if (textEl) textEl.style.display = "none";
11647
+ if (textEl === root) {
11648
+ Array.from(root.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).forEach((node) => node.remove());
11649
+ } else if (textEl) {
11650
+ textEl.style.display = "none";
11651
+ }
12179
11652
  root.removeAttribute("data-ohw-placeholder");
12180
11653
  return;
12181
11654
  }
@@ -12224,6 +11697,13 @@ function readLogoIdentityFromDom() {
12224
11697
  }
12225
11698
  let text = PLACEHOLDER_BUSINESS_NAME;
12226
11699
  let isPlaceholder = true;
11700
+ const rootWithText = Array.from(
11701
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
11702
+ ).find((root) => logoTextElement(root)?.textContent?.trim());
11703
+ if (rootWithText) {
11704
+ text = logoTextElement(rootWithText).textContent.trim();
11705
+ isPlaceholder = rootWithText.hasAttribute("data-ohw-placeholder") || text === PLACEHOLDER_BUSINESS_NAME;
11706
+ }
12227
11707
  for (const key of LOGO_TEXT_KEYS) {
12228
11708
  const el = document.querySelector(`[data-ohw-key="${key}"]`);
12229
11709
  if (el?.textContent?.trim()) {
@@ -12254,7 +11734,7 @@ function applyLogoFromContent(content) {
12254
11734
  if (!hasLogoIdentity) return false;
12255
11735
  const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
12256
11736
  const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
12257
- const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11737
+ const rawLogoImage = LOGO_IMAGE_KEYS.map((key) => content[key]).find((value) => typeof value === "string" && value.trim()) ?? null;
12258
11738
  const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
12259
11739
  const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
12260
11740
  const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
@@ -12389,7 +11869,6 @@ function readLogoSizeState(content, placement) {
12389
11869
  function getLogoElement(el) {
12390
11870
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12391
11871
  if (marked) return marked;
12392
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12393
11872
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12394
11873
  if (!root) return null;
12395
11874
  const anchor = el.closest("a");
@@ -13263,425 +12742,98 @@ function useNavItemDrag({
13263
12742
  };
13264
12743
  }
13265
12744
 
13266
- // src/useSectionDrag.ts
13267
- var import_react15 = require("react");
12745
+ // src/ui/footer-container-chrome.tsx
12746
+ var import_lucide_react15 = require("lucide-react");
12747
+ var import_jsx_runtime29 = require("react/jsx-runtime");
12748
+ function FooterContainerChrome({
12749
+ rect,
12750
+ onAdd,
12751
+ addDisabled = false
12752
+ }) {
12753
+ const chromeGap = 6;
12754
+ const buttonMargin = 7;
12755
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12756
+ "div",
12757
+ {
12758
+ "data-ohw-footer-container-chrome": "",
12759
+ "data-ohw-bridge": "",
12760
+ className: "pointer-events-none fixed z-[2147483647]",
12761
+ style: {
12762
+ top: rect.top - chromeGap,
12763
+ left: rect.left - chromeGap,
12764
+ width: rect.width + chromeGap * 2,
12765
+ height: rect.height + chromeGap * 2
12766
+ },
12767
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12768
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12769
+ "button",
12770
+ {
12771
+ type: "button",
12772
+ "data-ohw-footer-add-button": "",
12773
+ disabled: addDisabled,
12774
+ 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",
12775
+ style: { top: chromeGap - buttonMargin },
12776
+ "aria-label": "Add item",
12777
+ onMouseDown: (e) => {
12778
+ e.preventDefault();
12779
+ e.stopPropagation();
12780
+ },
12781
+ onClick: (e) => {
12782
+ e.preventDefault();
12783
+ e.stopPropagation();
12784
+ if (addDisabled) return;
12785
+ onAdd();
12786
+ },
12787
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12788
+ }
12789
+ ) }),
12790
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12791
+ ] })
12792
+ }
12793
+ ) });
12794
+ }
13268
12795
 
13269
- // src/lib/section-dnd.ts
13270
- function isFooterSection(el) {
13271
- return el.dataset.ohwSection === "footer";
12796
+ // src/lib/carousel.ts
12797
+ var import_react15 = require("react");
12798
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12799
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12800
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12801
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12802
+ function listCarouselKeys() {
12803
+ const keys = /* @__PURE__ */ new Set();
12804
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12805
+ const key = el.getAttribute("data-ohw-key");
12806
+ if (key) keys.add(key);
12807
+ });
12808
+ return [...keys];
13272
12809
  }
13273
- function buildSectionDropSlots(draggedInstanceId) {
13274
- const sections = topLevelSections().filter(
13275
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12810
+ function containersForKey(key) {
12811
+ return Array.from(
12812
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13276
12813
  );
13277
- const slots = [];
13278
- if (sections.length === 0) return slots;
13279
- const left = 0;
13280
- const width = document.documentElement.clientWidth;
13281
- for (let i = 0; i <= sections.length; i++) {
13282
- let y;
13283
- if (i === 0) {
13284
- y = sections[0].getBoundingClientRect().top;
13285
- } else if (i === sections.length) {
13286
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13287
- } else {
13288
- const prev = sections[i - 1].getBoundingClientRect();
13289
- const next = sections[i].getBoundingClientRect();
13290
- y = (prev.bottom + next.top) / 2;
13291
- }
13292
- slots.push({ insertIndex: i, y, left, width });
13293
- }
13294
- return slots;
13295
12814
  }
13296
- function hitTestSectionDropSlot(y, slots) {
13297
- let best = null;
13298
- for (const slot of slots) {
13299
- const dist = Math.abs(y - slot.y);
13300
- if (!best || dist < best.dist) best = { slot, dist };
12815
+ function isCarouselKey(key) {
12816
+ return containersForKey(key).length > 0;
12817
+ }
12818
+ function parseSlides(raw) {
12819
+ if (!raw) return [];
12820
+ try {
12821
+ const parsed = JSON.parse(raw);
12822
+ if (!Array.isArray(parsed)) return [];
12823
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12824
+ } catch {
12825
+ return [];
13301
12826
  }
13302
- return best?.slot ?? null;
13303
12827
  }
13304
-
13305
- // src/useSectionDrag.ts
13306
- var PRESS_THRESHOLD = 10;
13307
- var EDGE_ZONE = 60;
13308
- var MAX_AUTO_SCROLL_SPEED = 18;
13309
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13310
- "[data-ohw-toolbar]",
13311
- "[data-ohw-edit-chrome]",
13312
- "[data-ohw-item-interaction]",
13313
- "[data-ohw-drag-handle-container]",
13314
- '[data-slot="drag-handle"]',
13315
- "[data-ohw-item-toolbar-anchor]",
13316
- "[data-ohw-item-drag-surface]",
13317
- "[data-ohw-more-menu]",
13318
- '[data-slot="dropdown-menu-content"]',
13319
- '[data-slot="dropdown-menu-item"]',
13320
- "[data-ohw-state-toggle]",
13321
- "[data-ohw-max-badge]",
13322
- "[data-ohw-floating-panel]",
13323
- "[data-ohw-section-picker]",
13324
- "[data-ohw-link-popover-root]",
13325
- "[data-ohw-link-modal-root]",
13326
- "[data-ohw-link-page-dropdown]",
13327
- '[data-slot="popover-content"]',
13328
- '[data-slot="dialog-content"]',
13329
- '[data-slot="dialog-overlay"]',
13330
- "[data-ohw-ai-review]",
13331
- "[data-ohw-editable]",
13332
- "[data-ohw-editable-state]",
13333
- "[contenteditable]",
13334
- "[data-ohw-href-key]",
13335
- "[data-ohw-footer-col]",
13336
- "[data-ohw-social-label]",
13337
- "a",
13338
- "button",
13339
- '[role="button"]',
13340
- '[data-ohw-role="navbar-button"]',
13341
- '[data-ohw-role="button"]',
13342
- "[data-ohw-carousel]",
13343
- "[data-ohw-carousel-value]",
13344
- "[data-ohw-carousel-slide]",
13345
- "[data-ohw-carousel-overlay]",
13346
- "[data-ohw-media-chrome]",
13347
- "[data-ohw-media-overlay]",
13348
- "[data-ohw-media-skeleton]"
13349
- ].join(", ");
13350
- function visibleClip(ps) {
13351
- if (!ps) return null;
13352
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13353
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13354
- return { top, bottom: Math.max(top, bottom) };
13355
- }
13356
- function useSectionDrag({
13357
- isEditMode,
13358
- editContentRef,
13359
- postToParentRef,
13360
- parentScrollRef,
13361
- navDragRef,
13362
- footerDragRef,
13363
- suppressNextClickRef,
13364
- suppressClickUntilRef
13365
- }) {
13366
- const sectionDragRef = (0, import_react15.useRef)(null);
13367
- const [sectionDropSlots, setSectionDropSlots] = (0, import_react15.useState)([]);
13368
- const [activeSectionDropIndex, setActiveSectionDropIndex] = (0, import_react15.useState)(null);
13369
- const [isSectionDragging, setIsSectionDragging] = (0, import_react15.useState)(false);
13370
- const sectionPointerDragRef = (0, import_react15.useRef)(null);
13371
- const autoScrollRafRef = (0, import_react15.useRef)(null);
13372
- const autoScrollDeltaRef = (0, import_react15.useRef)(0);
13373
- const stopAutoScroll = (0, import_react15.useCallback)(() => {
13374
- if (autoScrollRafRef.current != null) {
13375
- cancelAnimationFrame(autoScrollRafRef.current);
13376
- autoScrollRafRef.current = null;
13377
- }
13378
- autoScrollDeltaRef.current = 0;
13379
- }, []);
13380
- const tickAutoScroll = (0, import_react15.useCallback)(() => {
13381
- if (!sectionDragRef.current) {
13382
- stopAutoScroll();
13383
- return;
13384
- }
13385
- if (autoScrollDeltaRef.current !== 0) {
13386
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13387
- }
13388
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13389
- }, [postToParentRef, stopAutoScroll]);
13390
- const updateAutoScroll = (0, import_react15.useCallback)(
13391
- (clientY) => {
13392
- const clip = visibleClip(parentScrollRef.current);
13393
- let delta = 0;
13394
- if (clip) {
13395
- const distTop = clientY - clip.top;
13396
- const distBottom = clip.bottom - clientY;
13397
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13398
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13399
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13400
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13401
- }
13402
- }
13403
- autoScrollDeltaRef.current = delta;
13404
- if (delta !== 0 && autoScrollRafRef.current == null) {
13405
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13406
- } else if (delta === 0) {
13407
- stopAutoScroll();
13408
- }
13409
- },
13410
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13411
- );
13412
- const clearSectionDragVisuals = (0, import_react15.useCallback)(() => {
13413
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13414
- sectionDragRef.current = null;
13415
- setSectionDropSlots([]);
13416
- setActiveSectionDropIndex(null);
13417
- setIsSectionDragging(false);
13418
- stopAutoScroll();
13419
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13420
- unlockItemDragInteraction();
13421
- }, [stopAutoScroll]);
13422
- const refreshSectionDragVisuals = (0, import_react15.useCallback)(
13423
- (session, clientX, clientY) => {
13424
- session.lastClientX = clientX;
13425
- session.lastClientY = clientY;
13426
- const slots = buildSectionDropSlots(session.instanceId);
13427
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13428
- session.activeSlot = activeSlot;
13429
- setSectionDropSlots(slots);
13430
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13431
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13432
- updateAutoScroll(clientY);
13433
- },
13434
- [updateAutoScroll]
13435
- );
13436
- const beginSectionDrag = (0, import_react15.useCallback)(
13437
- (session) => {
13438
- sectionDragRef.current = session;
13439
- setIsSectionDragging(true);
13440
- lockItemDuringDrag();
13441
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13442
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13443
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13444
- },
13445
- [refreshSectionDragVisuals]
13446
- );
13447
- const commitSectionDrag = (0, import_react15.useCallback)(() => {
13448
- const session = sectionDragRef.current;
13449
- if (!session) {
13450
- clearSectionDragVisuals();
13451
- return;
13452
- }
13453
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13454
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13455
- if (!entries) {
13456
- clearSectionDragVisuals();
13457
- return;
13458
- }
13459
- const orderJson = JSON.stringify(entries);
13460
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13461
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13462
- applyPersistedOrder(entries);
13463
- clearSectionDragVisuals();
13464
- requestAnimationFrame(() => {
13465
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13466
- applyPersistedOrder(entries);
13467
- }
13468
- requestAnimationFrame(() => {
13469
- window.dispatchEvent(new Event("resize"));
13470
- });
13471
- });
13472
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13473
- const startSectionPressDrag = (0, import_react15.useCallback)(
13474
- (el, clientX, clientY, pointerId) => {
13475
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13476
- const instanceId = instanceIdOf(el);
13477
- if (!instanceId) return false;
13478
- sectionPointerDragRef.current = {
13479
- el,
13480
- instanceId,
13481
- startX: clientX,
13482
- startY: clientY,
13483
- pointerId,
13484
- started: false
13485
- };
13486
- return true;
13487
- },
13488
- [footerDragRef, navDragRef]
13489
- );
13490
- (0, import_react15.useEffect)(() => {
13491
- if (!isEditMode) return;
13492
- const onPointerDown = (e) => {
13493
- if (e.button !== 0) return;
13494
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13495
- if (sectionPointerDragRef.current) return;
13496
- const target = e.target;
13497
- if (!(target instanceof HTMLElement)) return;
13498
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13499
- const sectionEl = target.closest("[data-ohw-section]");
13500
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13501
- if (!topLevelSections().includes(sectionEl)) return;
13502
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13503
- };
13504
- const onPointerMove = (e) => {
13505
- const pending = sectionPointerDragRef.current;
13506
- if (!pending) return;
13507
- if (pending.started) {
13508
- e.preventDefault();
13509
- clearTextSelection();
13510
- const session = sectionDragRef.current;
13511
- if (!session) return;
13512
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13513
- return;
13514
- }
13515
- const dx = e.clientX - pending.startX;
13516
- const dy = e.clientY - pending.startY;
13517
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13518
- e.preventDefault();
13519
- pending.started = true;
13520
- armItemPressDrag();
13521
- clearTextSelection();
13522
- try {
13523
- document.body.setPointerCapture(pending.pointerId);
13524
- } catch {
13525
- }
13526
- beginSectionDrag({
13527
- instanceId: pending.instanceId,
13528
- draggedEl: pending.el,
13529
- lastClientX: e.clientX,
13530
- lastClientY: e.clientY,
13531
- activeSlot: null
13532
- });
13533
- };
13534
- const endPointerDrag = (e) => {
13535
- const pending = sectionPointerDragRef.current;
13536
- sectionPointerDragRef.current = null;
13537
- try {
13538
- if (document.body.hasPointerCapture(e.pointerId)) {
13539
- document.body.releasePointerCapture(e.pointerId);
13540
- }
13541
- } catch {
13542
- }
13543
- if (!pending) return;
13544
- if (!pending.started) {
13545
- unlockItemDragInteraction();
13546
- return;
13547
- }
13548
- suppressNextClickRef.current = true;
13549
- suppressClickUntilRef.current = Date.now() + 500;
13550
- commitSectionDrag();
13551
- };
13552
- const onKeyDown = (e) => {
13553
- if (e.key !== "Escape") return;
13554
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13555
- sectionPointerDragRef.current = null;
13556
- clearSectionDragVisuals();
13557
- };
13558
- document.addEventListener("pointerdown", onPointerDown, true);
13559
- document.addEventListener("pointermove", onPointerMove, true);
13560
- document.addEventListener("pointerup", endPointerDrag, true);
13561
- document.addEventListener("pointercancel", endPointerDrag, true);
13562
- document.addEventListener("keydown", onKeyDown, true);
13563
- return () => {
13564
- document.removeEventListener("pointerdown", onPointerDown, true);
13565
- document.removeEventListener("pointermove", onPointerMove, true);
13566
- document.removeEventListener("pointerup", endPointerDrag, true);
13567
- document.removeEventListener("pointercancel", endPointerDrag, true);
13568
- document.removeEventListener("keydown", onKeyDown, true);
13569
- unlockItemDragInteraction();
13570
- stopAutoScroll();
13571
- };
13572
- }, [
13573
- beginSectionDrag,
13574
- clearSectionDragVisuals,
13575
- commitSectionDrag,
13576
- footerDragRef,
13577
- isEditMode,
13578
- navDragRef,
13579
- refreshSectionDragVisuals,
13580
- startSectionPressDrag,
13581
- stopAutoScroll,
13582
- suppressClickUntilRef,
13583
- suppressNextClickRef
13584
- ]);
13585
- return {
13586
- sectionDragRef,
13587
- sectionDropSlots,
13588
- activeSectionDropIndex,
13589
- isSectionDragging
13590
- };
13591
- }
13592
-
13593
- // src/ui/footer-container-chrome.tsx
13594
- var import_lucide_react15 = require("lucide-react");
13595
- var import_jsx_runtime29 = require("react/jsx-runtime");
13596
- function FooterContainerChrome({
13597
- rect,
13598
- onAdd,
13599
- addDisabled = false
13600
- }) {
13601
- const chromeGap = 6;
13602
- const buttonMargin = 7;
13603
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13604
- "div",
13605
- {
13606
- "data-ohw-footer-container-chrome": "",
13607
- "data-ohw-bridge": "",
13608
- className: "pointer-events-none fixed z-[2147483647]",
13609
- style: {
13610
- top: rect.top - chromeGap,
13611
- left: rect.left - chromeGap,
13612
- width: rect.width + chromeGap * 2,
13613
- height: rect.height + chromeGap * 2
13614
- },
13615
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
13616
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13617
- "button",
13618
- {
13619
- type: "button",
13620
- "data-ohw-footer-add-button": "",
13621
- disabled: addDisabled,
13622
- 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",
13623
- style: { top: chromeGap - buttonMargin },
13624
- "aria-label": "Add item",
13625
- onMouseDown: (e) => {
13626
- e.preventDefault();
13627
- e.stopPropagation();
13628
- },
13629
- onClick: (e) => {
13630
- e.preventDefault();
13631
- e.stopPropagation();
13632
- if (addDisabled) return;
13633
- onAdd();
13634
- },
13635
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13636
- }
13637
- ) }),
13638
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13639
- ] })
13640
- }
13641
- ) });
13642
- }
13643
-
13644
- // src/lib/carousel.ts
13645
- var import_react16 = require("react");
13646
- var CAROUSEL_ATTR = "data-ohw-carousel";
13647
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13648
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13649
- var CAROUSEL_EVENT = "ohw:carousel-change";
13650
- function listCarouselKeys() {
13651
- const keys = /* @__PURE__ */ new Set();
13652
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13653
- const key = el.getAttribute("data-ohw-key");
13654
- if (key) keys.add(key);
13655
- });
13656
- return [...keys];
13657
- }
13658
- function containersForKey(key) {
13659
- return Array.from(
13660
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13661
- );
13662
- }
13663
- function isCarouselKey(key) {
13664
- return containersForKey(key).length > 0;
13665
- }
13666
- function parseSlides(raw) {
13667
- if (!raw) return [];
13668
- try {
13669
- const parsed = JSON.parse(raw);
13670
- if (!Array.isArray(parsed)) return [];
13671
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13672
- } catch {
13673
- return [];
13674
- }
13675
- }
13676
- function readCarouselValue(key) {
13677
- const container = containersForKey(key)[0];
13678
- if (!container) return [];
13679
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
13680
- if (fromAttr.length > 0) return fromAttr;
13681
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
13682
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
13683
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
13684
- });
12828
+ function readCarouselValue(key) {
12829
+ const container = containersForKey(key)[0];
12830
+ if (!container) return [];
12831
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
12832
+ if (fromAttr.length > 0) return fromAttr;
12833
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
12834
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
12835
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
12836
+ });
13685
12837
  }
13686
12838
  function slideIndex(el) {
13687
12839
  const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
@@ -13704,8 +12856,8 @@ function applyCarouselNode(key, val) {
13704
12856
  return true;
13705
12857
  }
13706
12858
  function useOhwCarousel(key, initial) {
13707
- const [images, setImages] = (0, import_react16.useState)(initial);
13708
- (0, import_react16.useEffect)(() => {
12859
+ const [images, setImages] = (0, import_react15.useState)(initial);
12860
+ (0, import_react15.useEffect)(() => {
13709
12861
  const el = document.querySelector(
13710
12862
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13711
12863
  );
@@ -13783,7 +12935,7 @@ function collectEditableNodes(extraContent, root = document) {
13783
12935
  nodes.push({ key, type: "link", text: href });
13784
12936
  }
13785
12937
  if (extraContent) {
13786
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12938
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13787
12939
  const text = extraContent[key];
13788
12940
  if (typeof text === "string" && text.length > 0) {
13789
12941
  nodes.push({ key, type: "meta", text });
@@ -13820,18 +12972,6 @@ function collectEditableNodes(extraContent, root = document) {
13820
12972
  }
13821
12973
  if (extraContent && !isScoped) {
13822
12974
  applyNavFooterDeleteOverrides(byKey, extraContent);
13823
- for (const key of LOGO_IMAGE_KEYS) {
13824
- if (!(key in extraContent)) continue;
13825
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13826
- }
13827
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13828
- if (!(key in extraContent)) continue;
13829
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13830
- }
13831
- for (const key of LOGO_SIZE_KEYS) {
13832
- if (!(key in extraContent)) continue;
13833
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13834
- }
13835
12975
  }
13836
12976
  return Array.from(byKey.values());
13837
12977
  }
@@ -14236,7 +13376,6 @@ function fadeInImageElement(img, onReady) {
14236
13376
  function applyEditableImageSrc(img, url) {
14237
13377
  img.removeAttribute("srcset");
14238
13378
  img.removeAttribute("sizes");
14239
- if (img.loading === "lazy") img.loading = "eager";
14240
13379
  img.src = url;
14241
13380
  }
14242
13381
  function fadeInBgImage(el, url, onReady) {
@@ -14301,10 +13440,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14301
13440
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14302
13441
  };
14303
13442
  }
14304
- function resolveEntryAnchor(entry) {
14305
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14306
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14307
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13443
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13444
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13445
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13446
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13447
+ return { effectiveInsertAfter, insertBefore };
13448
+ }
13449
+ function getSchedulingMountPoint(insertAfter) {
13450
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13451
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13452
+ if (!anchorEl && anchor === "scheduling") {
13453
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13454
+ anchorEl = widgets.at(-1) ?? null;
13455
+ }
13456
+ if (!anchorEl) return null;
13457
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14308
13458
  }
14309
13459
  function schedulingMountDepth(insertAfter) {
14310
13460
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14321,7 +13471,8 @@ function getPageSchedulingEntries(raw) {
14321
13471
  }
14322
13472
  }
14323
13473
  function isSchedulingWidgetMissing(entry) {
14324
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13474
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13475
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14325
13476
  }
14326
13477
  function hasMissingSchedulingWidgets(entries) {
14327
13478
  return entries.some(isSchedulingWidgetMissing);
@@ -14351,17 +13502,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14351
13502
  } catch {
14352
13503
  }
14353
13504
  }
14354
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14355
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14356
- const sectionId = schedulingSectionId(widgetId);
13505
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13506
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13507
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14357
13508
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14358
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14359
- if (!anchorEl) return false;
14360
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13509
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13510
+ if (!mountPoint) return false;
14361
13511
  const container = document.createElement("div");
14362
13512
  container.dataset.ohwSectionContainer = "scheduling";
14363
- if (beforeId) {
14364
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13513
+ if (insertBefore) {
13514
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14365
13515
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14366
13516
  if (!beforePoint) return false;
14367
13517
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14372,25 +13522,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14372
13522
  }
14373
13523
  tail.insertAdjacentElement("afterend", container);
14374
13524
  }
14375
- try {
14376
- const root = (0, import_client2.createRoot)(container);
14377
- (0, import_react_dom3.flushSync)(() => {
14378
- root.render(
14379
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14380
- SchedulingWidget,
14381
- {
14382
- notifyOnConnect,
14383
- initialScheduleId: scheduleId,
14384
- insertAfter: widgetId
14385
- }
14386
- )
14387
- );
14388
- });
14389
- } catch (err) {
14390
- console.error("[ow:scheduling] render threw", err);
14391
- container.remove();
14392
- return false;
14393
- }
13525
+ const root = (0, import_client2.createRoot)(container);
13526
+ (0, import_react_dom3.flushSync)(() => {
13527
+ root.render(
13528
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13529
+ SchedulingWidget,
13530
+ {
13531
+ notifyOnConnect,
13532
+ initialScheduleId: scheduleId,
13533
+ insertAfter: effectiveInsertAfter
13534
+ }
13535
+ )
13536
+ );
13537
+ });
14394
13538
  const tracker = getSectionsTracker();
14395
13539
  let sections = [];
14396
13540
  try {
@@ -14398,12 +13542,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14398
13542
  } catch {
14399
13543
  }
14400
13544
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14401
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13545
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14402
13546
  sections.push({
14403
13547
  type: "scheduling",
14404
- insertAfter: widgetId,
14405
- anchorId,
14406
- beforeId: beforeId ?? null,
13548
+ insertAfter: effectiveInsertAfter,
14407
13549
  pagePath: window.location.pathname,
14408
13550
  ...scheduleId ? { scheduleId } : {}
14409
13551
  });
@@ -14417,8 +13559,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14417
13559
  for (let i = pending.length - 1; i >= 0; i--) {
14418
13560
  const entry = pending[i];
14419
13561
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14420
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14421
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13562
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14422
13563
  pending.splice(i, 1);
14423
13564
  }
14424
13565
  }
@@ -14566,13 +13707,6 @@ function isInsideLinkEditor(target) {
14566
13707
  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"]')
14567
13708
  );
14568
13709
  }
14569
- function isInsideFloatingPanel(target) {
14570
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14571
- }
14572
- function isPointOverFloatingPanel(clientX, clientY) {
14573
- const el = document.elementFromPoint(clientX, clientY);
14574
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14575
- }
14576
13710
  function getHrefKeyFromElement(el) {
14577
13711
  if (!el) return null;
14578
13712
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14723,6 +13857,13 @@ function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
14723
13857
  if (isPointOverNavItem(column, clientX, clientY)) return null;
14724
13858
  return column;
14725
13859
  }
13860
+ function isPointOverLogo(x, y) {
13861
+ for (const root of document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')) {
13862
+ const r2 = root.getBoundingClientRect();
13863
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
13864
+ }
13865
+ return false;
13866
+ }
14726
13867
  function isPointOverNavigation(x, y) {
14727
13868
  const roots = /* @__PURE__ */ new Set();
14728
13869
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
@@ -14811,7 +13952,7 @@ function getNavigationSelectionParent(el) {
14811
13952
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14812
13953
  return getFooterLinksContainer();
14813
13954
  }
14814
- 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)) {
13955
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14815
13956
  return getNavigationRoot(el);
14816
13957
  }
14817
13958
  return null;
@@ -15280,9 +14421,9 @@ function FloatingToolbar({
15280
14421
  showEditLink,
15281
14422
  onEditLink
15282
14423
  }) {
15283
- const localRef = import_react17.default.useRef(null);
15284
- const [measuredW, setMeasuredW] = import_react17.default.useState(330);
15285
- const setRefs = import_react17.default.useCallback(
14424
+ const localRef = import_react16.default.useRef(null);
14425
+ const [measuredW, setMeasuredW] = import_react16.default.useState(330);
14426
+ const setRefs = import_react16.default.useCallback(
15286
14427
  (node) => {
15287
14428
  localRef.current = node;
15288
14429
  if (typeof elRef === "function") elRef(node);
@@ -15294,7 +14435,7 @@ function FloatingToolbar({
15294
14435
  },
15295
14436
  [elRef]
15296
14437
  );
15297
- import_react17.default.useLayoutEffect(() => {
14438
+ import_react16.default.useLayoutEffect(() => {
15298
14439
  const node = localRef.current;
15299
14440
  if (!node) return;
15300
14441
  const update = () => {
@@ -15320,7 +14461,7 @@ function FloatingToolbar({
15320
14461
  pointerEvents: "auto"
15321
14462
  },
15322
14463
  children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
15323
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react17.default.Fragment, { children: [
14464
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
15324
14465
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
15325
14466
  btns.map((btn) => {
15326
14467
  const isActive = activeCommands.has(btn.cmd);
@@ -15404,45 +14545,6 @@ function StateToggle({
15404
14545
  );
15405
14546
  }
15406
14547
  var contentCache = /* @__PURE__ */ new Map();
15407
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15408
- var OHW_LOADER_STYLE = {
15409
- position: "fixed",
15410
- inset: 0,
15411
- background: "#fff",
15412
- zIndex: 2147483646,
15413
- display: "flex",
15414
- alignItems: "center",
15415
- justifyContent: "center"
15416
- };
15417
- function OhwLoaderSpinner() {
15418
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15419
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15420
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15421
- "circle",
15422
- {
15423
- cx: "14",
15424
- cy: "14",
15425
- r: "11",
15426
- stroke: "#1C1917",
15427
- strokeWidth: "3",
15428
- strokeDasharray: "17 52",
15429
- strokeLinecap: "round",
15430
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15431
- "animateTransform",
15432
- {
15433
- attributeName: "transform",
15434
- type: "rotate",
15435
- from: "0 14 14",
15436
- to: "360 14 14",
15437
- dur: "0.7s",
15438
- repeatCount: "indefinite"
15439
- }
15440
- )
15441
- }
15442
- )
15443
- ] });
15444
- }
15445
- 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){}})();`;
15446
14548
  function resolveSubdomain(subdomainFromQuery) {
15447
14549
  if (subdomainFromQuery) return subdomainFromQuery;
15448
14550
  if (typeof window !== "undefined") {
@@ -15465,8 +14567,8 @@ function OhhwellsBridge() {
15465
14567
  const router = (0, import_navigation3.useRouter)();
15466
14568
  const searchParams = (0, import_navigation3.useSearchParams)();
15467
14569
  const isEditMode = isEditSessionActive();
15468
- const [bridgeRoot, setBridgeRoot] = (0, import_react17.useState)(null);
15469
- (0, import_react17.useEffect)(() => {
14570
+ const [bridgeRoot, setBridgeRoot] = (0, import_react16.useState)(null);
14571
+ (0, import_react16.useEffect)(() => {
15470
14572
  const figtreeFontId = "ohw-figtree-font";
15471
14573
  if (!document.getElementById(figtreeFontId)) {
15472
14574
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15495,146 +14597,82 @@ function OhhwellsBridge() {
15495
14597
  const subdomain = resolveSubdomain(subdomainFromQuery);
15496
14598
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15497
14599
  useSavedLinkNavigation(isEditMode);
15498
- const postToParent2 = (0, import_react17.useCallback)((data) => {
14600
+ const postToParent2 = (0, import_react16.useCallback)((data) => {
15499
14601
  if (typeof window !== "undefined" && window.parent !== window) {
15500
14602
  window.parent.postMessage(data, "*");
15501
14603
  }
15502
14604
  }, []);
15503
- const [fetchState, setFetchState] = (0, import_react17.useState)("idle");
15504
- const autoSaveTimers = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
15505
- const activeElRef = (0, import_react17.useRef)(null);
15506
- const pointerHeldRef = (0, import_react17.useRef)(false);
15507
- const selectedElRef = (0, import_react17.useRef)(null);
15508
- const selectedHrefKeyRef = (0, import_react17.useRef)(null);
15509
- const selectedFooterColAttrRef = (0, import_react17.useRef)(null);
15510
- const originalContentRef = (0, import_react17.useRef)(null);
15511
- const activeStateElRef = (0, import_react17.useRef)(null);
15512
- const parentScrollRef = (0, import_react17.useRef)(null);
15513
- const visibleViewportRef = (0, import_react17.useRef)(null);
15514
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react17.useState)(null);
15515
- const attachVisibleViewport = (0, import_react17.useCallback)((node) => {
14605
+ const [fetchState, setFetchState] = (0, import_react16.useState)("idle");
14606
+ const autoSaveTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
14607
+ const activeElRef = (0, import_react16.useRef)(null);
14608
+ const pointerHeldRef = (0, import_react16.useRef)(false);
14609
+ const selectedElRef = (0, import_react16.useRef)(null);
14610
+ const selectedHrefKeyRef = (0, import_react16.useRef)(null);
14611
+ const selectedFooterColAttrRef = (0, import_react16.useRef)(null);
14612
+ const originalContentRef = (0, import_react16.useRef)(null);
14613
+ const activeStateElRef = (0, import_react16.useRef)(null);
14614
+ const parentScrollRef = (0, import_react16.useRef)(null);
14615
+ const visibleViewportRef = (0, import_react16.useRef)(null);
14616
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react16.useState)(null);
14617
+ const attachVisibleViewport = (0, import_react16.useCallback)((node) => {
15516
14618
  visibleViewportRef.current = node;
15517
14619
  setDialogPortalContainer(node);
15518
14620
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15519
14621
  }, []);
15520
- const toolbarElRef = (0, import_react17.useRef)(null);
15521
- const glowElRef = (0, import_react17.useRef)(null);
15522
- const hoveredImageRef = (0, import_react17.useRef)(null);
15523
- const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
15524
- const dragOverElRef = (0, import_react17.useRef)(null);
15525
- const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
15526
- const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
15527
- const selectedMediaElRef = (0, import_react17.useRef)(null);
15528
- const clearMediaSelection = (0, import_react17.useCallback)(() => {
15529
- const prev = selectedMediaElRef.current;
15530
- selectedMediaElRef.current = null;
15531
- setSelectedMedia(null);
15532
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15533
- if (sectionEl) {
15534
- postToParentRef.current({
15535
- type: "ow:section-selected",
15536
- sectionId: sectionEl.dataset.ohwSection ?? null,
15537
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15538
- key: null
15539
- });
15540
- }
15541
- }, []);
15542
- const clearMediaSelectionRef = (0, import_react17.useRef)(clearMediaSelection);
15543
- clearMediaSelectionRef.current = clearMediaSelection;
15544
- const selectMediaElement = (0, import_react17.useCallback)((el) => {
15545
- const r2 = el.getBoundingClientRect();
15546
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15547
- selectedMediaElRef.current = el;
15548
- setSelectedMedia({
15549
- key: el.dataset.ohwKey ?? "",
15550
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15551
- elementType: el.dataset.ohwEditable ?? "image",
15552
- hasTextOverlap: false,
15553
- isDragOver: false,
15554
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15555
- });
15556
- const sectionEl = el.closest("[data-ohw-section]");
15557
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15558
- postToParentRef.current({
15559
- type: "ow:section-selected",
15560
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15561
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15562
- key: el.dataset.ohwKey ?? null,
15563
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15564
- // bridge knows what the node IS, so it names it.
15565
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : "Image"
15566
- });
15567
- }, []);
15568
- const selectMediaElementRef = (0, import_react17.useRef)(selectMediaElement);
15569
- selectMediaElementRef.current = selectMediaElement;
15570
- (0, import_react17.useEffect)(() => {
15571
- if (!selectedMedia) return;
15572
- const update = () => {
15573
- const el = selectedMediaElRef.current;
15574
- if (!el || !el.isConnected) {
15575
- clearMediaSelection();
15576
- return;
15577
- }
15578
- const r2 = el.getBoundingClientRect();
15579
- setSelectedMedia(
15580
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15581
- );
15582
- };
15583
- window.addEventListener("scroll", update, true);
15584
- window.addEventListener("resize", update);
15585
- return () => {
15586
- window.removeEventListener("scroll", update, true);
15587
- window.removeEventListener("resize", update);
15588
- };
15589
- }, [selectedMedia !== null]);
15590
- const [carouselHover, setCarouselHover] = (0, import_react17.useState)(null);
15591
- const [uploadingRects, setUploadingRects] = (0, import_react17.useState)({});
15592
- const hoveredGapRef = (0, import_react17.useRef)(null);
15593
- const imageUnhoverTimerRef = (0, import_react17.useRef)(null);
15594
- const imageShowTimerRef = (0, import_react17.useRef)(null);
15595
- const editStylesRef = (0, import_react17.useRef)(null);
15596
- const activateRef = (0, import_react17.useRef)(() => {
14622
+ const toolbarElRef = (0, import_react16.useRef)(null);
14623
+ const glowElRef = (0, import_react16.useRef)(null);
14624
+ const hoveredImageRef = (0, import_react16.useRef)(null);
14625
+ const hoveredImageHasTextOverlapRef = (0, import_react16.useRef)(false);
14626
+ const dragOverElRef = (0, import_react16.useRef)(null);
14627
+ const [mediaHover, setMediaHover] = (0, import_react16.useState)(null);
14628
+ const [carouselHover, setCarouselHover] = (0, import_react16.useState)(null);
14629
+ const [uploadingRects, setUploadingRects] = (0, import_react16.useState)({});
14630
+ const hoveredGapRef = (0, import_react16.useRef)(null);
14631
+ const imageUnhoverTimerRef = (0, import_react16.useRef)(null);
14632
+ const imageShowTimerRef = (0, import_react16.useRef)(null);
14633
+ const editStylesRef = (0, import_react16.useRef)(null);
14634
+ const activateRef = (0, import_react16.useRef)(() => {
15597
14635
  });
15598
- const deactivateRef = (0, import_react17.useRef)(() => {
14636
+ const deactivateRef = (0, import_react16.useRef)(() => {
15599
14637
  });
15600
- const selectRef = (0, import_react17.useRef)(() => {
14638
+ const selectRef = (0, import_react16.useRef)(() => {
15601
14639
  });
15602
- const selectFrameRef = (0, import_react17.useRef)(() => {
14640
+ const selectFrameRef = (0, import_react16.useRef)(() => {
15603
14641
  });
15604
- const selectLogoRef = (0, import_react17.useRef)(() => {
14642
+ const selectLogoRef = (0, import_react16.useRef)(() => {
15605
14643
  });
15606
- const openLogoSizePanelRef = (0, import_react17.useRef)(() => {
14644
+ const openLogoSizePanelRef = (0, import_react16.useRef)(() => {
15607
14645
  });
15608
- const deselectRef = (0, import_react17.useRef)(() => {
14646
+ const deselectRef = (0, import_react16.useRef)(() => {
15609
14647
  });
15610
- const closeFloatingPanelOnlyRef = (0, import_react17.useRef)(() => {
14648
+ const closeFloatingPanelOnlyRef = (0, import_react16.useRef)(() => {
15611
14649
  });
15612
- const reselectNavigationItemRef = (0, import_react17.useRef)(() => {
14650
+ const reselectNavigationItemRef = (0, import_react16.useRef)(() => {
15613
14651
  });
15614
- const commitNavigationTextEditRef = (0, import_react17.useRef)(() => {
14652
+ const commitNavigationTextEditRef = (0, import_react16.useRef)(() => {
15615
14653
  });
15616
- const handleDeleteSelectedRef = (0, import_react17.useRef)(() => false);
15617
- const runPendingDeleteUndoRef = (0, import_react17.useRef)(() => false);
15618
- const isFooterFrameSelectionRef = (0, import_react17.useRef)(false);
15619
- const refreshActiveCommandsRef = (0, import_react17.useRef)(() => {
14654
+ const handleDeleteSelectedRef = (0, import_react16.useRef)(() => false);
14655
+ const runPendingDeleteUndoRef = (0, import_react16.useRef)(() => false);
14656
+ const isFooterFrameSelectionRef = (0, import_react16.useRef)(false);
14657
+ const refreshActiveCommandsRef = (0, import_react16.useRef)(() => {
15620
14658
  });
15621
- const postToParentRef = (0, import_react17.useRef)(postToParent2);
14659
+ const postToParentRef = (0, import_react16.useRef)(postToParent2);
15622
14660
  postToParentRef.current = postToParent2;
15623
- const aiSectionApiRef = (0, import_react17.useRef)(null);
15624
- const sectionsLoadedRef = (0, import_react17.useRef)(false);
15625
- const pendingScheduleConfigRequests = (0, import_react17.useRef)([]);
15626
- const [toolbarRect, setToolbarRect] = (0, import_react17.useState)(null);
15627
- const [formPickRect, setFormPickRect] = (0, import_react17.useState)(null);
15628
- const formPickElRef = (0, import_react17.useRef)(null);
15629
- const [formViewState, setFormViewStateUi] = (0, import_react17.useState)("default");
15630
- const [formPickCount, setFormPickCount] = (0, import_react17.useState)(null);
15631
- const [formHoverRect, setFormHoverRect] = (0, import_react17.useState)(null);
15632
- const formHoverElRef = (0, import_react17.useRef)(null);
15633
- const [fieldPickRect, setFieldPickRect] = (0, import_react17.useState)(null);
15634
- const fieldPickElRef = (0, import_react17.useRef)(null);
15635
- const [fieldPickState, setFieldPickState] = (0, import_react17.useState)(null);
15636
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react17.useState)(false);
15637
- const clearFormPick = (0, import_react17.useCallback)(() => {
14661
+ const aiSectionApiRef = (0, import_react16.useRef)(null);
14662
+ const sectionsLoadedRef = (0, import_react16.useRef)(false);
14663
+ const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14664
+ const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
14665
+ const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
14666
+ const formPickElRef = (0, import_react16.useRef)(null);
14667
+ const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
14668
+ const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
14669
+ const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
14670
+ const formHoverElRef = (0, import_react16.useRef)(null);
14671
+ const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
14672
+ const fieldPickElRef = (0, import_react16.useRef)(null);
14673
+ const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
14674
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
14675
+ const clearFormPick = (0, import_react16.useCallback)(() => {
15638
14676
  const form = formPickElRef.current;
15639
14677
  const editing = fieldPickElRef.current;
15640
14678
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15654,7 +14692,7 @@ function OhhwellsBridge() {
15654
14692
  formPickElRef.current = null;
15655
14693
  setFormPickRect(null);
15656
14694
  }, []);
15657
- const clearFieldPick = (0, import_react17.useCallback)(() => {
14695
+ const clearFieldPick = (0, import_react16.useCallback)(() => {
15658
14696
  const wrapper = fieldPickElRef.current;
15659
14697
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15660
14698
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15664,9 +14702,9 @@ function OhhwellsBridge() {
15664
14702
  setFieldPickRect(null);
15665
14703
  setFieldPickState(null);
15666
14704
  }, []);
15667
- const persistFieldsRef = (0, import_react17.useRef)(() => {
14705
+ const persistFieldsRef = (0, import_react16.useRef)(() => {
15668
14706
  });
15669
- const persistFields = (0, import_react17.useCallback)(
14707
+ const persistFields = (0, import_react16.useCallback)(
15670
14708
  (form) => {
15671
14709
  const key = formKeyOf(form);
15672
14710
  if (!key) return;
@@ -15677,7 +14715,7 @@ function OhhwellsBridge() {
15677
14715
  []
15678
14716
  );
15679
14717
  persistFieldsRef.current = persistFields;
15680
- const selectField = (0, import_react17.useCallback)((wrapper) => {
14718
+ const selectField = (0, import_react16.useCallback)((wrapper) => {
15681
14719
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15682
14720
  commitPlaceholderEdit(fieldPickElRef.current);
15683
14721
  }
@@ -15690,7 +14728,7 @@ function OhhwellsBridge() {
15690
14728
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15691
14729
  setFieldTypePickerOpen(false);
15692
14730
  }, []);
15693
- const withSelectedField = (0, import_react17.useCallback)(
14731
+ const withSelectedField = (0, import_react16.useCallback)(
15694
14732
  (run) => {
15695
14733
  const wrapper = fieldPickElRef.current;
15696
14734
  const form = formPickElRef.current;
@@ -15703,28 +14741,28 @@ function OhhwellsBridge() {
15703
14741
  },
15704
14742
  [persistFields]
15705
14743
  );
15706
- const handleFieldTypeChange = (0, import_react17.useCallback)(
14744
+ const handleFieldTypeChange = (0, import_react16.useCallback)(
15707
14745
  (type) => withSelectedField((_form, wrapper) => {
15708
14746
  applyFieldType(wrapper, type);
15709
14747
  selectField(wrapper);
15710
14748
  }),
15711
14749
  [selectField, withSelectedField]
15712
14750
  );
15713
- const handleFieldRequiredToggle = (0, import_react17.useCallback)(
14751
+ const handleFieldRequiredToggle = (0, import_react16.useCallback)(
15714
14752
  () => withSelectedField((_form, wrapper) => {
15715
14753
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15716
14754
  selectField(wrapper);
15717
14755
  }),
15718
14756
  [selectField, withSelectedField]
15719
14757
  );
15720
- const handleFieldDuplicate = (0, import_react17.useCallback)(
14758
+ const handleFieldDuplicate = (0, import_react16.useCallback)(
15721
14759
  () => withSelectedField((form, wrapper) => {
15722
14760
  const copy = duplicateField(form, wrapper);
15723
14761
  selectField(copy);
15724
14762
  }),
15725
14763
  [selectField, withSelectedField]
15726
14764
  );
15727
- const handleFieldDelete = (0, import_react17.useCallback)(
14765
+ const handleFieldDelete = (0, import_react16.useCallback)(
15728
14766
  () => withSelectedField((_form, wrapper) => {
15729
14767
  removeField(wrapper);
15730
14768
  clearFieldPick();
@@ -15732,7 +14770,7 @@ function OhhwellsBridge() {
15732
14770
  }),
15733
14771
  [clearFieldPick, withSelectedField]
15734
14772
  );
15735
- const handleAddField = (0, import_react17.useCallback)(
14773
+ const handleAddField = (0, import_react16.useCallback)(
15736
14774
  (type) => {
15737
14775
  const form = formPickElRef.current;
15738
14776
  if (!form) return;
@@ -15748,8 +14786,8 @@ function OhhwellsBridge() {
15748
14786
  },
15749
14787
  [persistFields, selectField]
15750
14788
  );
15751
- const fieldDragRef = (0, import_react17.useRef)(null);
15752
- const buildFieldDropSlots = (0, import_react17.useCallback)((form, draggedKey) => {
14789
+ const fieldDragRef = (0, import_react16.useRef)(null);
14790
+ const buildFieldDropSlots = (0, import_react16.useCallback)((form, draggedKey) => {
15753
14791
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15754
14792
  const slots = others.map((el) => {
15755
14793
  const rect = el.getBoundingClientRect();
@@ -15762,7 +14800,7 @@ function OhhwellsBridge() {
15762
14800
  }
15763
14801
  return slots;
15764
14802
  }, []);
15765
- const handleFieldDragStart = (0, import_react17.useCallback)(() => {
14803
+ const handleFieldDragStart = (0, import_react16.useCallback)(() => {
15766
14804
  const wrapper = fieldPickElRef.current;
15767
14805
  const form = formPickElRef.current;
15768
14806
  if (!wrapper || !form) return;
@@ -15771,18 +14809,18 @@ function OhhwellsBridge() {
15771
14809
  setFieldDragging(true);
15772
14810
  setFieldDropSlots(buildFieldDropSlots(form, key));
15773
14811
  }, [buildFieldDropSlots]);
15774
- const handleFieldDragEnd = (0, import_react17.useCallback)(() => {
14812
+ const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
15775
14813
  fieldDragRef.current = null;
15776
14814
  setFieldDropIndex(null);
15777
14815
  setFieldDropSlots([]);
15778
14816
  setFieldDragging(false);
15779
14817
  }, []);
15780
- const [fieldDropIndex, setFieldDropIndex] = (0, import_react17.useState)(null);
15781
- const [fieldDropSlots, setFieldDropSlots] = (0, import_react17.useState)([]);
15782
- const [fieldDragging, setFieldDragging] = (0, import_react17.useState)(false);
15783
- const clearFormPickRef = (0, import_react17.useRef)(clearFormPick);
14818
+ const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
14819
+ const [fieldDropSlots, setFieldDropSlots] = (0, import_react16.useState)([]);
14820
+ const [fieldDragging, setFieldDragging] = (0, import_react16.useState)(false);
14821
+ const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
15784
14822
  clearFormPickRef.current = clearFormPick;
15785
- (0, import_react17.useEffect)(() => {
14823
+ (0, import_react16.useEffect)(() => {
15786
14824
  const el = fieldPickElRef.current;
15787
14825
  if (!el || fieldPickRect === null) return;
15788
14826
  const observer = new ResizeObserver(() => {
@@ -15791,7 +14829,7 @@ function OhhwellsBridge() {
15791
14829
  observer.observe(el);
15792
14830
  return () => observer.disconnect();
15793
14831
  }, [fieldPickRect !== null, fieldPickState]);
15794
- (0, import_react17.useEffect)(() => {
14832
+ (0, import_react16.useEffect)(() => {
15795
14833
  const el = formPickElRef.current;
15796
14834
  if (!el || formPickRect === null) return;
15797
14835
  const observer = new ResizeObserver(() => {
@@ -15800,25 +14838,25 @@ function OhhwellsBridge() {
15800
14838
  observer.observe(el);
15801
14839
  return () => observer.disconnect();
15802
14840
  }, [formPickRect !== null, formViewState]);
15803
- const [toolbarVariant, setToolbarVariant] = (0, import_react17.useState)("none");
15804
- const toolbarVariantRef = (0, import_react17.useRef)("none");
14841
+ const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
14842
+ const toolbarVariantRef = (0, import_react16.useRef)("none");
15805
14843
  toolbarVariantRef.current = toolbarVariant;
15806
- const [selectedIsCta, setSelectedIsCta] = (0, import_react17.useState)(false);
15807
- const [selectedIsSocial, setSelectedIsSocial] = (0, import_react17.useState)(false);
15808
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react17.useState)(false);
15809
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react17.useState)(null);
15810
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react17.useState)(false);
15811
- const [toggleState, setToggleState] = (0, import_react17.useState)(null);
15812
- const [maxBadge, setMaxBadge] = (0, import_react17.useState)(null);
15813
- const [activeCommands, setActiveCommands] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
15814
- const [sectionGap, setSectionGap] = (0, import_react17.useState)(null);
15815
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react17.useState)(false);
15816
- const hoveredNavContainerRef = (0, import_react17.useRef)(null);
15817
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react17.useState)(null);
15818
- const hoveredItemElRef = (0, import_react17.useRef)(null);
15819
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react17.useState)(null);
15820
- const [hoveredTextRect, setHoveredTextRect] = (0, import_react17.useState)(null);
15821
- (0, import_react17.useEffect)(() => {
14844
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react16.useState)(false);
14845
+ const [selectedIsSocial, setSelectedIsSocial] = (0, import_react16.useState)(false);
14846
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react16.useState)(false);
14847
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react16.useState)(null);
14848
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react16.useState)(false);
14849
+ const [toggleState, setToggleState] = (0, import_react16.useState)(null);
14850
+ const [maxBadge, setMaxBadge] = (0, import_react16.useState)(null);
14851
+ const [activeCommands, setActiveCommands] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
14852
+ const [sectionGap, setSectionGap] = (0, import_react16.useState)(null);
14853
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react16.useState)(false);
14854
+ const hoveredNavContainerRef = (0, import_react16.useRef)(null);
14855
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
14856
+ const hoveredItemElRef = (0, import_react16.useRef)(null);
14857
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
14858
+ const [hoveredTextRect, setHoveredTextRect] = (0, import_react16.useState)(null);
14859
+ (0, import_react16.useEffect)(() => {
15822
14860
  const sync = () => {
15823
14861
  const el = document.querySelector(
15824
14862
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15839,56 +14877,43 @@ function OhhwellsBridge() {
15839
14877
  });
15840
14878
  return () => observer.disconnect();
15841
14879
  }, []);
15842
- const siblingHintElRef = (0, import_react17.useRef)(null);
15843
- const [siblingHintRect, setSiblingHintRect] = (0, import_react17.useState)(null);
15844
- const [siblingHintRects, setSiblingHintRects] = (0, import_react17.useState)([]);
15845
- const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
15846
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
14880
+ const siblingHintElRef = (0, import_react16.useRef)(null);
14881
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
14882
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
14883
+ const [isItemDragging, setIsItemDragging] = (0, import_react16.useState)(false);
14884
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react16.useState)(false);
15847
14885
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15848
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
15849
- const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
15850
- const footerDragRef = (0, import_react17.useRef)(null);
15851
- const [footerDropSlots, setFooterDropSlots] = (0, import_react17.useState)([]);
15852
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react17.useState)(null);
15853
- const [draggedItemRect, setDraggedItemRect] = (0, import_react17.useState)(null);
15854
- const footerPointerDragRef = (0, import_react17.useRef)(null);
15855
- const suppressNextClickRef = (0, import_react17.useRef)(false);
15856
- const suppressClickUntilRef = (0, import_react17.useRef)(0);
15857
- const [linkPopover, setLinkPopover] = (0, import_react17.useState)(null);
15858
- const linkPopoverSessionRef = (0, import_react17.useRef)(null);
15859
- const addNavAfterAnchorRef = (0, import_react17.useRef)(null);
15860
- const editContentRef = (0, import_react17.useRef)({});
15861
- const aiSectionsRef = (0, import_react17.useRef)("");
15862
- const brandKitRef = (0, import_react17.useRef)("");
15863
- const stylesRef = (0, import_react17.useRef)("");
15864
- const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
15865
- const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
15866
- const floatingPanelOpenRef = (0, import_react17.useRef)(false);
15867
- const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
15868
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
15869
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
15870
- const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
15871
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
15872
- const [sitePages, setSitePages] = (0, import_react17.useState)([]);
15873
- const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
15874
- const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
15875
- const setLinkPopoverRef = (0, import_react17.useRef)(setLinkPopover);
15876
- const linkPopoverPanelRef = (0, import_react17.useRef)(null);
15877
- const linkPopoverOpenRef = (0, import_react17.useRef)(false);
15878
- const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
14886
+ const [floatingPanel, setFloatingPanel] = (0, import_react16.useState)(null);
14887
+ const floatingPanelOpenRef = (0, import_react16.useRef)(false);
14888
+ floatingPanelOpenRef.current = floatingPanel !== null;
14889
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react16.useState)(null);
14890
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react16.useState)(null);
14891
+ const [editorViewport, setEditorViewport] = (0, import_react16.useState)("desktop");
14892
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react16.useState)(null);
14893
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react16.useState)(null);
14894
+ const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react16.useState)(null);
14895
+ const footerDragRef = (0, import_react16.useRef)(null);
14896
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react16.useState)([]);
14897
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react16.useState)(null);
14898
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react16.useState)(null);
14899
+ const footerPointerDragRef = (0, import_react16.useRef)(null);
14900
+ const suppressNextClickRef = (0, import_react16.useRef)(false);
14901
+ const suppressClickUntilRef = (0, import_react16.useRef)(0);
14902
+ const [linkPopover, setLinkPopover] = (0, import_react16.useState)(null);
14903
+ const linkPopoverSessionRef = (0, import_react16.useRef)(null);
14904
+ const addNavAfterAnchorRef = (0, import_react16.useRef)(null);
14905
+ const editContentRef = (0, import_react16.useRef)({});
14906
+ const aiSectionsRef = (0, import_react16.useRef)("");
14907
+ const pendingDeleteUndoRef = (0, import_react16.useRef)(null);
14908
+ const [sitePages, setSitePages] = (0, import_react16.useState)([]);
14909
+ const [sectionsByPath, setSectionsByPath] = (0, import_react16.useState)({});
14910
+ const sectionsPrefetchGenRef = (0, import_react16.useRef)(0);
14911
+ const setLinkPopoverRef = (0, import_react16.useRef)(setLinkPopover);
14912
+ const linkPopoverPanelRef = (0, import_react16.useRef)(null);
14913
+ const linkPopoverOpenRef = (0, import_react16.useRef)(false);
14914
+ const linkPopoverGraceUntilRef = (0, import_react16.useRef)(0);
15879
14915
  setLinkPopoverRef.current = setLinkPopover;
15880
- setFloatingPanelRef.current = setFloatingPanel;
15881
14916
  linkPopoverSessionRef.current = linkPopover;
15882
- floatingPanelOpenRef.current = Boolean(floatingPanel);
15883
- (0, import_react17.useEffect)(() => {
15884
- const syncViewport = () => {
15885
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
15886
- setEditorViewport((prev) => prev === next ? prev : next);
15887
- };
15888
- syncViewport();
15889
- window.addEventListener("resize", syncViewport);
15890
- return () => window.removeEventListener("resize", syncViewport);
15891
- }, []);
15892
14917
  const {
15893
14918
  navDragRef,
15894
14919
  navDropSlots,
@@ -15921,20 +14946,10 @@ function OhhwellsBridge() {
15921
14946
  getNavigationItemAnchor,
15922
14947
  isDragHandleDisabled
15923
14948
  });
15924
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15925
- isEditMode,
15926
- editContentRef,
15927
- postToParentRef,
15928
- parentScrollRef,
15929
- navDragRef,
15930
- footerDragRef,
15931
- suppressNextClickRef,
15932
- suppressClickUntilRef
15933
- });
15934
14949
  const bumpLinkPopoverGrace = () => {
15935
14950
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15936
14951
  };
15937
- const runSectionsPrefetch = (0, import_react17.useCallback)((pages) => {
14952
+ const runSectionsPrefetch = (0, import_react16.useCallback)((pages) => {
15938
14953
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15939
14954
  const gen = ++sectionsPrefetchGenRef.current;
15940
14955
  const paths = pages.map((p) => p.path);
@@ -15953,9 +14968,9 @@ function OhhwellsBridge() {
15953
14968
  );
15954
14969
  });
15955
14970
  }, [isEditMode, pathname]);
15956
- const runSectionsPrefetchRef = (0, import_react17.useRef)(runSectionsPrefetch);
14971
+ const runSectionsPrefetchRef = (0, import_react16.useRef)(runSectionsPrefetch);
15957
14972
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15958
- (0, import_react17.useEffect)(() => {
14973
+ (0, import_react16.useEffect)(() => {
15959
14974
  if (!linkPopover) {
15960
14975
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15961
14976
  return;
@@ -15983,7 +14998,7 @@ function OhhwellsBridge() {
15983
14998
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15984
14999
  };
15985
15000
  }, [linkPopover, postToParent2]);
15986
- (0, import_react17.useEffect)(() => {
15001
+ (0, import_react16.useEffect)(() => {
15987
15002
  if (!isEditMode) return;
15988
15003
  const useFixtures = shouldUseDevFixtures();
15989
15004
  if (useFixtures) {
@@ -16007,14 +15022,14 @@ function OhhwellsBridge() {
16007
15022
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
16008
15023
  return () => window.removeEventListener("message", onSitePages);
16009
15024
  }, [isEditMode, postToParent2]);
16010
- (0, import_react17.useEffect)(() => {
15025
+ (0, import_react16.useEffect)(() => {
16011
15026
  if (!isEditMode || shouldUseDevFixtures()) return;
16012
15027
  void loadAllSectionsManifest().then((manifest) => {
16013
15028
  if (Object.keys(manifest).length === 0) return;
16014
15029
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
16015
15030
  });
16016
15031
  }, [isEditMode]);
16017
- (0, import_react17.useEffect)(() => {
15032
+ (0, import_react16.useEffect)(() => {
16018
15033
  const update = () => {
16019
15034
  const el = activeElRef.current ?? selectedElRef.current;
16020
15035
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -16038,10 +15053,10 @@ function OhhwellsBridge() {
16038
15053
  vvp.removeEventListener("resize", update);
16039
15054
  };
16040
15055
  }, []);
16041
- const refreshStateRules = (0, import_react17.useCallback)(() => {
15056
+ const refreshStateRules = (0, import_react16.useCallback)(() => {
16042
15057
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
16043
15058
  }, []);
16044
- const processConfigRequest = (0, import_react17.useCallback)((insertAfterVal) => {
15059
+ const processConfigRequest = (0, import_react16.useCallback)((insertAfterVal) => {
16045
15060
  const tracker = getSectionsTracker();
16046
15061
  let entries = [];
16047
15062
  try {
@@ -16064,7 +15079,7 @@ function OhhwellsBridge() {
16064
15079
  }
16065
15080
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
16066
15081
  }, [isEditMode]);
16067
- const deactivate = (0, import_react17.useCallback)(() => {
15082
+ const deactivate = (0, import_react16.useCallback)(() => {
16068
15083
  const el = activeElRef.current;
16069
15084
  if (!el) return;
16070
15085
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16105,12 +15120,12 @@ function OhhwellsBridge() {
16105
15120
  setToolbarShowEditLink(false);
16106
15121
  postToParent2({ type: "ow:exit-edit" });
16107
15122
  }, [postToParent2]);
16108
- const clearSelectedAttr = (0, import_react17.useCallback)(() => {
15123
+ const clearSelectedAttr = (0, import_react16.useCallback)(() => {
16109
15124
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16110
15125
  el.removeAttribute("data-ohw-selected");
16111
15126
  });
16112
15127
  }, []);
16113
- const deselect = (0, import_react17.useCallback)(() => {
15128
+ const deselect = (0, import_react16.useCallback)(() => {
16114
15129
  clearSelectedAttr();
16115
15130
  selectedElRef.current = null;
16116
15131
  selectedHrefKeyRef.current = null;
@@ -16139,12 +15154,11 @@ function OhhwellsBridge() {
16139
15154
  setToolbarVariant("none");
16140
15155
  }
16141
15156
  }, [clearSelectedAttr]);
16142
- const markSelected = (0, import_react17.useCallback)((el) => {
15157
+ const markSelected = (0, import_react16.useCallback)((el) => {
16143
15158
  clearSelectedAttr();
16144
- el.removeAttribute("data-ohw-hovered");
16145
15159
  el.setAttribute("data-ohw-selected", "");
16146
15160
  }, [clearSelectedAttr]);
16147
- const resolveHrefKeyElement = (0, import_react17.useCallback)((hrefKey) => {
15161
+ const resolveHrefKeyElement = (0, import_react16.useCallback)((hrefKey) => {
16148
15162
  if (isFooterHrefKey(hrefKey)) {
16149
15163
  return document.querySelector(
16150
15164
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16159,7 +15173,7 @@ function OhhwellsBridge() {
16159
15173
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16160
15174
  );
16161
15175
  }, []);
16162
- const resyncSelectedNavigationItem = (0, import_react17.useCallback)(() => {
15176
+ const resyncSelectedNavigationItem = (0, import_react16.useCallback)(() => {
16163
15177
  const hrefKey = selectedHrefKeyRef.current;
16164
15178
  if (hrefKey) {
16165
15179
  const link = resolveHrefKeyElement(hrefKey);
@@ -16197,7 +15211,7 @@ function OhhwellsBridge() {
16197
15211
  );
16198
15212
  }
16199
15213
  }, [resolveHrefKeyElement]);
16200
- const reselectNavigationItem = (0, import_react17.useCallback)((navAnchor) => {
15214
+ const reselectNavigationItem = (0, import_react16.useCallback)((navAnchor) => {
16201
15215
  selectedElRef.current = navAnchor;
16202
15216
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16203
15217
  selectedFooterColAttrRef.current = null;
@@ -16228,7 +15242,7 @@ function OhhwellsBridge() {
16228
15242
  setToolbarShowEditLink(false);
16229
15243
  setActiveCommands(/* @__PURE__ */ new Set());
16230
15244
  }, [markSelected]);
16231
- const commitNavigationTextEdit = (0, import_react17.useCallback)((navAnchor) => {
15245
+ const commitNavigationTextEdit = (0, import_react16.useCallback)((navAnchor) => {
16232
15246
  const el = activeElRef.current;
16233
15247
  if (!el) return;
16234
15248
  const key = el.dataset.ohwKey;
@@ -16261,7 +15275,7 @@ function OhhwellsBridge() {
16261
15275
  postToParent2({ type: "ow:exit-edit" });
16262
15276
  reselectNavigationItem(navAnchor);
16263
15277
  }, [postToParent2, reselectNavigationItem]);
16264
- const handleAddTopLevelNavItem = (0, import_react17.useCallback)(() => {
15278
+ const handleAddTopLevelNavItem = (0, import_react16.useCallback)(() => {
16265
15279
  const items = listNavbarRootItems();
16266
15280
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16267
15281
  deselectRef.current();
@@ -16273,7 +15287,7 @@ function OhhwellsBridge() {
16273
15287
  intent: "add-nav"
16274
15288
  });
16275
15289
  }, []);
16276
- const maybeWarnNavLinkDropdownConflict = (0, import_react17.useCallback)(
15290
+ const maybeWarnNavLinkDropdownConflict = (0, import_react16.useCallback)(
16277
15291
  (anchor) => {
16278
15292
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16279
15293
  if (!navDropdownsOpenOnClick()) return;
@@ -16286,7 +15300,7 @@ function OhhwellsBridge() {
16286
15300
  },
16287
15301
  [postToParent2]
16288
15302
  );
16289
- const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
15303
+ const handleNavDropdownOpenChange = (0, import_react16.useCallback)((open) => {
16290
15304
  const selected = selectedElRef.current;
16291
15305
  if (!selected || !isNavigationItem2(selected)) return;
16292
15306
  setNavGroupForceOpen(selected, open);
@@ -16298,7 +15312,7 @@ function OhhwellsBridge() {
16298
15312
  }
16299
15313
  });
16300
15314
  }, []);
16301
- const handleFooterHeadingVisibleChange = (0, import_react17.useCallback)(
15315
+ const handleFooterHeadingVisibleChange = (0, import_react16.useCallback)(
16302
15316
  (visible) => {
16303
15317
  const selected = selectedElRef.current;
16304
15318
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16322,7 +15336,7 @@ function OhhwellsBridge() {
16322
15336
  },
16323
15337
  [postToParent2]
16324
15338
  );
16325
- const enterEditOnNewItem = (0, import_react17.useCallback)((anchor) => {
15339
+ const enterEditOnNewItem = (0, import_react16.useCallback)((anchor) => {
16326
15340
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16327
15341
  if (!label) {
16328
15342
  selectRef.current(anchor);
@@ -16331,7 +15345,7 @@ function OhhwellsBridge() {
16331
15345
  setNavGroupForceOpen(anchor, true);
16332
15346
  activateRef.current(label);
16333
15347
  }, []);
16334
- const handleAddChildItem = (0, import_react17.useCallback)(() => {
15348
+ const handleAddChildItem = (0, import_react16.useCallback)(() => {
16335
15349
  const selected = selectedElRef.current;
16336
15350
  if (!selected) return;
16337
15351
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16443,7 +15457,7 @@ function OhhwellsBridge() {
16443
15457
  enterEditOnNewItem(result.anchor);
16444
15458
  });
16445
15459
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16446
- const handleAddFooterColumn = (0, import_react17.useCallback)(() => {
15460
+ const handleAddFooterColumn = (0, import_react16.useCallback)(() => {
16447
15461
  if (!canAddFooterColumn()) {
16448
15462
  postToParent2({
16449
15463
  type: "ow:toast",
@@ -16464,7 +15478,7 @@ function OhhwellsBridge() {
16464
15478
  selectRef.current(result.firstLink);
16465
15479
  });
16466
15480
  }, [postToParent2]);
16467
- const clearFooterDragVisuals = (0, import_react17.useCallback)(() => {
15481
+ const clearFooterDragVisuals = (0, import_react16.useCallback)(() => {
16468
15482
  footerDragRef.current = null;
16469
15483
  setSiblingHintRects([]);
16470
15484
  setFooterDropSlots([]);
@@ -16473,7 +15487,7 @@ function OhhwellsBridge() {
16473
15487
  setIsItemDragging(false);
16474
15488
  unlockFooterDragInteraction();
16475
15489
  }, []);
16476
- const refreshFooterDragVisuals = (0, import_react17.useCallback)((session, activeSlot, clientX, clientY) => {
15490
+ const refreshFooterDragVisuals = (0, import_react16.useCallback)((session, activeSlot, clientX, clientY) => {
16477
15491
  const dragged = session.draggedEl;
16478
15492
  setDraggedItemRect(dragged.getBoundingClientRect());
16479
15493
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16505,13 +15519,13 @@ function OhhwellsBridge() {
16505
15519
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16506
15520
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16507
15521
  }, []);
16508
- const refreshFooterDragVisualsRef = (0, import_react17.useRef)(refreshFooterDragVisuals);
15522
+ const refreshFooterDragVisualsRef = (0, import_react16.useRef)(refreshFooterDragVisuals);
16509
15523
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16510
- const commitFooterDragRef = (0, import_react17.useRef)(() => {
15524
+ const commitFooterDragRef = (0, import_react16.useRef)(() => {
16511
15525
  });
16512
- const beginFooterDragRef = (0, import_react17.useRef)(() => {
15526
+ const beginFooterDragRef = (0, import_react16.useRef)(() => {
16513
15527
  });
16514
- const beginFooterDrag = (0, import_react17.useCallback)(
15528
+ const beginFooterDrag = (0, import_react16.useCallback)(
16515
15529
  (session) => {
16516
15530
  const rect = session.draggedEl.getBoundingClientRect();
16517
15531
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16531,7 +15545,7 @@ function OhhwellsBridge() {
16531
15545
  [refreshFooterDragVisuals]
16532
15546
  );
16533
15547
  beginFooterDragRef.current = beginFooterDrag;
16534
- const commitFooterDrag = (0, import_react17.useCallback)(
15548
+ const commitFooterDrag = (0, import_react16.useCallback)(
16535
15549
  (clientX, clientY) => {
16536
15550
  const session = footerDragRef.current;
16537
15551
  if (!session) {
@@ -16659,7 +15673,7 @@ function OhhwellsBridge() {
16659
15673
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16660
15674
  );
16661
15675
  commitFooterDragRef.current = commitFooterDrag;
16662
- const startFooterLinkDrag = (0, import_react17.useCallback)(
15676
+ const startFooterLinkDrag = (0, import_react16.useCallback)(
16663
15677
  (anchor, clientX, clientY, wasSelected) => {
16664
15678
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16665
15679
  if (!hrefKey) return false;
@@ -16695,7 +15709,7 @@ function OhhwellsBridge() {
16695
15709
  },
16696
15710
  [beginFooterDrag]
16697
15711
  );
16698
- const startFooterColumnDrag = (0, import_react17.useCallback)(
15712
+ const startFooterColumnDrag = (0, import_react16.useCallback)(
16699
15713
  (columnEl, clientX, clientY, wasSelected) => {
16700
15714
  const columns = listFooterColumns();
16701
15715
  const idx = columns.indexOf(columnEl);
@@ -16715,7 +15729,7 @@ function OhhwellsBridge() {
16715
15729
  },
16716
15730
  [beginFooterDrag]
16717
15731
  );
16718
- const handleItemDragStart = (0, import_react17.useCallback)(
15732
+ const handleItemDragStart = (0, import_react16.useCallback)(
16719
15733
  (e) => {
16720
15734
  const selected = selectedElRef.current;
16721
15735
  if (!selected) {
@@ -16735,7 +15749,7 @@ function OhhwellsBridge() {
16735
15749
  },
16736
15750
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16737
15751
  );
16738
- const handleItemDragEnd = (0, import_react17.useCallback)(
15752
+ const handleItemDragEnd = (0, import_react16.useCallback)(
16739
15753
  (e) => {
16740
15754
  if (footerDragRef.current) {
16741
15755
  const x = e?.clientX;
@@ -16761,7 +15775,7 @@ function OhhwellsBridge() {
16761
15775
  },
16762
15776
  [commitFooterDrag, commitNavDrag, navDragRef]
16763
15777
  );
16764
- const handleItemChromePointerDown = (0, import_react17.useCallback)((e) => {
15778
+ const handleItemChromePointerDown = (0, import_react16.useCallback)((e) => {
16765
15779
  if (e.button !== 0) return;
16766
15780
  const selected = selectedElRef.current;
16767
15781
  if (!selected) return;
@@ -16792,7 +15806,7 @@ function OhhwellsBridge() {
16792
15806
  }
16793
15807
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16794
15808
  }, [armNavPressFromChrome]);
16795
- const handleItemChromeClick = (0, import_react17.useCallback)((clientX, clientY) => {
15809
+ const handleItemChromeClick = (0, import_react16.useCallback)((clientX, clientY) => {
16796
15810
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16797
15811
  suppressNextClickRef.current = false;
16798
15812
  return;
@@ -16805,7 +15819,7 @@ function OhhwellsBridge() {
16805
15819
  }, []);
16806
15820
  reselectNavigationItemRef.current = reselectNavigationItem;
16807
15821
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16808
- const select = (0, import_react17.useCallback)((anchor) => {
15822
+ const select = (0, import_react16.useCallback)((anchor) => {
16809
15823
  if (!isNavigationItem2(anchor)) return;
16810
15824
  if (activeElRef.current) deactivate();
16811
15825
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16848,7 +15862,7 @@ function OhhwellsBridge() {
16848
15862
  setFloatingPanel(null);
16849
15863
  setLogoSizeDraft(null);
16850
15864
  }, [deactivate, markSelected]);
16851
- const selectFrame = (0, import_react17.useCallback)((el) => {
15865
+ const selectFrame = (0, import_react16.useCallback)((el) => {
16852
15866
  if (!isNavigationContainer(el)) return;
16853
15867
  if (activeElRef.current) deactivate();
16854
15868
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16899,7 +15913,7 @@ function OhhwellsBridge() {
16899
15913
  setFloatingPanel(null);
16900
15914
  setLogoSizeDraft(null);
16901
15915
  }, [deactivate, markSelected, postToParent2]);
16902
- const selectLogo = (0, import_react17.useCallback)(
15916
+ const selectLogo = (0, import_react16.useCallback)(
16903
15917
  (logoEl) => {
16904
15918
  if (activeElRef.current) deactivate();
16905
15919
  selectedElRef.current = logoEl;
@@ -16928,7 +15942,7 @@ function OhhwellsBridge() {
16928
15942
  },
16929
15943
  [deactivate, markSelected]
16930
15944
  );
16931
- const openLogoSizePanel = (0, import_react17.useCallback)((logoEl) => {
15945
+ const openLogoSizePanel = (0, import_react16.useCallback)((logoEl) => {
16932
15946
  const placement = getLogoPlacement(logoEl);
16933
15947
  const draft = readLogoSizeState(editContentRef.current, placement);
16934
15948
  setLogoSizeDraft(draft);
@@ -16941,7 +15955,7 @@ function OhhwellsBridge() {
16941
15955
  placement
16942
15956
  });
16943
15957
  }, []);
16944
- const openSocialsDisplayPanel = (0, import_react17.useCallback)((row) => {
15958
+ const openSocialsDisplayPanel = (0, import_react16.useCallback)((row) => {
16945
15959
  setParentScrollSnap(parentScrollRef.current);
16946
15960
  setFloatingPanel({
16947
15961
  key: "socials-display",
@@ -16951,7 +15965,7 @@ function OhhwellsBridge() {
16951
15965
  row
16952
15966
  });
16953
15967
  }, []);
16954
- const changeSocialsDisplay = (0, import_react17.useCallback)(
15968
+ const changeSocialsDisplay = (0, import_react16.useCallback)(
16955
15969
  (row, next) => {
16956
15970
  if (next.icon) {
16957
15971
  const missing = socialsMissingIcons(row);
@@ -16974,17 +15988,17 @@ function OhhwellsBridge() {
16974
15988
  },
16975
15989
  []
16976
15990
  );
16977
- const closeFloatingPanelOnly = (0, import_react17.useCallback)(() => {
15991
+ const closeFloatingPanelOnly = (0, import_react16.useCallback)(() => {
16978
15992
  setFloatingPanel(null);
16979
15993
  setLogoSizeDraft(null);
16980
15994
  }, []);
16981
15995
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16982
- const closeFloatingPanelAndDeselect = (0, import_react17.useCallback)(() => {
15996
+ const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
16983
15997
  setFloatingPanel(null);
16984
15998
  setLogoSizeDraft(null);
16985
15999
  deselectRef.current();
16986
16000
  }, []);
16987
- (0, import_react17.useEffect)(() => {
16001
+ (0, import_react16.useEffect)(() => {
16988
16002
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
16989
16003
  if (!session || !logoSizeDraft) {
16990
16004
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -17003,7 +16017,7 @@ function OhhwellsBridge() {
17003
16017
  max: LOGO_SIZE_MAX
17004
16018
  });
17005
16019
  }, [floatingPanel, logoSizeDraft, editorViewport]);
17006
- const persistLogoSizeDraft = (0, import_react17.useCallback)(
16020
+ const persistLogoSizeDraft = (0, import_react16.useCallback)(
17007
16021
  (placement, draft) => {
17008
16022
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
17009
16023
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -17043,7 +16057,7 @@ function OhhwellsBridge() {
17043
16057
  },
17044
16058
  [postToParent2]
17045
16059
  );
17046
- const activate = (0, import_react17.useCallback)((el, options) => {
16060
+ const activate = (0, import_react16.useCallback)((el, options) => {
17047
16061
  if (activeElRef.current === el) return;
17048
16062
  if (isIconEditable(el)) return;
17049
16063
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17127,8 +16141,8 @@ function OhhwellsBridge() {
17127
16141
  openLogoSizePanelRef.current = openLogoSizePanel;
17128
16142
  deselectRef.current = deselect;
17129
16143
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17130
- const lastSiteWideScopeRef = (0, import_react17.useRef)(null);
17131
- (0, import_react17.useEffect)(() => {
16144
+ const lastSiteWideScopeRef = (0, import_react16.useRef)(null);
16145
+ (0, import_react16.useEffect)(() => {
17132
16146
  if (!isEditMode) {
17133
16147
  if (lastSiteWideScopeRef.current !== false) {
17134
16148
  lastSiteWideScopeRef.current = false;
@@ -17154,34 +16168,22 @@ function OhhwellsBridge() {
17154
16168
  isFooterFrameSelection,
17155
16169
  postToParent2
17156
16170
  ]);
17157
- (0, import_react17.useLayoutEffect)(() => {
16171
+ (0, import_react16.useLayoutEffect)(() => {
17158
16172
  if (!subdomain || isEditMode) {
17159
16173
  setFetchState("done");
17160
16174
  return;
17161
16175
  }
17162
16176
  const applyContent = (content) => {
17163
16177
  const imageLoads = [];
17164
- if (typeof content[BRAND_KIT_KEY] === "string") {
17165
- brandKitRef.current = content[BRAND_KIT_KEY];
17166
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17167
- }
17168
16178
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17169
16179
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17170
16180
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17171
16181
  }
17172
- if (typeof content[STYLE_STORE_KEY] === "string") {
17173
- stylesRef.current = content[STYLE_STORE_KEY];
17174
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17175
- }
17176
- applyBrandChrome(content);
17177
16182
  for (const [key, val] of Object.entries(content)) {
17178
16183
  if (key === "__ohw_sections") continue;
17179
16184
  if (key === AI_SECTIONS_KEY) continue;
17180
16185
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17181
16186
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17182
- if (key === BRAND_KIT_KEY) continue;
17183
- if (key === STYLE_STORE_KEY) continue;
17184
- if (BRAND_CHROME_KEYS.has(key)) continue;
17185
16187
  if (applyVideoSettingNode(key, val)) continue;
17186
16188
  if (applyCarouselNode(key, val)) continue;
17187
16189
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17239,9 +16241,7 @@ function OhhwellsBridge() {
17239
16241
  let cancelled = false;
17240
16242
  setFetchState("loading");
17241
16243
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17242
- const initialPath = pathname;
17243
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17244
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16244
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17245
16245
  if (cancelled) return;
17246
16246
  const content = data?.content ?? {};
17247
16247
  contentCache.set(subdomain, content);
@@ -17254,7 +16254,7 @@ function OhhwellsBridge() {
17254
16254
  cancelled = true;
17255
16255
  };
17256
16256
  }, [subdomain, isEditMode]);
17257
- (0, import_react17.useEffect)(() => {
16257
+ (0, import_react16.useEffect)(() => {
17258
16258
  if (!isEditMode) return;
17259
16259
  const resolveIndex = (form, clientY) => {
17260
16260
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17295,7 +16295,7 @@ function OhhwellsBridge() {
17295
16295
  window.removeEventListener("drop", onDrop, true);
17296
16296
  };
17297
16297
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17298
- (0, import_react17.useEffect)(() => {
16298
+ (0, import_react16.useEffect)(() => {
17299
16299
  if (!isEditMode) return;
17300
16300
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17301
16301
  markFormFields(form);
@@ -17307,7 +16307,7 @@ function OhhwellsBridge() {
17307
16307
  });
17308
16308
  return () => observer.disconnect();
17309
16309
  }, [isEditMode, fetchState, pathname]);
17310
- (0, import_react17.useEffect)(() => {
16310
+ (0, import_react16.useEffect)(() => {
17311
16311
  if (!isEditMode) return;
17312
16312
  let saveTimer = null;
17313
16313
  const onInput = (e) => {
@@ -17329,14 +16329,14 @@ function OhhwellsBridge() {
17329
16329
  document.addEventListener("input", onInput, true);
17330
16330
  return () => document.removeEventListener("input", onInput, true);
17331
16331
  }, [isEditMode, persistFields]);
17332
- (0, import_react17.useEffect)(() => {
16332
+ (0, import_react16.useEffect)(() => {
17333
16333
  if (isEditMode || fetchState !== "done") return;
17334
16334
  const content = contentCache.get(subdomain) ?? {};
17335
16335
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17336
16336
  reconcileFieldsFromContent(form, content);
17337
16337
  });
17338
16338
  }, [isEditMode, fetchState, subdomain]);
17339
- (0, import_react17.useEffect)(() => {
16339
+ (0, import_react16.useEffect)(() => {
17340
16340
  if (!isEditMode) return;
17341
16341
  const swallow = (e) => {
17342
16342
  const target = e.target;
@@ -17345,12 +16345,12 @@ function OhhwellsBridge() {
17345
16345
  document.addEventListener("submit", swallow, true);
17346
16346
  return () => document.removeEventListener("submit", swallow, true);
17347
16347
  }, [isEditMode]);
17348
- (0, import_react17.useEffect)(() => {
16348
+ (0, import_react16.useEffect)(() => {
17349
16349
  if (isEditMode || fetchState !== "done") return;
17350
16350
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17351
16351
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17352
16352
  }, [isEditMode, fetchState, subdomain]);
17353
- (0, import_react17.useEffect)(() => {
16353
+ (0, import_react16.useEffect)(() => {
17354
16354
  if (!subdomain || isEditMode) return;
17355
16355
  let debounceTimer = null;
17356
16356
  let observer = null;
@@ -17361,21 +16361,10 @@ function OhhwellsBridge() {
17361
16361
  initSectionInstancesFromContent(content, window.location.pathname);
17362
16362
  observer?.disconnect();
17363
16363
  try {
17364
- applyBrandChrome(content);
17365
- if (typeof content[BRAND_KIT_KEY] === "string") {
17366
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17367
- }
17368
- if (typeof content[STYLE_STORE_KEY] === "string") {
17369
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17370
- }
17371
16364
  for (const [key, val] of Object.entries(content)) {
17372
16365
  if (key === "__ohw_sections") continue;
17373
16366
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17374
16367
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17375
- if (key === BRAND_KIT_KEY) continue;
17376
- if (key === STYLE_STORE_KEY) continue;
17377
- if (key === STYLE_STORE_KEY) continue;
17378
- if (BRAND_CHROME_KEYS.has(key)) continue;
17379
16368
  if (applyVideoSettingNode(key, val)) continue;
17380
16369
  if (applyCarouselNode(key, val)) continue;
17381
16370
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17418,17 +16407,6 @@ function OhhwellsBridge() {
17418
16407
  debounceTimer = setTimeout(applyFromCache, 150);
17419
16408
  };
17420
16409
  applyFromCache();
17421
- const pathCacheKey = `${subdomain}::${pathname}`;
17422
- if (!fetchedContentPaths.has(pathCacheKey)) {
17423
- fetchedContentPaths.add(pathCacheKey);
17424
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17425
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17426
- if (!data?.content) return;
17427
- contentCache.set(subdomain, data.content);
17428
- applyFromCache();
17429
- }).catch(() => {
17430
- });
17431
- }
17432
16410
  observer = new MutationObserver(scheduleApply);
17433
16411
  observer.observe(document.body, { childList: true, subtree: true });
17434
16412
  return () => {
@@ -17436,16 +16414,16 @@ function OhhwellsBridge() {
17436
16414
  if (debounceTimer) clearTimeout(debounceTimer);
17437
16415
  };
17438
16416
  }, [subdomain, isEditMode, pathname]);
17439
- (0, import_react17.useLayoutEffect)(() => {
16417
+ (0, import_react16.useLayoutEffect)(() => {
17440
16418
  const el = document.getElementById("ohw-loader");
17441
16419
  if (!el) return;
17442
16420
  const visible = Boolean(subdomain) && fetchState !== "done";
17443
16421
  el.style.display = visible ? "flex" : "none";
17444
16422
  }, [subdomain, fetchState]);
17445
- (0, import_react17.useEffect)(() => {
16423
+ (0, import_react16.useEffect)(() => {
17446
16424
  postToParent2({ type: "ow:navigation", path: pathname });
17447
16425
  }, [pathname, postToParent2]);
17448
- (0, import_react17.useEffect)(() => {
16426
+ (0, import_react16.useEffect)(() => {
17449
16427
  if (!isEditMode) return;
17450
16428
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17451
16429
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17453,7 +16431,7 @@ function OhhwellsBridge() {
17453
16431
  deselectRef.current();
17454
16432
  deactivateRef.current();
17455
16433
  }, [pathname, isEditMode]);
17456
- (0, import_react17.useEffect)(() => {
16434
+ (0, import_react16.useEffect)(() => {
17457
16435
  const contentForNav = () => {
17458
16436
  if (isEditMode) return editContentRef.current;
17459
16437
  if (!subdomain) return {};
@@ -17520,36 +16498,31 @@ function OhhwellsBridge() {
17520
16498
  observer?.disconnect();
17521
16499
  };
17522
16500
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17523
- (0, import_react17.useEffect)(() => {
16501
+ (0, import_react16.useEffect)(() => {
17524
16502
  if (!isEditMode) return;
17525
- let lastPosted = 0;
17526
16503
  const measure = () => {
17527
16504
  const h = document.body.scrollHeight;
17528
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17529
- lastPosted = h;
17530
- postToParent2({ type: "ow:height", height: h });
17531
- }
17532
- };
17533
- let raf = null;
17534
- const schedule = () => {
17535
- if (raf != null) return;
17536
- raf = requestAnimationFrame(() => {
17537
- raf = null;
17538
- measure();
17539
- });
16505
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17540
16506
  };
17541
16507
  const t1 = setTimeout(measure, 50);
17542
16508
  const t2 = setTimeout(measure, 500);
17543
- const ro = new ResizeObserver(schedule);
17544
- ro.observe(document.body);
16509
+ let lastWidth = window.innerWidth;
16510
+ let resizeTimer = null;
16511
+ const handleResize = () => {
16512
+ if (window.innerWidth === lastWidth) return;
16513
+ lastWidth = window.innerWidth;
16514
+ if (resizeTimer) clearTimeout(resizeTimer);
16515
+ resizeTimer = setTimeout(measure, 150);
16516
+ };
16517
+ window.addEventListener("resize", handleResize);
17545
16518
  return () => {
17546
16519
  clearTimeout(t1);
17547
16520
  clearTimeout(t2);
17548
- if (raf != null) cancelAnimationFrame(raf);
17549
- ro.disconnect();
16521
+ if (resizeTimer) clearTimeout(resizeTimer);
16522
+ window.removeEventListener("resize", handleResize);
17550
16523
  };
17551
16524
  }, [pathname, isEditMode, postToParent2]);
17552
- (0, import_react17.useEffect)(() => {
16525
+ (0, import_react16.useEffect)(() => {
17553
16526
  if (!subdomainFromQuery || isEditMode) return;
17554
16527
  const handleClick = (e) => {
17555
16528
  const anchor = e.target.closest("a");
@@ -17565,7 +16538,7 @@ function OhhwellsBridge() {
17565
16538
  document.addEventListener("click", handleClick, true);
17566
16539
  return () => document.removeEventListener("click", handleClick, true);
17567
16540
  }, [subdomainFromQuery, isEditMode, router]);
17568
- (0, import_react17.useEffect)(() => {
16541
+ (0, import_react16.useEffect)(() => {
17569
16542
  if (!isEditMode) {
17570
16543
  editStylesRef.current?.base.remove();
17571
16544
  editStylesRef.current?.forceHover.remove();
@@ -17727,21 +16700,16 @@ function OhhwellsBridge() {
17727
16700
  return;
17728
16701
  }
17729
16702
  const target = e.target;
17730
- if (target.closest("[data-ohw-ai-review]")) return;
17731
16703
  if (target.closest("[data-ohw-toolbar]")) return;
17732
16704
  if (target.closest("[data-ohw-state-toggle]")) return;
17733
16705
  if (target.closest("[data-ohw-max-badge]")) return;
17734
16706
  if (isInsideLinkEditor(target)) return;
17735
- if (isInsideFloatingPanel(target)) return;
17736
16707
  if (target.closest("[data-ohw-form-toolbar]")) return;
17737
16708
  if (target.closest(
17738
16709
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17739
16710
  )) {
17740
16711
  return;
17741
16712
  }
17742
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
17743
- clearMediaSelectionRef.current();
17744
- }
17745
16713
  {
17746
16714
  const formEl = getFormElement(target);
17747
16715
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -17889,11 +16857,8 @@ function OhhwellsBridge() {
17889
16857
  if (isMediaEditable(editable) && !buttonOnMedia) {
17890
16858
  e.preventDefault();
17891
16859
  e.stopPropagation();
17892
- if (selectedMediaElRef.current === editable) {
17893
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17894
- } else {
17895
- selectMediaElementRef.current(editable);
17896
- }
16860
+ aiSectionApiRef.current?.selectFromElement(editable);
16861
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17897
16862
  return;
17898
16863
  }
17899
16864
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
@@ -18012,12 +16977,10 @@ function OhhwellsBridge() {
18012
16977
  };
18013
16978
  const handleDblClick = (e) => {
18014
16979
  const target = e.target;
18015
- if (target.closest("[data-ohw-ai-review]")) return;
18016
16980
  if (target.closest("[data-ohw-toolbar]")) return;
18017
16981
  if (target.closest("[data-ohw-state-toggle]")) return;
18018
16982
  if (target.closest("[data-ohw-max-badge]")) return;
18019
16983
  if (isInsideLinkEditor(target)) return;
18020
- if (isInsideFloatingPanel(target)) return;
18021
16984
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
18022
16985
  return;
18023
16986
  }
@@ -18058,14 +17021,11 @@ function OhhwellsBridge() {
18058
17021
  setSiblingHintRects([]);
18059
17022
  return;
18060
17023
  }
18061
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
17024
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
18062
17025
  hoveredItemElRef.current = null;
18063
17026
  setHoveredItemRect(null);
18064
17027
  hoveredNavContainerRef.current = null;
18065
17028
  setHoveredNavContainerRect(null);
18066
- siblingHintElRef.current = null;
18067
- setSiblingHintRect(null);
18068
- setSiblingHintRects([]);
18069
17029
  return;
18070
17030
  }
18071
17031
  {
@@ -18083,16 +17043,6 @@ function OhhwellsBridge() {
18083
17043
  return;
18084
17044
  }
18085
17045
  }
18086
- if (allowNavContainerHover) {
18087
- const socialsRow = isSocialsRow(target) ? target : null;
18088
- if (socialsRow && !getSocialItem(target) && selected2 !== socialsRow) {
18089
- hoveredNavContainerRef.current = socialsRow;
18090
- setHoveredNavContainerRect(socialsRow.getBoundingClientRect());
18091
- hoveredItemElRef.current = null;
18092
- setHoveredItemRect(null);
18093
- return;
18094
- }
18095
- }
18096
17046
  if (allowFooterLinksHover) {
18097
17047
  const navContainer = target.closest("[data-ohw-nav-container]");
18098
17048
  if (!navContainer) {
@@ -18178,12 +17128,13 @@ function OhhwellsBridge() {
18178
17128
  clearHrefKeyHover(hoverTarget);
18179
17129
  hoveredItemElRef.current = hoverTarget;
18180
17130
  setHoveredItemRect(hoverTarget.getBoundingClientRect());
18181
- } else if (!isInsideNavigationItem(editable) && hoverTarget !== selectedElRef.current) {
17131
+ } else if (!isInsideNavigationItem(editable)) {
18182
17132
  hoverTarget.setAttribute("data-ohw-hovered", "");
18183
17133
  if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
18184
17134
  hoveredNavContainerRef.current = null;
18185
17135
  setHoveredNavContainerRect(null);
18186
17136
  hoveredItemElRef.current = editable;
17137
+ setHoveredItemRect(editable.getBoundingClientRect());
18187
17138
  }
18188
17139
  }
18189
17140
  }
@@ -18480,7 +17431,7 @@ function OhhwellsBridge() {
18480
17431
  }
18481
17432
  };
18482
17433
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18483
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17434
+ if (linkPopoverOpenRef.current) {
18484
17435
  if (hoveredImageRef.current) {
18485
17436
  hoveredImageRef.current = null;
18486
17437
  hoveredImageHasTextOverlapRef.current = false;
@@ -18496,6 +17447,11 @@ function OhhwellsBridge() {
18496
17447
  probeNavigationHoverAt(x, y);
18497
17448
  return;
18498
17449
  }
17450
+ if (isPointOverLogo(x, y)) {
17451
+ dismissImageHover();
17452
+ probeNavigationHoverAt(x, y);
17453
+ return;
17454
+ }
18499
17455
  const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
18500
17456
  '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
18501
17457
  );
@@ -18734,7 +17690,7 @@ function OhhwellsBridge() {
18734
17690
  }
18735
17691
  };
18736
17692
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18737
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17693
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18738
17694
  if (activeStateElRef.current) {
18739
17695
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18740
17696
  activeStateElRef.current = null;
@@ -18771,35 +17727,6 @@ function OhhwellsBridge() {
18771
17727
  }
18772
17728
  }
18773
17729
  };
18774
- const probeSocialsRowAt = (clientX, clientY, fromParentViewport = false) => {
18775
- const wasSocialsRow = Boolean(hoveredNavContainerRef.current?.hasAttribute(SOCIALS_ROW_ATTR));
18776
- const clear = () => {
18777
- if (!wasSocialsRow) return false;
18778
- hoveredNavContainerRef.current = null;
18779
- setHoveredNavContainerRect(null);
18780
- return false;
18781
- };
18782
- if (linkPopoverOpenRef.current || toolbarVariantRef.current === "select-frame") return clear();
18783
- const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
18784
- const SLACK = 6;
18785
- for (const row of Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`))) {
18786
- const rect = row.getBoundingClientRect();
18787
- const inside = x >= rect.left - SLACK && x <= rect.right + SLACK && y >= rect.top - SLACK && y <= rect.bottom + SLACK;
18788
- if (!inside) continue;
18789
- if (selectedElRef.current === row) return clear();
18790
- const overItem = listSocialItems(row).some((item) => {
18791
- const box = item.getBoundingClientRect();
18792
- return x >= box.left && x <= box.right && y >= box.top && y <= box.bottom;
18793
- });
18794
- if (overItem) return clear();
18795
- hoveredNavContainerRef.current = row;
18796
- setHoveredNavContainerRect(rect);
18797
- hoveredItemElRef.current = null;
18798
- setHoveredItemRect(null);
18799
- return true;
18800
- }
18801
- return clear();
18802
- };
18803
17730
  const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
18804
17731
  if (linkPopoverOpenRef.current) {
18805
17732
  if (hoveredGapRef.current) {
@@ -18809,9 +17736,7 @@ function OhhwellsBridge() {
18809
17736
  return;
18810
17737
  }
18811
17738
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
18812
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
18813
- (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
18814
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
17739
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18815
17740
  const ZONE = 20;
18816
17741
  for (let i = 0; i < sections.length; i++) {
18817
17742
  const a = sections[i];
@@ -18840,7 +17765,8 @@ function OhhwellsBridge() {
18840
17765
  };
18841
17766
  const handleMouseMove = (e) => {
18842
17767
  const { clientX, clientY } = e;
18843
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17768
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17769
+ if (isOverEditorChrome(clientX, clientY)) {
18844
17770
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18845
17771
  formHoverElRef.current = null;
18846
17772
  setFormHoverRect(null);
@@ -18848,15 +17774,8 @@ function OhhwellsBridge() {
18848
17774
  setHoveredItemRect(null);
18849
17775
  hoveredNavContainerRef.current = null;
18850
17776
  setHoveredNavContainerRect(null);
18851
- siblingHintElRef.current = null;
18852
- setSiblingHintRect(null);
18853
- setSiblingHintRects([]);
18854
- dismissImageHover();
18855
- clearImageHover();
18856
- setSectionGap(null);
18857
17777
  return;
18858
17778
  }
18859
- if (probeSocialsRowAt(clientX, clientY)) return;
18860
17779
  probeSectionGapAt(clientX, clientY);
18861
17780
  probeImageAt(clientX, clientY);
18862
17781
  probeHoverCardsAt(clientX, clientY);
@@ -18865,12 +17784,7 @@ function OhhwellsBridge() {
18865
17784
  if (e.data?.type !== "ow:pointer-sync") return;
18866
17785
  const { clientX, clientY } = e.data;
18867
17786
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18868
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18869
- dismissImageHover();
18870
- clearImageHover();
18871
- return;
18872
- }
18873
- if (probeSocialsRowAt(clientX, clientY)) return;
17787
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18874
17788
  probeSectionGapAt(clientX, clientY);
18875
17789
  probeImageAt(clientX, clientY);
18876
17790
  probeHoverCardsAt(clientX, clientY);
@@ -19116,19 +18030,10 @@ function OhhwellsBridge() {
19116
18030
  if (e.data?.type !== "ow:hydrate") return;
19117
18031
  const content = e.data.content;
19118
18032
  if (!content) return;
19119
- if (typeof content[BRAND_KIT_KEY] === "string") {
19120
- brandKitRef.current = content[BRAND_KIT_KEY];
19121
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19122
- }
19123
18033
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19124
18034
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19125
18035
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19126
18036
  }
19127
- if (typeof content[STYLE_STORE_KEY] === "string") {
19128
- stylesRef.current = content[STYLE_STORE_KEY];
19129
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19130
- }
19131
- applyBrandChrome(content);
19132
18037
  let sectionsJson = null;
19133
18038
  for (const [key, val] of Object.entries(content)) {
19134
18039
  if (key === "__ohw_sections") {
@@ -19138,9 +18043,6 @@ function OhhwellsBridge() {
19138
18043
  if (key === AI_SECTIONS_KEY) continue;
19139
18044
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19140
18045
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19141
- if (key === BRAND_KIT_KEY) continue;
19142
- if (key === STYLE_STORE_KEY) continue;
19143
- if (BRAND_CHROME_KEYS.has(key)) continue;
19144
18046
  if (applyVideoSettingNode(key, val)) continue;
19145
18047
  if (applyCarouselNode(key, val)) continue;
19146
18048
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19237,21 +18139,12 @@ function OhhwellsBridge() {
19237
18139
  nodes: collectEditableNodes(editContentRef.current)
19238
18140
  });
19239
18141
  };
19240
- const clearInteractionChrome = () => {
19241
- deactivateRef.current();
19242
- deselectRef.current();
19243
- clearMediaSelectionRef.current();
19244
- };
19245
18142
  const handleAiApplyTree = (e) => {
19246
18143
  if (e.data?.type !== "ow:ai-apply-tree") return;
19247
18144
  const payload = e.data.payload;
19248
18145
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19249
- clearInteractionChrome();
19250
18146
  const previous = aiSectionsRef.current;
19251
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19252
- ...payload,
19253
- path: payload.path ?? window.location.pathname
19254
- });
18147
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19255
18148
  const nextValue = serializeAiSectionsState(nextState);
19256
18149
  aiSectionsRef.current = nextValue;
19257
18150
  applyAiSectionsToDom(nextState);
@@ -19271,7 +18164,6 @@ function OhhwellsBridge() {
19271
18164
  if (!sectionId || sectionId === "navbar" || sectionId === "footer") return;
19272
18165
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
19273
18166
  if (!exists) return;
19274
- clearInteractionChrome();
19275
18167
  const previous = aiSectionsRef.current;
19276
18168
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
19277
18169
  const nextValue = serializeAiSectionsState(nextState);
@@ -19287,58 +18179,14 @@ function OhhwellsBridge() {
19287
18179
  const handleAiSetSections = (e) => {
19288
18180
  if (e.data?.type !== "ow:ai-set-sections") return;
19289
18181
  const value = typeof e.data.value === "string" ? e.data.value : "";
19290
- clearInteractionChrome();
19291
18182
  aiSectionsRef.current = value;
19292
18183
  applyAiSectionsToDom(parseAiSectionsState(value));
19293
- applyStylesToDom(parseStyleStore(stylesRef.current));
19294
18184
  const restoredHeight = document.documentElement.scrollHeight;
19295
18185
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19296
18186
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19297
18187
  postAiSectionsChanged();
19298
18188
  };
19299
18189
  window.addEventListener("message", handleAiSetSections);
19300
- const handleMoveSection = (e) => {
19301
- if (e.data?.type !== "ow:move-section") return;
19302
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19303
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19304
- if (!instanceId || !direction) return;
19305
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19306
- if (!entries) return;
19307
- const orderJson = JSON.stringify(entries);
19308
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19309
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19310
- window.dispatchEvent(new Event("resize"));
19311
- };
19312
- window.addEventListener("message", handleMoveSection);
19313
- const handleAiSetBrand = (e) => {
19314
- if (e.data?.type !== "ow:ai-set-brand") return;
19315
- const value = typeof e.data.value === "string" ? e.data.value : "";
19316
- const previous = brandKitRef.current;
19317
- brandKitRef.current = value;
19318
- applyBrandToDom(parseBrandKit(value));
19319
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19320
- applyStylesToDom(parseStyleStore(stylesRef.current));
19321
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19322
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19323
- };
19324
- window.addEventListener("message", handleAiSetBrand);
19325
- const handleAiSetStyles = (e) => {
19326
- if (e.data?.type !== "ow:ai-set-styles") return;
19327
- const value = typeof e.data.value === "string" ? e.data.value : "";
19328
- const previous = stylesRef.current;
19329
- stylesRef.current = value;
19330
- applyStylesToDom(parseStyleStore(value));
19331
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19332
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19333
- };
19334
- window.addEventListener("message", handleAiSetStyles);
19335
- const handleGetBrand = (e) => {
19336
- if (e.data?.type !== "ow:get-brand") return;
19337
- const template = deriveTemplateBrand();
19338
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19339
- postToParentRef.current({ type: "ow:brand-value", value });
19340
- };
19341
- window.addEventListener("message", handleGetBrand);
19342
18190
  const handlePanelDragging = (e) => {
19343
18191
  if (e.data?.type !== "ow:panel-dragging") return;
19344
18192
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
@@ -19354,12 +18202,6 @@ function OhhwellsBridge() {
19354
18202
  closeLinkPopoverRef.current();
19355
18203
  return;
19356
18204
  }
19357
- if (floatingPanelOpenRef.current) {
19358
- setFloatingPanelRef.current(null);
19359
- deselectRef.current();
19360
- deactivateRef.current();
19361
- return;
19362
- }
19363
18205
  deselectRef.current();
19364
18206
  deactivateRef.current();
19365
18207
  };
@@ -19447,10 +18289,6 @@ function OhhwellsBridge() {
19447
18289
  const handleKeyDown = (e) => {
19448
18290
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19449
18291
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19450
- if (e.key === "Escape" && selectedMediaElRef.current) {
19451
- clearMediaSelectionRef.current();
19452
- return;
19453
- }
19454
18292
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19455
18293
  e.preventDefault();
19456
18294
  selectAllTextInEditable(activeElRef.current);
@@ -19610,12 +18448,6 @@ function OhhwellsBridge() {
19610
18448
  if (aiSectionsRef.current) {
19611
18449
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19612
18450
  }
19613
- if (stylesRef.current) {
19614
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19615
- }
19616
- if (brandKitRef.current) {
19617
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19618
- }
19619
18451
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19620
18452
  const formKey = formKeyOf(form);
19621
18453
  if (!formKey) return;
@@ -19633,12 +18465,8 @@ function OhhwellsBridge() {
19633
18465
  if (inserted) {
19634
18466
  const tracker = getSectionsTracker();
19635
18467
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19636
- const reportHeight = () => {
19637
- const h = document.body.scrollHeight;
19638
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19639
- };
19640
- reportHeight();
19641
- setTimeout(reportHeight, 500);
18468
+ const h = document.documentElement.scrollHeight;
18469
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19642
18470
  }
19643
18471
  };
19644
18472
  const handleSwitchSchedule = (e) => {
@@ -20025,23 +18853,19 @@ function OhhwellsBridge() {
20025
18853
  window.removeEventListener("message", handleAiApplyTree);
20026
18854
  window.removeEventListener("message", handleAiDeleteSection);
20027
18855
  window.removeEventListener("message", handleAiSetSections);
20028
- window.removeEventListener("message", handleMoveSection);
20029
- window.removeEventListener("message", handleAiSetBrand);
20030
- window.removeEventListener("message", handleAiSetStyles);
20031
- window.removeEventListener("message", handleGetBrand);
20032
18856
  window.removeEventListener("message", handlePanelDragging);
20033
18857
  window.removeEventListener("message", handleDeactivate);
18858
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
20034
18859
  window.removeEventListener("message", handleToastAction);
20035
18860
  window.removeEventListener("message", handleFormCount);
20036
18861
  window.removeEventListener("message", handleUiEscape);
20037
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
20038
18862
  autoSaveTimers.current.forEach(clearTimeout);
20039
18863
  autoSaveTimers.current.clear();
20040
18864
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
20041
18865
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
20042
18866
  };
20043
18867
  }, [isEditMode, refreshStateRules]);
20044
- (0, import_react17.useEffect)(() => {
18868
+ (0, import_react16.useEffect)(() => {
20045
18869
  if (!isEditMode) return;
20046
18870
  const THRESHOLD = 10;
20047
18871
  const resolveWasSelected = (el) => {
@@ -20197,7 +19021,7 @@ function OhhwellsBridge() {
20197
19021
  unlockFooterDragInteraction();
20198
19022
  };
20199
19023
  }, [isEditMode]);
20200
- (0, import_react17.useEffect)(() => {
19024
+ (0, import_react16.useEffect)(() => {
20201
19025
  const handler = (e) => {
20202
19026
  if (e.data?.type !== "ow:request-schedule-config") return;
20203
19027
  const insertAfterVal = e.data.insertAfter;
@@ -20213,7 +19037,7 @@ function OhhwellsBridge() {
20213
19037
  window.addEventListener("message", handler);
20214
19038
  return () => window.removeEventListener("message", handler);
20215
19039
  }, [processConfigRequest]);
20216
- (0, import_react17.useEffect)(() => {
19040
+ (0, import_react16.useEffect)(() => {
20217
19041
  if (!isEditMode) return;
20218
19042
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20219
19043
  el.removeAttribute("data-ohw-active-state");
@@ -20237,7 +19061,7 @@ function OhhwellsBridge() {
20237
19061
  postToParent2({
20238
19062
  type: "ow:ready",
20239
19063
  version: "1",
20240
- bridgeVersion: "0.1.68",
19064
+ bridgeVersion: "0.1.67",
20241
19065
  path: pathname,
20242
19066
  nodes: collectEditableNodes(editContentRef.current),
20243
19067
  sections
@@ -20249,13 +19073,13 @@ function OhhwellsBridge() {
20249
19073
  clearTimeout(timer);
20250
19074
  };
20251
19075
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20252
- (0, import_react17.useEffect)(() => {
19076
+ (0, import_react16.useEffect)(() => {
20253
19077
  scrollToHashSectionWhenReady();
20254
19078
  const onHashChange = () => scrollToHashSectionWhenReady();
20255
19079
  window.addEventListener("hashchange", onHashChange);
20256
19080
  return () => window.removeEventListener("hashchange", onHashChange);
20257
19081
  }, [pathname]);
20258
- const handleCommand = (0, import_react17.useCallback)((cmd) => {
19082
+ const handleCommand = (0, import_react16.useCallback)((cmd) => {
20259
19083
  const el = activeElRef.current;
20260
19084
  const selBefore = window.getSelection();
20261
19085
  let savedOffsets = null;
@@ -20291,7 +19115,7 @@ function OhhwellsBridge() {
20291
19115
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20292
19116
  refreshActiveCommandsRef.current();
20293
19117
  }, []);
20294
- (0, import_react17.useEffect)(() => {
19118
+ (0, import_react16.useEffect)(() => {
20295
19119
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20296
19120
  if (!session || !logoSizeDraft) return;
20297
19121
  const onPanelAction = (e) => {
@@ -20329,7 +19153,7 @@ function OhhwellsBridge() {
20329
19153
  window.addEventListener("message", onPanelAction);
20330
19154
  return () => window.removeEventListener("message", onPanelAction);
20331
19155
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20332
- const handleStateChange = (0, import_react17.useCallback)((state) => {
19156
+ const handleStateChange = (0, import_react16.useCallback)((state) => {
20333
19157
  if (!activeStateElRef.current) return;
20334
19158
  const el = activeStateElRef.current;
20335
19159
  if (state === "Default") {
@@ -20342,7 +19166,7 @@ function OhhwellsBridge() {
20342
19166
  }
20343
19167
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20344
19168
  }, [deactivate]);
20345
- const reselectAfterLinkPopover = (0, import_react17.useCallback)(
19169
+ const reselectAfterLinkPopover = (0, import_react16.useCallback)(
20346
19170
  (hrefKey) => {
20347
19171
  requestAnimationFrame(() => {
20348
19172
  const el = resolveHrefKeyElement(hrefKey);
@@ -20351,7 +19175,7 @@ function OhhwellsBridge() {
20351
19175
  },
20352
19176
  [resolveHrefKeyElement]
20353
19177
  );
20354
- const closeLinkPopover = (0, import_react17.useCallback)(() => {
19178
+ const closeLinkPopover = (0, import_react16.useCallback)(() => {
20355
19179
  const session = linkPopoverSessionRef.current;
20356
19180
  addNavAfterAnchorRef.current = null;
20357
19181
  setLinkPopover(null);
@@ -20359,9 +19183,9 @@ function OhhwellsBridge() {
20359
19183
  reselectAfterLinkPopover(session.key);
20360
19184
  }
20361
19185
  }, [reselectAfterLinkPopover]);
20362
- const closeLinkPopoverRef = (0, import_react17.useRef)(closeLinkPopover);
19186
+ const closeLinkPopoverRef = (0, import_react16.useRef)(closeLinkPopover);
20363
19187
  closeLinkPopoverRef.current = closeLinkPopover;
20364
- const openLinkPopoverForActive = (0, import_react17.useCallback)(() => {
19188
+ const openLinkPopoverForActive = (0, import_react16.useCallback)(() => {
20365
19189
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20366
19190
  if (!hrefCtx) return;
20367
19191
  bumpLinkPopoverGrace();
@@ -20372,7 +19196,7 @@ function OhhwellsBridge() {
20372
19196
  });
20373
19197
  deactivate();
20374
19198
  }, [deactivate]);
20375
- const openLinkPopoverForSelected = (0, import_react17.useCallback)(() => {
19199
+ const openLinkPopoverForSelected = (0, import_react16.useCallback)(() => {
20376
19200
  const anchor = selectedElRef.current;
20377
19201
  if (!anchor) return;
20378
19202
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20389,7 +19213,7 @@ function OhhwellsBridge() {
20389
19213
  });
20390
19214
  deselect();
20391
19215
  }, [deselect]);
20392
- const handleSelectParent = (0, import_react17.useCallback)(() => {
19216
+ const handleSelectParent = (0, import_react16.useCallback)(() => {
20393
19217
  const selected = selectedElRef.current;
20394
19218
  if (!selected) return;
20395
19219
  if (toolbarVariantRef.current === "select-frame") {
@@ -20416,7 +19240,7 @@ function OhhwellsBridge() {
20416
19240
  }
20417
19241
  deselectRef.current();
20418
19242
  }, []);
20419
- const handleDuplicateSelected = (0, import_react17.useCallback)(() => {
19243
+ const handleDuplicateSelected = (0, import_react16.useCallback)(() => {
20420
19244
  const selected = selectedElRef.current;
20421
19245
  if (!selected || !isNavigationItem2(selected)) return;
20422
19246
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20532,7 +19356,7 @@ function OhhwellsBridge() {
20532
19356
  });
20533
19357
  }
20534
19358
  }, [postToParent2]);
20535
- const runPendingDeleteUndo = (0, import_react17.useCallback)(() => {
19359
+ const runPendingDeleteUndo = (0, import_react16.useCallback)(() => {
20536
19360
  const pending = pendingDeleteUndoRef.current;
20537
19361
  if (!pending) return false;
20538
19362
  pendingDeleteUndoRef.current = null;
@@ -20540,7 +19364,7 @@ function OhhwellsBridge() {
20540
19364
  enforceLinkHrefs();
20541
19365
  return true;
20542
19366
  }, []);
20543
- const handleDeleteSelected = (0, import_react17.useCallback)(() => {
19367
+ const handleDeleteSelected = (0, import_react16.useCallback)(() => {
20544
19368
  const selected = selectedElRef.current;
20545
19369
  if (!selected) return false;
20546
19370
  return deleteSelectedNavFooterItem({
@@ -20561,7 +19385,7 @@ function OhhwellsBridge() {
20561
19385
  }, [postToParent2]);
20562
19386
  handleDeleteSelectedRef.current = handleDeleteSelected;
20563
19387
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20564
- const handleLinkPopoverSubmit = (0, import_react17.useCallback)(
19388
+ const handleLinkPopoverSubmit = (0, import_react16.useCallback)(
20565
19389
  (target) => {
20566
19390
  const session = linkPopoverSessionRef.current;
20567
19391
  if (!session) return;
@@ -20627,30 +19451,19 @@ function OhhwellsBridge() {
20627
19451
  const showEditLink = toolbarShowEditLink;
20628
19452
  const currentSections = sectionsByPath[pathname] ?? [];
20629
19453
  linkPopoverOpenRef.current = linkPopover !== null;
20630
- const handleMediaSelect = (0, import_react17.useCallback)((key) => {
20631
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
20632
- (m) => (m.dataset.ohwKey ?? "") === key
20633
- ) ?? null;
20634
- if (!el) return;
20635
- selectMediaElementRef.current(el);
20636
- }, []);
20637
- const handleMediaReplace = (0, import_react17.useCallback)(
19454
+ const handleMediaReplace = (0, import_react16.useCallback)(
20638
19455
  (key) => {
20639
- postToParent2({
20640
- type: "ow:image-pick",
20641
- key,
20642
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
20643
- });
19456
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20644
19457
  },
20645
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19458
+ [postToParent2, mediaHover?.elementType]
20646
19459
  );
20647
- const handleEditCarousel = (0, import_react17.useCallback)(
19460
+ const handleEditCarousel = (0, import_react16.useCallback)(
20648
19461
  (key) => {
20649
19462
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20650
19463
  },
20651
19464
  [postToParent2]
20652
19465
  );
20653
- const handleMediaFadeOutComplete = (0, import_react17.useCallback)((key) => {
19466
+ const handleMediaFadeOutComplete = (0, import_react16.useCallback)((key) => {
20654
19467
  setUploadingRects((prev) => {
20655
19468
  if (!(key in prev)) return prev;
20656
19469
  const next = { ...prev };
@@ -20658,7 +19471,7 @@ function OhhwellsBridge() {
20658
19471
  return next;
20659
19472
  });
20660
19473
  }, []);
20661
- const handleVideoSettingsChange = (0, import_react17.useCallback)(
19474
+ const handleVideoSettingsChange = (0, import_react16.useCallback)(
20662
19475
  (key, settings) => {
20663
19476
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20664
19477
  const video = getVideoEl2(el);
@@ -20680,506 +19493,420 @@ function OhhwellsBridge() {
20680
19493
  },
20681
19494
  [postToParent2]
20682
19495
  );
20683
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20684
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(OhwLoaderSpinner, {}) }),
20685
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20686
- bridgeRoot ? (0, import_react_dom4.createPortal)(
20687
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20688
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20689
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20690
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20691
- "div",
20692
- {
20693
- className: "pointer-events-none fixed z-2147483646",
20694
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20695
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20696
- DropIndicator,
20697
- {
20698
- direction: "horizontal",
20699
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20700
- className: "!h-full !w-full"
20701
- }
20702
- )
20703
- },
20704
- `section-drop-${slot.insertIndex}-${i}`
20705
- )),
20706
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20707
- MediaOverlay,
20708
- {
20709
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20710
- isUploading: true,
20711
- fadingOut,
20712
- onFadeOutComplete: handleMediaFadeOutComplete,
20713
- onReplace: handleMediaReplace
20714
- },
20715
- `uploading-${key}`
20716
- )),
20717
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20718
- MediaOverlay,
20719
- {
20720
- hover: mediaHover,
20721
- isUploading: false,
20722
- onReplace: handleMediaReplace,
20723
- onSelect: handleMediaSelect,
20724
- onVideoSettingsChange: handleVideoSettingsChange
20725
- }
20726
- ),
20727
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20728
- MediaOverlay,
20729
- {
20730
- hover: selectedMedia,
20731
- selected: true,
20732
- hovered: mediaHover?.key === selectedMedia.key,
20733
- isUploading: false,
20734
- onReplace: handleMediaReplace,
20735
- onSelect: handleMediaSelect,
20736
- onVideoSettingsChange: handleVideoSettingsChange
20737
- }
20738
- ),
20739
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20740
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20741
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20742
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20743
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20744
- "div",
20745
- {
20746
- className: "pointer-events-none fixed z-2147483646",
20747
- style: {
20748
- left: slot.left,
20749
- top: slot.top,
20750
- width: slot.width,
20751
- height: slot.height
20752
- },
20753
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20754
- DropIndicator,
20755
- {
20756
- direction: slot.direction,
20757
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20758
- className: "!h-full !w-full"
20759
- }
20760
- )
20761
- },
20762
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20763
- )),
20764
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20765
- "div",
20766
- {
20767
- className: "pointer-events-none fixed z-2147483646",
20768
- style: {
20769
- left: slot.left,
20770
- top: slot.top,
20771
- width: slot.width,
20772
- height: slot.height
20773
- },
20774
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20775
- DropIndicator,
20776
- {
20777
- direction: slot.direction,
20778
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20779
- className: "!h-full !w-full"
20780
- }
20781
- )
19496
+ return bridgeRoot ? (0, import_react_dom4.createPortal)(
19497
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19498
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19499
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19500
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19501
+ MediaOverlay,
19502
+ {
19503
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19504
+ isUploading: true,
19505
+ fadingOut,
19506
+ onFadeOutComplete: handleMediaFadeOutComplete,
19507
+ onReplace: handleMediaReplace
19508
+ },
19509
+ `uploading-${key}`
19510
+ )),
19511
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19512
+ MediaOverlay,
19513
+ {
19514
+ hover: mediaHover,
19515
+ isUploading: false,
19516
+ onReplace: handleMediaReplace,
19517
+ onVideoSettingsChange: handleVideoSettingsChange
19518
+ }
19519
+ ),
19520
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19521
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19522
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19523
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19524
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19525
+ "div",
19526
+ {
19527
+ className: "pointer-events-none fixed z-2147483646",
19528
+ style: {
19529
+ left: slot.left,
19530
+ top: slot.top,
19531
+ width: slot.width,
19532
+ height: slot.height
20782
19533
  },
20783
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20784
- )),
20785
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20786
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20787
- hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20788
- formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20789
- ItemInteractionLayer,
20790
- {
20791
- rect: formPickRect,
20792
- state: "active-top",
20793
- itemDragSurface: false,
20794
- toolbarAlign: "left",
20795
- chromeGap: 24,
20796
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20797
- "div",
20798
- {
20799
- "data-ohw-form-toolbar": "",
20800
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20801
- children: [
20802
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20803
- "button",
20804
- {
20805
- type: "button",
20806
- "aria-label": "Add field",
20807
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20808
- onClick: () => setFieldTypePickerOpen((open) => !open),
20809
- "data-ohw-add-field": "",
20810
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
20811
- }
20812
- ),
20813
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20814
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20815
- "button",
20816
- {
20817
- type: "button",
20818
- 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",
20819
- onClick: () => {
20820
- const form = formPickElRef.current;
20821
- if (!form) return;
20822
- postToParent2({
20823
- type: "ow:form-pick",
20824
- formKey: formKeyOf(form),
20825
- hasLongText: formHasLongText(form)
20826
- });
20827
- },
20828
- children: [
20829
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
20830
- "Form settings",
20831
- formPickCount ? (
20832
- // Counter pill, per the design — not a text suffix.
20833
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20834
- "span",
20835
- {
20836
- "data-ohw-form-count": "",
20837
- 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",
20838
- children: formPickCount
20839
- }
20840
- )
20841
- ) : null
20842
- ]
20843
- }
20844
- ),
20845
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20846
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20847
- "button",
20848
- {
20849
- type: "button",
20850
- "aria-pressed": formViewState === state,
20851
- 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"),
20852
- onClick: () => {
20853
- const form = formPickElRef.current;
20854
- const key = form ? formKeyOf(form) : null;
20855
- if (!form || !key) return;
20856
- const initial = successInitialFor(form, key, editContentRef.current);
20857
- setFormViewState(form, key, state, initial);
20858
- setFormViewStateUi(state);
20859
- setFormPickRect(form.getBoundingClientRect());
20860
- if (state === "success") {
20861
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20862
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20863
- } else {
20864
- deactivateRef.current();
20865
- }
20866
- },
20867
- children: state
20868
- },
20869
- state
20870
- )) })
20871
- ]
20872
- }
20873
- )
20874
- }
20875
- ),
20876
- formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20877
- ItemInteractionLayer,
20878
- {
20879
- rect: formHoverRect,
20880
- state: "hover",
20881
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20882
- }
20883
- ),
20884
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20885
- ItemInteractionLayer,
20886
- {
20887
- rect: fieldPickRect,
20888
- state: fieldDragging ? "dragging" : "active-top",
20889
- itemDragSurface: false,
20890
- toolbarAlign: "left",
20891
- chromeGap: 10,
20892
- showHandle: true,
20893
- dragHandleLabel: "Reorder field",
20894
- onDragHandleDragStart: handleFieldDragStart,
20895
- onDragHandleDragEnd: handleFieldDragEnd,
20896
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20897
- FormFieldToolbar,
20898
- {
20899
- type: fieldPickState.type,
20900
- required: fieldPickState.required,
20901
- onTypeChange: handleFieldTypeChange,
20902
- onRequiredToggle: handleFieldRequiredToggle,
20903
- onDuplicate: handleFieldDuplicate,
20904
- onDelete: handleFieldDelete
20905
- }
20906
- )
20907
- }
20908
- ),
20909
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20910
- "div",
20911
- {
20912
- className: "pointer-events-none fixed z-[2147483644]",
20913
- style: { top: slot.top, left: slot.left, width: slot.width },
20914
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20915
- DropIndicator,
20916
- {
20917
- direction: "horizontal",
20918
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20919
- className: "!w-full"
20920
- }
20921
- )
19534
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19535
+ DropIndicator,
19536
+ {
19537
+ direction: slot.direction,
19538
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19539
+ className: "!h-full !w-full"
19540
+ }
19541
+ )
19542
+ },
19543
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19544
+ )),
19545
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19546
+ "div",
19547
+ {
19548
+ className: "pointer-events-none fixed z-2147483646",
19549
+ style: {
19550
+ left: slot.left,
19551
+ top: slot.top,
19552
+ width: slot.width,
19553
+ height: slot.height
20922
19554
  },
20923
- `field-drop-${i}`
20924
- )) : null,
20925
- fieldTypePickerOpen && formPickRect ? (() => {
20926
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20927
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20928
- "div",
19555
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19556
+ DropIndicator,
20929
19557
  {
20930
- className: "pointer-events-none fixed z-[2147483645]",
20931
- style: {
20932
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20933
- left: toolbar ? toolbar.left : formPickRect.left + 24
20934
- },
20935
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
19558
+ direction: slot.direction,
19559
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19560
+ className: "!h-full !w-full"
20936
19561
  }
20937
- );
20938
- })() : null,
20939
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20940
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20941
- FooterContainerChrome,
20942
- {
20943
- rect: toolbarRect,
20944
- onAdd: handleAddFooterColumn,
20945
- addDisabled: !canAddFooterColumn()
20946
- }
20947
- ),
20948
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20949
- ItemInteractionLayer,
20950
- {
20951
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20952
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20953
- elRef: glowElRef,
20954
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20955
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20956
- dragDisabled: reorderDragDisabled,
20957
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20958
- onDragHandleDragStart: handleItemDragStart,
20959
- onDragHandleDragEnd: handleItemDragEnd,
20960
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20961
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20962
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20963
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20964
- ItemActionToolbar,
20965
- {
20966
- onEditLink: openLinkPopoverForSelected,
20967
- onStyle: () => {
20968
- const row = selectedElRef.current;
20969
- if (!row) return;
20970
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20971
- else openSocialsDisplayPanel(row);
20972
- },
20973
- showStyle: selectedIsSocialsRow,
20974
- styleActive: floatingPanel?.kind === "socials-display",
20975
- onAddItem: handleAddChildItem,
20976
- onSelectParent: handleSelectParent,
20977
- onDuplicate: handleDuplicateSelected,
20978
- onDelete: handleDeleteSelected,
20979
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20980
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20981
- return row ? !canAddSocialItem(row) : false;
20982
- })(),
20983
- editLinkDisabled: false,
20984
- moreDisabled: false,
20985
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20986
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20987
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20988
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19562
+ )
19563
+ },
19564
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19565
+ )),
19566
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19567
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19568
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19569
+ formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19570
+ ItemInteractionLayer,
19571
+ {
19572
+ rect: formPickRect,
19573
+ state: "active-top",
19574
+ itemDragSurface: false,
19575
+ toolbarAlign: "left",
19576
+ chromeGap: 24,
19577
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19578
+ "div",
19579
+ {
19580
+ "data-ohw-form-toolbar": "",
19581
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19582
+ children: [
19583
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19584
+ "button",
19585
+ {
19586
+ type: "button",
19587
+ "aria-label": "Add field",
19588
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19589
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19590
+ "data-ohw-add-field": "",
19591
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
19592
+ }
20989
19593
  ),
20990
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20991
- dropdownOpen: navDropdownPreviewOpen,
20992
- onDropdownOpenChange: handleNavDropdownOpenChange,
20993
- headingVisible: footerHeadingVisible,
20994
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20995
- }
20996
- ) : void 0
20997
- }
20998
- ),
20999
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21000
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21001
- EditGlowChrome,
19594
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19595
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19596
+ "button",
19597
+ {
19598
+ type: "button",
19599
+ 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",
19600
+ onClick: () => {
19601
+ const form = formPickElRef.current;
19602
+ if (!form) return;
19603
+ postToParent2({
19604
+ type: "ow:form-pick",
19605
+ formKey: formKeyOf(form),
19606
+ hasLongText: formHasLongText(form)
19607
+ });
19608
+ },
19609
+ children: [
19610
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
19611
+ "Form settings",
19612
+ formPickCount ? (
19613
+ // Counter pill, per the design — not a text suffix.
19614
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19615
+ "span",
19616
+ {
19617
+ "data-ohw-form-count": "",
19618
+ 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",
19619
+ children: formPickCount
19620
+ }
19621
+ )
19622
+ ) : null
19623
+ ]
19624
+ }
19625
+ ),
19626
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19627
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19628
+ "button",
19629
+ {
19630
+ type: "button",
19631
+ "aria-pressed": formViewState === state,
19632
+ 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"),
19633
+ onClick: () => {
19634
+ const form = formPickElRef.current;
19635
+ const key = form ? formKeyOf(form) : null;
19636
+ if (!form || !key) return;
19637
+ const initial = successInitialFor(form, key, editContentRef.current);
19638
+ setFormViewState(form, key, state, initial);
19639
+ setFormViewStateUi(state);
19640
+ setFormPickRect(form.getBoundingClientRect());
19641
+ if (state === "success") {
19642
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19643
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19644
+ } else {
19645
+ deactivateRef.current();
19646
+ }
19647
+ },
19648
+ children: state
19649
+ },
19650
+ state
19651
+ )) })
19652
+ ]
19653
+ }
19654
+ )
19655
+ }
19656
+ ),
19657
+ formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19658
+ ItemInteractionLayer,
19659
+ {
19660
+ rect: formHoverRect,
19661
+ state: "hover",
19662
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19663
+ }
19664
+ ),
19665
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19666
+ ItemInteractionLayer,
19667
+ {
19668
+ rect: fieldPickRect,
19669
+ state: fieldDragging ? "dragging" : "active-top",
19670
+ itemDragSurface: false,
19671
+ toolbarAlign: "left",
19672
+ chromeGap: 10,
19673
+ showHandle: true,
19674
+ dragHandleLabel: "Reorder field",
19675
+ onDragHandleDragStart: handleFieldDragStart,
19676
+ onDragHandleDragEnd: handleFieldDragEnd,
19677
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19678
+ FormFieldToolbar,
21002
19679
  {
21003
- rect: toolbarRect,
21004
- elRef: glowElRef,
21005
- reorderHrefKey,
21006
- dragDisabled: reorderDragDisabled,
21007
- hideHandle: isItemDragging
19680
+ type: fieldPickState.type,
19681
+ required: fieldPickState.required,
19682
+ onTypeChange: handleFieldTypeChange,
19683
+ onRequiredToggle: handleFieldRequiredToggle,
19684
+ onDuplicate: handleFieldDuplicate,
19685
+ onDelete: handleFieldDelete
21008
19686
  }
21009
- ),
21010
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21011
- FloatingToolbar,
19687
+ )
19688
+ }
19689
+ ),
19690
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19691
+ "div",
19692
+ {
19693
+ className: "pointer-events-none fixed z-[2147483644]",
19694
+ style: { top: slot.top, left: slot.left, width: slot.width },
19695
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19696
+ DropIndicator,
21012
19697
  {
21013
- rect: toolbarRect,
21014
- parentScroll: parentScrollRef.current,
21015
- elRef: toolbarElRef,
21016
- onCommand: handleCommand,
21017
- activeCommands,
21018
- showEditLink,
21019
- onEditLink: openLinkPopoverForActive
19698
+ direction: "horizontal",
19699
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19700
+ className: "!w-full"
21020
19701
  }
21021
19702
  )
21022
- ] }),
21023
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19703
+ },
19704
+ `field-drop-${i}`
19705
+ )) : null,
19706
+ fieldTypePickerOpen && formPickRect ? (() => {
19707
+ const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
19708
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21024
19709
  "div",
21025
19710
  {
21026
- "data-ohw-max-badge": "",
19711
+ className: "pointer-events-none fixed z-[2147483645]",
21027
19712
  style: {
21028
- position: "fixed",
21029
- top: maxBadge.rect.bottom + 4,
21030
- left: maxBadge.rect.right,
21031
- transform: "translateX(-100%)",
21032
- zIndex: 2147483647,
21033
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
21034
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
21035
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
21036
- borderRadius: 4,
21037
- padding: "2px 6px",
21038
- fontSize: 11,
21039
- fontWeight: 500,
21040
- pointerEvents: "none"
19713
+ top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
19714
+ left: toolbar ? toolbar.left : formPickRect.left + 24
21041
19715
  },
21042
- children: [
21043
- maxBadge.current,
21044
- "/",
21045
- maxBadge.max
21046
- ]
19716
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
21047
19717
  }
21048
- ),
21049
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21050
- StateToggle,
19718
+ );
19719
+ })() : null,
19720
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19721
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19722
+ FooterContainerChrome,
19723
+ {
19724
+ rect: toolbarRect,
19725
+ onAdd: handleAddFooterColumn,
19726
+ addDisabled: !canAddFooterColumn()
19727
+ }
19728
+ ),
19729
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19730
+ ItemInteractionLayer,
19731
+ {
19732
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19733
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19734
+ elRef: glowElRef,
19735
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19736
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19737
+ dragDisabled: reorderDragDisabled,
19738
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19739
+ onDragHandleDragStart: handleItemDragStart,
19740
+ onDragHandleDragEnd: handleItemDragEnd,
19741
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19742
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19743
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19744
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19745
+ ItemActionToolbar,
19746
+ {
19747
+ onEditLink: openLinkPopoverForSelected,
19748
+ onStyle: () => {
19749
+ const row = selectedElRef.current;
19750
+ if (!row) return;
19751
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19752
+ else openSocialsDisplayPanel(row);
19753
+ },
19754
+ showStyle: selectedIsSocialsRow,
19755
+ styleActive: floatingPanel?.kind === "socials-display",
19756
+ onAddItem: handleAddChildItem,
19757
+ onSelectParent: handleSelectParent,
19758
+ onDuplicate: handleDuplicateSelected,
19759
+ onDelete: handleDeleteSelected,
19760
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19761
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19762
+ return row ? !canAddSocialItem(row) : false;
19763
+ })(),
19764
+ editLinkDisabled: false,
19765
+ moreDisabled: false,
19766
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19767
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19768
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19769
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19770
+ ),
19771
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19772
+ dropdownOpen: navDropdownPreviewOpen,
19773
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19774
+ headingVisible: footerHeadingVisible,
19775
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19776
+ }
19777
+ ) : void 0
19778
+ }
19779
+ ),
19780
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19781
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19782
+ EditGlowChrome,
21051
19783
  {
21052
- rect: toggleState.rect,
21053
- activeState: toggleState.activeState,
21054
- states: toggleState.states,
21055
- onStateChange: handleStateChange
19784
+ rect: toolbarRect,
19785
+ elRef: glowElRef,
19786
+ reorderHrefKey,
19787
+ dragDisabled: reorderDragDisabled,
19788
+ hideHandle: isItemDragging
21056
19789
  }
21057
19790
  ),
21058
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21059
- "div",
19791
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19792
+ FloatingToolbar,
21060
19793
  {
21061
- "data-ohw-section-insert-line": "",
21062
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
21063
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
21064
- children: [
21065
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
21066
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21067
- Badge,
21068
- {
21069
- 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",
21070
- onClick: () => {
21071
- window.parent.postMessage(
21072
- {
21073
- type: "ow:add-section",
21074
- insertAfter: sectionGap.insertAfter,
21075
- insertBefore: sectionGap.insertBefore
21076
- },
21077
- "*"
21078
- );
21079
- },
21080
- children: "Add Section"
21081
- }
21082
- ),
21083
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
21084
- ]
19794
+ rect: toolbarRect,
19795
+ parentScroll: parentScrollRef.current,
19796
+ elRef: toolbarElRef,
19797
+ onCommand: handleCommand,
19798
+ activeCommands,
19799
+ showEditLink,
19800
+ onEditLink: openLinkPopoverForActive
21085
19801
  }
21086
- ),
21087
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21088
- LinkPopover,
21089
- {
21090
- panelRef: linkPopoverPanelRef,
21091
- portalContainer: dialogPortalContainer,
21092
- open: true,
21093
- mode: linkPopover.mode ?? "edit",
21094
- pages: sitePages,
21095
- sections: currentSections,
21096
- sectionsByPath,
21097
- initialTarget: linkPopover.target,
21098
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21099
- onClose: closeLinkPopover,
21100
- onSubmit: handleLinkPopoverSubmit
19802
+ )
19803
+ ] }),
19804
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19805
+ "div",
19806
+ {
19807
+ "data-ohw-max-badge": "",
19808
+ style: {
19809
+ position: "fixed",
19810
+ top: maxBadge.rect.bottom + 4,
19811
+ left: maxBadge.rect.right,
19812
+ transform: "translateX(-100%)",
19813
+ zIndex: 2147483647,
19814
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19815
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19816
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19817
+ borderRadius: 4,
19818
+ padding: "2px 6px",
19819
+ fontSize: 11,
19820
+ fontWeight: 500,
19821
+ pointerEvents: "none"
21101
19822
  },
21102
- linkPopover.key
21103
- ) : null,
21104
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21105
- FloatingPanel,
21106
- {
21107
- open: true,
21108
- title: floatingPanel.title,
21109
- context: floatingPanel.context,
21110
- position: floatingPanelPos,
21111
- onPositionChange: setFloatingPanelPos,
21112
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21113
- onClose: closeFloatingPanelOnly,
21114
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21115
- SocialsDisplayPanel,
19823
+ children: [
19824
+ maxBadge.current,
19825
+ "/",
19826
+ maxBadge.max
19827
+ ]
19828
+ }
19829
+ ),
19830
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19831
+ StateToggle,
19832
+ {
19833
+ rect: toggleState.rect,
19834
+ activeState: toggleState.activeState,
19835
+ states: toggleState.states,
19836
+ onStateChange: handleStateChange
19837
+ }
19838
+ ),
19839
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19840
+ "div",
19841
+ {
19842
+ "data-ohw-section-insert-line": "",
19843
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19844
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19845
+ children: [
19846
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19847
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19848
+ Badge,
21116
19849
  {
21117
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21118
- onChange: (next) => {
21119
- changeSocialsDisplay(floatingPanel.row, next);
21120
- setFloatingPanel({ ...floatingPanel });
21121
- }
19850
+ 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",
19851
+ onClick: () => {
19852
+ window.parent.postMessage(
19853
+ {
19854
+ type: "ow:add-section",
19855
+ insertAfter: sectionGap.insertAfter,
19856
+ insertBefore: sectionGap.insertBefore
19857
+ },
19858
+ "*"
19859
+ );
19860
+ },
19861
+ children: "Add Section"
21122
19862
  }
21123
- )
21124
- }
21125
- ) : null
21126
- ] }),
21127
- bridgeRoot
21128
- ) : null
21129
- ] });
21130
- }
21131
-
21132
- // src/ui/EmptySection.tsx
21133
- var import_link = __toESM(require("next/link"), 1);
21134
- var import_jsx_runtime34 = require("react/jsx-runtime");
21135
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21136
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
21137
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21138
- "p",
21139
- {
21140
- style: {
21141
- fontFamily: "var(--brand-font-body)",
21142
- fontSize: "0.75rem",
21143
- fontWeight: 500,
21144
- letterSpacing: "0.15em",
21145
- textTransform: "uppercase",
21146
- color: "var(--brand-accent)",
21147
- marginBottom: "1.5rem"
21148
- },
21149
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
21150
- }
21151
- ),
21152
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21153
- "h1",
21154
- {
21155
- style: {
21156
- fontFamily: "var(--brand-font-heading)",
21157
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21158
- lineHeight: 1.1,
21159
- letterSpacing: "-0.025em",
21160
- color: "var(--brand-text)",
21161
- marginBottom: "1rem"
21162
- },
21163
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21164
- children: title
21165
- }
21166
- ),
21167
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21168
- "p",
21169
- {
21170
- style: {
21171
- fontFamily: "var(--brand-font-body)",
21172
- fontSize: "1rem",
21173
- lineHeight: 1.7,
21174
- fontWeight: 300,
21175
- color: "var(--brand-text-muted)",
21176
- maxWidth: "340px"
19863
+ ),
19864
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19865
+ ]
19866
+ }
19867
+ ),
19868
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19869
+ LinkPopover,
19870
+ {
19871
+ panelRef: linkPopoverPanelRef,
19872
+ portalContainer: dialogPortalContainer,
19873
+ open: true,
19874
+ mode: linkPopover.mode ?? "edit",
19875
+ pages: sitePages,
19876
+ sections: currentSections,
19877
+ sectionsByPath,
19878
+ initialTarget: linkPopover.target,
19879
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19880
+ onClose: closeLinkPopover,
19881
+ onSubmit: handleLinkPopoverSubmit
21177
19882
  },
21178
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21179
- children: "This page doesn't have any content yet."
21180
- }
21181
- )
21182
- ] });
19883
+ linkPopover.key
19884
+ ) : null,
19885
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19886
+ FloatingPanel,
19887
+ {
19888
+ open: true,
19889
+ title: floatingPanel.title,
19890
+ context: floatingPanel.context,
19891
+ position: floatingPanelPos,
19892
+ onPositionChange: setFloatingPanelPos,
19893
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19894
+ onClose: closeFloatingPanelOnly,
19895
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19896
+ SocialsDisplayPanel,
19897
+ {
19898
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19899
+ onChange: (next) => {
19900
+ changeSocialsDisplay(floatingPanel.row, next);
19901
+ setFloatingPanel({ ...floatingPanel });
19902
+ }
19903
+ }
19904
+ )
19905
+ }
19906
+ ) : null
19907
+ ] }),
19908
+ bridgeRoot
19909
+ ) : null;
21183
19910
  }
21184
19911
  // Annotate the CommonJS export names for ESM import in node:
21185
19912
  0 && (module.exports = {
@@ -21198,7 +19925,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
21198
19925
  DropdownMenuItem,
21199
19926
  DropdownMenuSeparator,
21200
19927
  DropdownMenuTrigger,
21201
- EmptySection,
21202
19928
  ItemActionToolbar,
21203
19929
  ItemInteractionLayer,
21204
19930
  LinkEditorPanel,