@ohhwells/bridge 0.1.70-next.212 → 0.1.70

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
  }
@@ -580,12 +231,7 @@ var AI_RESPONSIVE_CSS = [
580
231
  "@media (max-width: 640px) {",
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
- // Group containers flatten to a column on phones; span placements come along for free.
584
- " [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
585
- " [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
586
234
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
587
- " [data-ai-responsive] { overflow-x: hidden; }",
588
- " [data-ai-responsive] img { max-width: 100%; }",
589
235
  "}"
590
236
  ].join("\n");
591
237
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -663,7 +309,7 @@ function ButtonEl({
663
309
  }) {
664
310
  const secondary = slots.variant === "secondary";
665
311
  const href = str(slots.href);
666
- 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`) } : {};
667
313
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
668
314
  "a",
669
315
  {
@@ -679,7 +325,7 @@ function ButtonEl({
679
325
  textDecoration: "none",
680
326
  cursor: "pointer",
681
327
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
682
- ...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 }
683
329
  },
684
330
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
685
331
  }
@@ -1185,24 +831,7 @@ function CardBlock({ node, ctx, path }) {
1185
831
  minWidth: 0
1186
832
  },
1187
833
  children: [
1188
- media && (horizontal ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1189
- "div",
1190
- {
1191
- style: (
1192
- // An icon hugs its glyph — flex:1 gave a 48px icon half the card and pushed the
1193
- // text to the far side. Photos keep the half-and-half split. The inset has no
1194
- // inner padding (the photo split absorbed that), so the icon carries its own gap.
1195
- /^(lucide|simple):/.test(mediaRef) ? {
1196
- flexShrink: 0,
1197
- display: "flex",
1198
- alignItems: "center",
1199
- padding: mediaInset,
1200
- [mediaPosition === "right" ? "marginLeft" : "marginRight"]: 20
1201
- } : { flex: 1, minWidth: 0, display: "flex", alignItems: "center", padding: mediaInset }
1202
- ),
1203
- children: media
1204
- }
1205
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
834
+ media && (horizontal ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, minWidth: 0, display: "flex", alignItems: "center", padding: mediaInset }, children: media }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1206
835
  "div",
1207
836
  {
1208
837
  style: /^(lucide|simple):/.test(mediaRef) ? { padding: `${AI_TREE_TOKENS.paddingBlock}px ${AI_TREE_TOKENS.paddingBlock}px 0` } : hasBg ? void 0 : { borderRadius: AI_TREE_TOKENS.radiusCard, overflow: "hidden" },
@@ -1466,49 +1095,6 @@ function renderNode(node, ctx, path) {
1466
1095
  switch (node.type) {
1467
1096
  case "text":
1468
1097
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextBlock, { slots, ctx, path });
1469
- // Layout container: arranges child blocks, contributes no content of its own. `grid` is a
1470
- // nested 12-column grid the children span (a collage is 3–5 media on it, bottom-aligned so
1471
- // mixed aspects read as a composition); `split` is exactly two children at a ratio; `stack`
1472
- // is a column. Children render through this same dispatcher, so edit markers, media
1473
- // resolution, and copy paths all work unchanged inside a group.
1474
- case "group": {
1475
- const layout = str(slots.layout);
1476
- const gap = slots.spacing === "tight" ? AI_TREE_TOKENS.spacing3 : slots.spacing === "airy" ? AI_TREE_TOKENS.spacing8 : AI_TREE_TOKENS.spacing6;
1477
- const kids = (node.children ?? []).map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1478
- "div",
1479
- {
1480
- style: layout === "grid" ? {
1481
- gridColumn: `span ${typeof child.span === "number" ? Math.min(12, Math.max(1, child.span)) : 12}`,
1482
- minWidth: 0
1483
- } : { minWidth: 0 },
1484
- children: renderNode(child, ctx, `${path}.c${i}`)
1485
- },
1486
- i
1487
- ));
1488
- if (layout === "grid") {
1489
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1490
- "div",
1491
- {
1492
- "data-ai-group": "grid",
1493
- style: { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap, alignItems: "end" },
1494
- children: kids
1495
- }
1496
- );
1497
- }
1498
- if (layout === "split") {
1499
- const ratio = str(slots.ratio);
1500
- const cols = ratio === "3:5" ? "3fr 5fr" : ratio === "5:3" ? "5fr 3fr" : "1fr 1fr";
1501
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1502
- "div",
1503
- {
1504
- "data-ai-group": "split",
1505
- style: { display: "grid", gridTemplateColumns: cols, gap, alignItems: "center" },
1506
- children: kids
1507
- }
1508
- );
1509
- }
1510
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-ai-group": "stack", style: { display: "flex", flexDirection: "column", gap }, children: kids });
1511
- }
1512
1098
  case "button":
1513
1099
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonEl, { slots, ctx, path });
1514
1100
  case "button-row":
@@ -1641,14 +1227,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1641
1227
  return null;
1642
1228
  }
1643
1229
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1644
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1645
- const blockBrand = band?.brand ?? resolvedBrand;
1646
1230
  const ctx = {
1647
- brand: blockBrand,
1231
+ brand: resolvedBrand,
1648
1232
  resolveMedia: resolveMedia ?? (() => null),
1649
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1650
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1651
- ...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
1652
1235
  };
1653
1236
  const settings = tree.settings ?? {};
1654
1237
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1656,20 +1239,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1656
1239
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1657
1240
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1658
1241
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1659
- const toneBackground = (() => {
1660
- const { dark, primary, light } = resolvedBrand.palette;
1661
- switch (settings.sectionBackground) {
1662
- case "surface":
1663
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1664
- case "accent":
1665
- return primary;
1666
- case "accent-soft":
1667
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1668
- default:
1669
- return void 0;
1670
- }
1671
- })();
1672
- const distributed = !isOverlay && settings.textDistribution;
1673
1242
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1674
1243
  "section",
1675
1244
  {
@@ -1679,11 +1248,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1679
1248
  style: {
1680
1249
  position: "relative",
1681
1250
  padding: `${pad}px 0`,
1682
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1251
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1683
1252
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1684
1253
  backgroundSize: "cover",
1685
- backgroundPosition: "center",
1686
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1254
+ backgroundPosition: "center"
1687
1255
  },
1688
1256
  children: [
1689
1257
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
@@ -1707,24 +1275,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1707
1275
  display: "grid",
1708
1276
  gridTemplateColumns: "repeat(12, 1fr)",
1709
1277
  gap: AI_TREE_TOKENS.spacing6,
1710
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1278
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1711
1279
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1712
1280
  },
1713
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1714
- "div",
1715
- {
1716
- "data-ai-cell": "",
1717
- style: {
1718
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1719
- minWidth: 0,
1720
- // space-between: each column becomes a flex column whose content spreads over
1721
- // the full row height instead of clumping at the top.
1722
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1723
- },
1724
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1725
- },
1726
- b
1727
- ))
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))
1728
1282
  },
1729
1283
  r2
1730
1284
  ))
@@ -1740,36 +1294,17 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1740
1294
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1741
1295
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1742
1296
  var REMOVED_ATTR = "data-ohw-ai-removed";
1743
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1744
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1745
- function readRootVar(name) {
1746
- if (typeof document === "undefined") return "";
1747
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1748
- }
1749
- function deriveBrandOverride() {
1750
- const dark = readRootVar("--ohw-brand-dark");
1751
- const primary = readRootVar("--ohw-brand-primary");
1752
- const light = readRootVar("--ohw-brand-light");
1753
- if (!dark || !primary || !light) return null;
1754
- const accent = readRootVar("--ohw-brand-accent");
1755
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1756
- const body = readRootVar("--font-body");
1757
- return {
1758
- palette: { dark, primary, accent: accent || dark, light },
1759
- fonts: {
1760
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1761
- body: body || AI_DEFAULT_BRAND.fonts.body
1762
- }
1763
- };
1764
- }
1765
1297
  function deriveTemplateBrand() {
1766
- const dark = readRootVar("--color-dark");
1767
- const primary = readRootVar("--color-primary");
1768
- 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");
1769
1304
  if (!dark || !primary || !light) return null;
1770
- const accent = readRootVar("--color-accent");
1771
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1772
- 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");
1773
1308
  return {
1774
1309
  palette: { dark, primary, accent: accent || dark, light },
1775
1310
  fonts: {
@@ -1841,24 +1376,6 @@ function syncRemovedSections(state) {
1841
1376
  }
1842
1377
  }
1843
1378
  }
1844
- function syncTemplateHidden(state, pageHasSections) {
1845
- const hide = state.hideTemplate === true && pageHasSections;
1846
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1847
- if (!hide) {
1848
- el.style.removeProperty("display");
1849
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1850
- }
1851
- }
1852
- if (!hide) return;
1853
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1854
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1855
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1856
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1857
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1858
- el.style.display = "none";
1859
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1860
- }
1861
- }
1862
1379
  function syncReplacedOriginals(state) {
1863
1380
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1864
1381
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1879,12 +1396,8 @@ function syncReplacedOriginals(state) {
1879
1396
  }
1880
1397
  function applyAiSectionsToDom(state, options) {
1881
1398
  if (typeof document === "undefined") return;
1882
- const brandOverride = deriveBrandOverride();
1883
1399
  const templateBrand = deriveTemplateBrand();
1884
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1885
- const pagePath = window.location.pathname;
1886
- const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
1887
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1400
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1888
1401
  for (const [id, section] of mounted) {
1889
1402
  if (!activeIds.has(id)) {
1890
1403
  section.root.unmount();
@@ -1892,8 +1405,8 @@ function applyAiSectionsToDom(state, options) {
1892
1405
  mounted.delete(id);
1893
1406
  }
1894
1407
  }
1895
- for (const entry of pageSections) {
1896
- const serialized = JSON.stringify(entry) + brandKey;
1408
+ for (const entry of state.sections) {
1409
+ const serialized = JSON.stringify(entry);
1897
1410
  const existing = mounted.get(entry.id);
1898
1411
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1899
1412
  continue;
@@ -1907,7 +1420,6 @@ function applyAiSectionsToDom(state, options) {
1907
1420
  mounted.delete(entry.id);
1908
1421
  }
1909
1422
  container.setAttribute("data-ohw-section", entry.id);
1910
- container.setAttribute("data-ohw-instance", entry.id);
1911
1423
  container.setAttribute("data-ohw-section-label", entry.label);
1912
1424
  placeContainer(container, entry);
1913
1425
  const root = mounted.get(entry.id)?.root ?? (0, import_client.createRoot)(container);
@@ -1918,7 +1430,7 @@ function applyAiSectionsToDom(state, options) {
1918
1430
  AiTreeRenderer,
1919
1431
  {
1920
1432
  tree: entry.tree,
1921
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1433
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1922
1434
  resolveMedia,
1923
1435
  editKeyPrefix: `ai.${entry.id}`
1924
1436
  }
@@ -1927,20 +1439,8 @@ function applyAiSectionsToDom(state, options) {
1927
1439
  });
1928
1440
  mounted.set(entry.id, { root, container, serialized });
1929
1441
  }
1930
- if (state.hideTemplate === true) {
1931
- let prev = null;
1932
- for (const entry of pageSections) {
1933
- const el = mounted.get(entry.id)?.container;
1934
- if (!el) continue;
1935
- if (prev && !(prev.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) {
1936
- prev.insertAdjacentElement("afterend", el);
1937
- }
1938
- prev = el;
1939
- }
1940
- }
1941
1442
  syncReplacedOriginals(state);
1942
1443
  syncRemovedSections(state);
1943
- syncTemplateHidden(state, pageSections.length > 0);
1944
1444
  }
1945
1445
 
1946
1446
  // src/useLinkHrefGuardian.ts
@@ -2547,7 +2047,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2547
2047
  const autoId = (0, import_react5.useId)();
2548
2048
  const insertAfter = insertAfterProp ?? autoId;
2549
2049
  const [schedule, setSchedule] = (0, import_react5.useState)(null);
2550
- const [loading, setLoading] = (0, import_react5.useState)(initialScheduleId !== null);
2050
+ const [loading, setLoading] = (0, import_react5.useState)(true);
2551
2051
  const [inEditor, setInEditor] = (0, import_react5.useState)(false);
2552
2052
  const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
2553
2053
  const [modalState, setModalState] = (0, import_react5.useState)(null);
@@ -2721,10 +2221,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2721
2221
  "*"
2722
2222
  );
2723
2223
  };
2224
+ if (!inEditor && !loading && !schedule) return null;
2724
2225
  const sectionId = `scheduling-${insertAfter}`;
2725
- if (!inEditor && !loading && !schedule) {
2726
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2727
- }
2728
2226
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2729
2227
  "section",
2730
2228
  {
@@ -7630,17 +7128,13 @@ function MediaOverlay({
7630
7128
  hover,
7631
7129
  isUploading,
7632
7130
  fadingOut = false,
7633
- selected = false,
7634
- hovered = false,
7635
7131
  onFadeOutComplete,
7636
7132
  onReplace,
7637
- onSelect,
7638
7133
  onVideoSettingsChange
7639
7134
  }) {
7640
7135
  const { rect } = hover;
7641
7136
  const skeletonRef = React8.useRef(null);
7642
7137
  const isVideo = hover.elementType === "video";
7643
- const showChrome = !selected || hovered;
7644
7138
  const autoplay = hover.videoAutoplay ?? true;
7645
7139
  const muted = hover.videoMuted ?? true;
7646
7140
  const box = {
@@ -7675,7 +7169,7 @@ function MediaOverlay({
7675
7169
  }
7676
7170
  );
7677
7171
  }
7678
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7172
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7679
7173
  "div",
7680
7174
  {
7681
7175
  "data-ohw-bridge": "",
@@ -7745,13 +7239,11 @@ function MediaOverlay({
7745
7239
  // in-document, pointer-events does it natively. The button below opts back in, so
7746
7240
  // Replace still works.
7747
7241
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7748
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7749
- // than hovered. Hover keeps the existing tinted preview.
7750
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7751
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7242
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7243
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7752
7244
  },
7753
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7754
- children: showChrome && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7245
+ onClick: () => onReplace(hover.key),
7246
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7755
7247
  Button,
7756
7248
  {
7757
7249
  "data-ohw-media-overlay": "",
@@ -7770,7 +7262,7 @@ function MediaOverlay({
7770
7262
  },
7771
7263
  children: [
7772
7264
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
7773
- isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image"
7265
+ isVideo ? "Replace video" : "Replace image"
7774
7266
  ]
7775
7267
  }
7776
7268
  )
@@ -7840,9 +7332,6 @@ var import_lucide_react7 = require("lucide-react");
7840
7332
 
7841
7333
  // src/lib/sections.ts
7842
7334
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7843
- function isChromeSection(el) {
7844
- return el.matches("header, nav, footer, aside");
7845
- }
7846
7335
  function titleCaseSectionId(id) {
7847
7336
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7848
7337
  }
@@ -7853,8 +7342,6 @@ function parseSectionsFromRoot(root) {
7853
7342
  const id = el.getAttribute("data-ohw-section") ?? "";
7854
7343
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7855
7344
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7856
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7857
- continue;
7858
7345
  seen.add(id);
7859
7346
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7860
7347
  sections.push({ id, label });
@@ -7872,12 +7359,8 @@ function parseSectionsFromHtml(html) {
7872
7359
 
7873
7360
  // src/ui/ai-section/AiSectionOverlay.tsx
7874
7361
  var import_jsx_runtime17 = require("react/jsx-runtime");
7875
- function findSectionElement(instanceId) {
7876
- const escaped = CSS.escape(instanceId);
7877
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7878
- }
7879
- function readRect(instanceId) {
7880
- const el = findSectionElement(instanceId);
7362
+ function readRect(sectionId) {
7363
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7881
7364
  if (!el) return null;
7882
7365
  const r2 = el.getBoundingClientRect();
7883
7366
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7900,7 +7383,7 @@ function useLiveSectionRect(sectionId) {
7900
7383
  const opts = { capture: true, passive: true };
7901
7384
  window.addEventListener("scroll", update, opts);
7902
7385
  window.addEventListener("resize", update);
7903
- const el = findSectionElement(sectionId);
7386
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7904
7387
  const ro = el ? new ResizeObserver(update) : null;
7905
7388
  if (el && ro) ro.observe(el);
7906
7389
  const interval = setInterval(update, 500);
@@ -7913,14 +7396,6 @@ function useLiveSectionRect(sectionId) {
7913
7396
  }, [sectionId]);
7914
7397
  return rect;
7915
7398
  }
7916
- function computeSectionBoundaryFlags(instanceId) {
7917
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7918
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7919
- );
7920
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7921
- if (index === -1) return { isFirst: true, isLast: true };
7922
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7923
- }
7924
7399
  var PRIMARY2 = "#0885FE";
7925
7400
  function edgeAwareRadius(rect) {
7926
7401
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7994,7 +7469,6 @@ function AiSectionOverlay({
7994
7469
  }) {
7995
7470
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
7996
7471
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
7997
- const [reviewButtonsHidden, setReviewButtonsHidden] = (0, import_react8.useState)(false);
7998
7472
  const reviewIdRef = (0, import_react8.useRef)(null);
7999
7473
  reviewIdRef.current = reviewId;
8000
7474
  const selectedIdRef = (0, import_react8.useRef)(null);
@@ -8003,7 +7477,7 @@ function AiSectionOverlay({
8003
7477
  (el) => {
8004
7478
  postToParent2({
8005
7479
  type: "ow:section-selected",
8006
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7480
+ sectionId: el?.dataset.ohwSection ?? null,
8007
7481
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
8008
7482
  });
8009
7483
  },
@@ -8012,7 +7486,7 @@ function AiSectionOverlay({
8012
7486
  const selectFromElement = (0, import_react8.useCallback)(
8013
7487
  (el, options) => {
8014
7488
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
8015
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7489
+ const id = sectionEl?.dataset.ohwSection ?? null;
8016
7490
  if (id === selectedIdRef.current) return;
8017
7491
  setSelectedId(id);
8018
7492
  if (options?.report !== false) report(sectionEl);
@@ -8053,10 +7527,9 @@ function AiSectionOverlay({
8053
7527
  }
8054
7528
  const found = readRect(sectionId) != null;
8055
7529
  setReviewId(found ? sectionId : null);
8056
- setReviewButtonsHidden(e.data.hideButtons === true);
8057
7530
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
8058
7531
  if (found) {
8059
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7532
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
8060
7533
  }
8061
7534
  }
8062
7535
  };
@@ -8075,7 +7548,7 @@ function AiSectionOverlay({
8075
7548
  return;
8076
7549
  }
8077
7550
  const sec = t.closest("[data-ohw-section]");
8078
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7551
+ setHoveredId(sec?.dataset.ohwSection ?? null);
8079
7552
  };
8080
7553
  const onLeave = () => setHoveredId(null);
8081
7554
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -8107,30 +7580,9 @@ function AiSectionOverlay({
8107
7580
  },
8108
7581
  [postToParent2]
8109
7582
  );
8110
- const activeSelectionId = reviewId ? null : selectedId;
8111
- const selectionRect = useLiveSectionRect(activeSelectionId);
7583
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
8112
7584
  const reviewRect = useLiveSectionRect(reviewId);
8113
7585
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
8114
- (0, import_react8.useEffect)(() => {
8115
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
8116
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
8117
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
8118
- return;
8119
- }
8120
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
8121
- postToParent2({
8122
- type: "ow:section-rect",
8123
- instanceId: activeSelectionId,
8124
- rect: {
8125
- top: selectionRect.top + window.scrollY,
8126
- left: selectionRect.left + window.scrollX,
8127
- width: selectionRect.width,
8128
- height: selectionRect.height
8129
- },
8130
- isFirst,
8131
- isLast
8132
- });
8133
- }, [activeSelectionId, selectionRect, postToParent2]);
8134
7586
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8135
7587
  hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8136
7588
  "div",
@@ -8181,16 +7633,13 @@ function AiSectionOverlay({
8181
7633
  border: `2px solid ${PRIMARY2}`,
8182
7634
  borderRadius: edgeAwareRadius(reviewRect),
8183
7635
  zIndex: 2147483200,
8184
- // The veil itself: swallows clicks so the section stays locked until decided. This
8185
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8186
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8187
- // Accept/Discard resolves to the media beneath and opens the file picker.
7636
+ // The veil itself: swallows clicks so the section stays locked until decided.
8188
7637
  background: "rgba(8, 133, 254, 0.04)",
8189
7638
  pointerEvents: "auto",
8190
7639
  cursor: "default"
8191
7640
  },
8192
7641
  onClick: (e) => e.stopPropagation(),
8193
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7642
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8194
7643
  "div",
8195
7644
  {
8196
7645
  style: {
@@ -8215,59 +7664,6 @@ function AiSectionOverlay({
8215
7664
 
8216
7665
  // src/lib/section-instances.ts
8217
7666
  var SECTION_ORDER_KEY = "__ohw_section_order";
8218
- function topLevelSections() {
8219
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8220
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8221
- );
8222
- }
8223
- function instanceIdOf(el) {
8224
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8225
- }
8226
- function planSectionMove(instanceId, targetIndex, currentPath) {
8227
- const sections = topLevelSections();
8228
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8229
- if (index === -1) return null;
8230
- const dragged = sections[index];
8231
- const others = sections.filter((_, i) => i !== index);
8232
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8233
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8234
- return reordered.map((el, order) => ({
8235
- instanceId: instanceIdOf(el),
8236
- type: el.getAttribute("data-ohw-section") ?? "",
8237
- order,
8238
- pagePath: currentPath
8239
- }));
8240
- }
8241
- function moveSectionInstance(instanceId, direction, currentPath) {
8242
- const sections = topLevelSections();
8243
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8244
- if (index === -1) return null;
8245
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8246
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8247
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8248
- if (!entries) return null;
8249
- applyPersistedOrder(entries);
8250
- return entries;
8251
- }
8252
- function applyPersistedOrder(entries) {
8253
- if (entries.length === 0) return;
8254
- const sections = topLevelSections();
8255
- if (sections.length === 0) return;
8256
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8257
- const ordered = [...sections].sort((a, b) => {
8258
- const aOrder = orderIndex.get(instanceIdOf(a));
8259
- const bOrder = orderIndex.get(instanceIdOf(b));
8260
- if (aOrder === void 0 && bOrder === void 0) return 0;
8261
- if (aOrder === void 0) return 1;
8262
- if (bOrder === void 0) return -1;
8263
- return aOrder - bOrder;
8264
- });
8265
- let prev = null;
8266
- for (const el of ordered) {
8267
- if (prev) prev.after(el);
8268
- prev = el;
8269
- }
8270
- }
8271
7667
  function getPageSectionOrderEntries(raw, currentPath) {
8272
7668
  if (!raw) return [];
8273
7669
  try {
@@ -8305,7 +7701,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8305
7701
  rekeySectionSubtree(clone, entry.instanceId);
8306
7702
  original.insertAdjacentElement("afterend", clone);
8307
7703
  }
8308
- applyPersistedOrder(entries);
8309
7704
  }
8310
7705
 
8311
7706
  // src/OhhwellsBridge.tsx
@@ -10852,13 +10247,8 @@ function referenceBox(slot) {
10852
10247
  const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find(
10853
10248
  (el) => el !== slot && !el.hasAttribute("data-ohw-social-icon-placeholder")
10854
10249
  ) : null;
10855
- if (neighbour) {
10856
- const box2 = neighbour.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect();
10857
- if (box2?.width && box2.height) return box2;
10858
- }
10859
- const own = slot.getBoundingClientRect();
10860
- if (own.width && own.height) return own;
10861
- const box = slot.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect() ?? null;
10250
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
10251
+ const box = source?.getBoundingClientRect() ?? null;
10862
10252
  return box?.width && box.height ? box : null;
10863
10253
  }
10864
10254
  function iconMarkupSizedFor(slot, markup) {
@@ -11013,6 +10403,10 @@ function markSocialsRows(root = document) {
11013
10403
  item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
11014
10404
  }
11015
10405
  const iconKey = socialIconKey(item) ?? socialHrefKey(item)?.replace(/-href$/, "");
10406
+ if (iconKey && !item.querySelector(ICON_SELECTOR)) {
10407
+ const drawn = item.querySelector("svg, img");
10408
+ if (drawn) adoptAsIconSlot(drawn, iconKey);
10409
+ }
11016
10410
  if (iconKey) ensureLabelSlot(item, iconKey);
11017
10411
  });
11018
10412
  });
@@ -11444,12 +10838,30 @@ function socialsMissingIcons(row) {
11444
10838
  label: (socialLabelElement(item)?.textContent ?? item.getAttribute("aria-label") ?? "").trim()
11445
10839
  })).filter((entry) => Boolean(entry.hrefKey));
11446
10840
  }
10841
+ function adoptAsIconSlot(drawn, base) {
10842
+ const parent = drawn.parentElement;
10843
+ if (!parent) return null;
10844
+ const taken = drawn.ownerDocument.querySelector(`[data-ohw-key="${base}"]`);
10845
+ const iconKey = taken ? `${base}-icon` : base;
10846
+ const slot = drawn.ownerDocument.createElement("span");
10847
+ slot.setAttribute("data-ohw-key", iconKey);
10848
+ slot.setAttribute("data-ohw-editable", "icon");
10849
+ slot.style.display = "inline-flex";
10850
+ parent.insertBefore(slot, drawn);
10851
+ slot.appendChild(drawn);
10852
+ return iconKey;
10853
+ }
11447
10854
  function ensureIconSlot(item) {
11448
10855
  const existing = item.querySelector(ICON_SELECTOR);
11449
10856
  if (existing) return existing.dataset.ohwKey ?? null;
11450
10857
  const hrefKey = socialHrefKey(item);
11451
10858
  if (!hrefKey) return null;
11452
10859
  const base = hrefKey.replace(/-href$/, "");
10860
+ const drawn = item.querySelector("svg, img");
10861
+ if (drawn) {
10862
+ const adopted = adoptAsIconSlot(drawn, base);
10863
+ if (adopted) return adopted;
10864
+ }
11453
10865
  const taken = document.querySelector(`[data-ohw-key="${base}"]`);
11454
10866
  const iconKey = taken && taken !== item ? `${base}-icon` : base;
11455
10867
  const slot = document.createElement("span");
@@ -12637,7 +12049,6 @@ function readLogoSizeState(content, placement) {
12637
12049
  function getLogoElement(el) {
12638
12050
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12639
12051
  if (marked) return marked;
12640
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12641
12052
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12642
12053
  if (!root) return null;
12643
12054
  const anchor = el.closest("a");
@@ -13511,415 +12922,88 @@ function useNavItemDrag({
13511
12922
  };
13512
12923
  }
13513
12924
 
13514
- // src/useSectionDrag.ts
13515
- var import_react15 = require("react");
12925
+ // src/ui/footer-container-chrome.tsx
12926
+ var import_lucide_react15 = require("lucide-react");
12927
+ var import_jsx_runtime29 = require("react/jsx-runtime");
12928
+ function FooterContainerChrome({
12929
+ rect,
12930
+ onAdd,
12931
+ addDisabled = false
12932
+ }) {
12933
+ const chromeGap = 6;
12934
+ const buttonMargin = 7;
12935
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12936
+ "div",
12937
+ {
12938
+ "data-ohw-footer-container-chrome": "",
12939
+ "data-ohw-bridge": "",
12940
+ className: "pointer-events-none fixed z-[2147483647]",
12941
+ style: {
12942
+ top: rect.top - chromeGap,
12943
+ left: rect.left - chromeGap,
12944
+ width: rect.width + chromeGap * 2,
12945
+ height: rect.height + chromeGap * 2
12946
+ },
12947
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12948
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12949
+ "button",
12950
+ {
12951
+ type: "button",
12952
+ "data-ohw-footer-add-button": "",
12953
+ disabled: addDisabled,
12954
+ 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",
12955
+ style: { top: chromeGap - buttonMargin },
12956
+ "aria-label": "Add item",
12957
+ onMouseDown: (e) => {
12958
+ e.preventDefault();
12959
+ e.stopPropagation();
12960
+ },
12961
+ onClick: (e) => {
12962
+ e.preventDefault();
12963
+ e.stopPropagation();
12964
+ if (addDisabled) return;
12965
+ onAdd();
12966
+ },
12967
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12968
+ }
12969
+ ) }),
12970
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12971
+ ] })
12972
+ }
12973
+ ) });
12974
+ }
13516
12975
 
13517
- // src/lib/section-dnd.ts
13518
- function isFooterSection(el) {
13519
- return el.dataset.ohwSection === "footer";
12976
+ // src/lib/carousel.ts
12977
+ var import_react15 = require("react");
12978
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12979
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12980
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12981
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12982
+ function listCarouselKeys() {
12983
+ const keys = /* @__PURE__ */ new Set();
12984
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12985
+ const key = el.getAttribute("data-ohw-key");
12986
+ if (key) keys.add(key);
12987
+ });
12988
+ return [...keys];
13520
12989
  }
13521
- function buildSectionDropSlots(draggedInstanceId) {
13522
- const sections = topLevelSections().filter(
13523
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12990
+ function containersForKey(key) {
12991
+ return Array.from(
12992
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13524
12993
  );
13525
- const slots = [];
13526
- if (sections.length === 0) return slots;
13527
- const left = 0;
13528
- const width = document.documentElement.clientWidth;
13529
- for (let i = 0; i <= sections.length; i++) {
13530
- let y;
13531
- if (i === 0) {
13532
- y = sections[0].getBoundingClientRect().top;
13533
- } else if (i === sections.length) {
13534
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13535
- } else {
13536
- const prev = sections[i - 1].getBoundingClientRect();
13537
- const next = sections[i].getBoundingClientRect();
13538
- y = (prev.bottom + next.top) / 2;
13539
- }
13540
- slots.push({ insertIndex: i, y, left, width });
13541
- }
13542
- return slots;
13543
12994
  }
13544
- function hitTestSectionDropSlot(y, slots) {
13545
- let best = null;
13546
- for (const slot of slots) {
13547
- const dist = Math.abs(y - slot.y);
13548
- if (!best || dist < best.dist) best = { slot, dist };
13549
- }
13550
- return best?.slot ?? null;
12995
+ function isCarouselKey(key) {
12996
+ return containersForKey(key).length > 0;
13551
12997
  }
13552
-
13553
- // src/useSectionDrag.ts
13554
- var PRESS_THRESHOLD = 10;
13555
- var EDGE_ZONE = 60;
13556
- var MAX_AUTO_SCROLL_SPEED = 18;
13557
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13558
- "[data-ohw-toolbar]",
13559
- "[data-ohw-edit-chrome]",
13560
- "[data-ohw-item-interaction]",
13561
- "[data-ohw-drag-handle-container]",
13562
- '[data-slot="drag-handle"]',
13563
- "[data-ohw-item-toolbar-anchor]",
13564
- "[data-ohw-item-drag-surface]",
13565
- "[data-ohw-more-menu]",
13566
- '[data-slot="dropdown-menu-content"]',
13567
- '[data-slot="dropdown-menu-item"]',
13568
- "[data-ohw-state-toggle]",
13569
- "[data-ohw-max-badge]",
13570
- "[data-ohw-floating-panel]",
13571
- "[data-ohw-section-picker]",
13572
- "[data-ohw-link-popover-root]",
13573
- "[data-ohw-link-modal-root]",
13574
- "[data-ohw-link-page-dropdown]",
13575
- '[data-slot="popover-content"]',
13576
- '[data-slot="dialog-content"]',
13577
- '[data-slot="dialog-overlay"]',
13578
- "[data-ohw-ai-review]",
13579
- "[data-ohw-editable]",
13580
- "[data-ohw-editable-state]",
13581
- "[contenteditable]",
13582
- "[data-ohw-href-key]",
13583
- "[data-ohw-footer-col]",
13584
- "[data-ohw-social-label]",
13585
- "a",
13586
- "button",
13587
- '[role="button"]',
13588
- '[data-ohw-role="navbar-button"]',
13589
- '[data-ohw-role="button"]',
13590
- "[data-ohw-carousel]",
13591
- "[data-ohw-carousel-value]",
13592
- "[data-ohw-carousel-slide]",
13593
- "[data-ohw-carousel-overlay]",
13594
- "[data-ohw-media-chrome]",
13595
- "[data-ohw-media-overlay]",
13596
- "[data-ohw-media-skeleton]"
13597
- ].join(", ");
13598
- function visibleClip(ps) {
13599
- if (!ps) return null;
13600
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13601
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13602
- return { top, bottom: Math.max(top, bottom) };
13603
- }
13604
- function useSectionDrag({
13605
- isEditMode,
13606
- editContentRef,
13607
- postToParentRef,
13608
- parentScrollRef,
13609
- navDragRef,
13610
- footerDragRef,
13611
- suppressNextClickRef,
13612
- suppressClickUntilRef
13613
- }) {
13614
- const sectionDragRef = (0, import_react15.useRef)(null);
13615
- const [sectionDropSlots, setSectionDropSlots] = (0, import_react15.useState)([]);
13616
- const [activeSectionDropIndex, setActiveSectionDropIndex] = (0, import_react15.useState)(null);
13617
- const [isSectionDragging, setIsSectionDragging] = (0, import_react15.useState)(false);
13618
- const sectionPointerDragRef = (0, import_react15.useRef)(null);
13619
- const autoScrollRafRef = (0, import_react15.useRef)(null);
13620
- const autoScrollDeltaRef = (0, import_react15.useRef)(0);
13621
- const stopAutoScroll = (0, import_react15.useCallback)(() => {
13622
- if (autoScrollRafRef.current != null) {
13623
- cancelAnimationFrame(autoScrollRafRef.current);
13624
- autoScrollRafRef.current = null;
13625
- }
13626
- autoScrollDeltaRef.current = 0;
13627
- }, []);
13628
- const tickAutoScroll = (0, import_react15.useCallback)(() => {
13629
- if (!sectionDragRef.current) {
13630
- stopAutoScroll();
13631
- return;
13632
- }
13633
- if (autoScrollDeltaRef.current !== 0) {
13634
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13635
- }
13636
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13637
- }, [postToParentRef, stopAutoScroll]);
13638
- const updateAutoScroll = (0, import_react15.useCallback)(
13639
- (clientY) => {
13640
- const clip = visibleClip(parentScrollRef.current);
13641
- let delta = 0;
13642
- if (clip) {
13643
- const distTop = clientY - clip.top;
13644
- const distBottom = clip.bottom - clientY;
13645
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13646
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13647
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13648
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13649
- }
13650
- }
13651
- autoScrollDeltaRef.current = delta;
13652
- if (delta !== 0 && autoScrollRafRef.current == null) {
13653
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13654
- } else if (delta === 0) {
13655
- stopAutoScroll();
13656
- }
13657
- },
13658
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13659
- );
13660
- const clearSectionDragVisuals = (0, import_react15.useCallback)(() => {
13661
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13662
- sectionDragRef.current = null;
13663
- setSectionDropSlots([]);
13664
- setActiveSectionDropIndex(null);
13665
- setIsSectionDragging(false);
13666
- stopAutoScroll();
13667
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13668
- unlockItemDragInteraction();
13669
- }, [stopAutoScroll]);
13670
- const refreshSectionDragVisuals = (0, import_react15.useCallback)(
13671
- (session, clientX, clientY) => {
13672
- session.lastClientX = clientX;
13673
- session.lastClientY = clientY;
13674
- const slots = buildSectionDropSlots(session.instanceId);
13675
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13676
- session.activeSlot = activeSlot;
13677
- setSectionDropSlots(slots);
13678
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13679
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13680
- updateAutoScroll(clientY);
13681
- },
13682
- [updateAutoScroll]
13683
- );
13684
- const beginSectionDrag = (0, import_react15.useCallback)(
13685
- (session) => {
13686
- sectionDragRef.current = session;
13687
- setIsSectionDragging(true);
13688
- lockItemDuringDrag();
13689
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13690
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13691
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13692
- },
13693
- [refreshSectionDragVisuals]
13694
- );
13695
- const commitSectionDrag = (0, import_react15.useCallback)(() => {
13696
- const session = sectionDragRef.current;
13697
- if (!session) {
13698
- clearSectionDragVisuals();
13699
- return;
13700
- }
13701
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13702
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13703
- if (!entries) {
13704
- clearSectionDragVisuals();
13705
- return;
13706
- }
13707
- const orderJson = JSON.stringify(entries);
13708
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13709
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13710
- applyPersistedOrder(entries);
13711
- clearSectionDragVisuals();
13712
- requestAnimationFrame(() => {
13713
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13714
- applyPersistedOrder(entries);
13715
- }
13716
- requestAnimationFrame(() => {
13717
- window.dispatchEvent(new Event("resize"));
13718
- });
13719
- });
13720
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13721
- const startSectionPressDrag = (0, import_react15.useCallback)(
13722
- (el, clientX, clientY, pointerId) => {
13723
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13724
- const instanceId = instanceIdOf(el);
13725
- if (!instanceId) return false;
13726
- sectionPointerDragRef.current = {
13727
- el,
13728
- instanceId,
13729
- startX: clientX,
13730
- startY: clientY,
13731
- pointerId,
13732
- started: false
13733
- };
13734
- return true;
13735
- },
13736
- [footerDragRef, navDragRef]
13737
- );
13738
- (0, import_react15.useEffect)(() => {
13739
- if (!isEditMode) return;
13740
- const onPointerDown = (e) => {
13741
- if (e.button !== 0) return;
13742
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13743
- if (sectionPointerDragRef.current) return;
13744
- const target = e.target;
13745
- if (!(target instanceof HTMLElement)) return;
13746
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13747
- const sectionEl = target.closest("[data-ohw-section]");
13748
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13749
- if (!topLevelSections().includes(sectionEl)) return;
13750
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13751
- };
13752
- const onPointerMove = (e) => {
13753
- const pending = sectionPointerDragRef.current;
13754
- if (!pending) return;
13755
- if (pending.started) {
13756
- e.preventDefault();
13757
- clearTextSelection();
13758
- const session = sectionDragRef.current;
13759
- if (!session) return;
13760
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13761
- return;
13762
- }
13763
- const dx = e.clientX - pending.startX;
13764
- const dy = e.clientY - pending.startY;
13765
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13766
- e.preventDefault();
13767
- pending.started = true;
13768
- armItemPressDrag();
13769
- clearTextSelection();
13770
- try {
13771
- document.body.setPointerCapture(pending.pointerId);
13772
- } catch {
13773
- }
13774
- beginSectionDrag({
13775
- instanceId: pending.instanceId,
13776
- draggedEl: pending.el,
13777
- lastClientX: e.clientX,
13778
- lastClientY: e.clientY,
13779
- activeSlot: null
13780
- });
13781
- };
13782
- const endPointerDrag = (e) => {
13783
- const pending = sectionPointerDragRef.current;
13784
- sectionPointerDragRef.current = null;
13785
- try {
13786
- if (document.body.hasPointerCapture(e.pointerId)) {
13787
- document.body.releasePointerCapture(e.pointerId);
13788
- }
13789
- } catch {
13790
- }
13791
- if (!pending) return;
13792
- if (!pending.started) {
13793
- unlockItemDragInteraction();
13794
- return;
13795
- }
13796
- suppressNextClickRef.current = true;
13797
- suppressClickUntilRef.current = Date.now() + 500;
13798
- commitSectionDrag();
13799
- };
13800
- const onKeyDown = (e) => {
13801
- if (e.key !== "Escape") return;
13802
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13803
- sectionPointerDragRef.current = null;
13804
- clearSectionDragVisuals();
13805
- };
13806
- document.addEventListener("pointerdown", onPointerDown, true);
13807
- document.addEventListener("pointermove", onPointerMove, true);
13808
- document.addEventListener("pointerup", endPointerDrag, true);
13809
- document.addEventListener("pointercancel", endPointerDrag, true);
13810
- document.addEventListener("keydown", onKeyDown, true);
13811
- return () => {
13812
- document.removeEventListener("pointerdown", onPointerDown, true);
13813
- document.removeEventListener("pointermove", onPointerMove, true);
13814
- document.removeEventListener("pointerup", endPointerDrag, true);
13815
- document.removeEventListener("pointercancel", endPointerDrag, true);
13816
- document.removeEventListener("keydown", onKeyDown, true);
13817
- unlockItemDragInteraction();
13818
- stopAutoScroll();
13819
- };
13820
- }, [
13821
- beginSectionDrag,
13822
- clearSectionDragVisuals,
13823
- commitSectionDrag,
13824
- footerDragRef,
13825
- isEditMode,
13826
- navDragRef,
13827
- refreshSectionDragVisuals,
13828
- startSectionPressDrag,
13829
- stopAutoScroll,
13830
- suppressClickUntilRef,
13831
- suppressNextClickRef
13832
- ]);
13833
- return {
13834
- sectionDragRef,
13835
- sectionDropSlots,
13836
- activeSectionDropIndex,
13837
- isSectionDragging
13838
- };
13839
- }
13840
-
13841
- // src/ui/footer-container-chrome.tsx
13842
- var import_lucide_react15 = require("lucide-react");
13843
- var import_jsx_runtime29 = require("react/jsx-runtime");
13844
- function FooterContainerChrome({
13845
- rect,
13846
- onAdd,
13847
- addDisabled = false
13848
- }) {
13849
- const chromeGap = 6;
13850
- const buttonMargin = 7;
13851
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13852
- "div",
13853
- {
13854
- "data-ohw-footer-container-chrome": "",
13855
- "data-ohw-bridge": "",
13856
- className: "pointer-events-none fixed z-[2147483647]",
13857
- style: {
13858
- top: rect.top - chromeGap,
13859
- left: rect.left - chromeGap,
13860
- width: rect.width + chromeGap * 2,
13861
- height: rect.height + chromeGap * 2
13862
- },
13863
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
13864
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13865
- "button",
13866
- {
13867
- type: "button",
13868
- "data-ohw-footer-add-button": "",
13869
- disabled: addDisabled,
13870
- 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",
13871
- style: { top: chromeGap - buttonMargin },
13872
- "aria-label": "Add item",
13873
- onMouseDown: (e) => {
13874
- e.preventDefault();
13875
- e.stopPropagation();
13876
- },
13877
- onClick: (e) => {
13878
- e.preventDefault();
13879
- e.stopPropagation();
13880
- if (addDisabled) return;
13881
- onAdd();
13882
- },
13883
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13884
- }
13885
- ) }),
13886
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13887
- ] })
13888
- }
13889
- ) });
13890
- }
13891
-
13892
- // src/lib/carousel.ts
13893
- var import_react16 = require("react");
13894
- var CAROUSEL_ATTR = "data-ohw-carousel";
13895
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13896
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13897
- var CAROUSEL_EVENT = "ohw:carousel-change";
13898
- function listCarouselKeys() {
13899
- const keys = /* @__PURE__ */ new Set();
13900
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13901
- const key = el.getAttribute("data-ohw-key");
13902
- if (key) keys.add(key);
13903
- });
13904
- return [...keys];
13905
- }
13906
- function containersForKey(key) {
13907
- return Array.from(
13908
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13909
- );
13910
- }
13911
- function isCarouselKey(key) {
13912
- return containersForKey(key).length > 0;
13913
- }
13914
- function parseSlides(raw) {
13915
- if (!raw) return [];
13916
- try {
13917
- const parsed = JSON.parse(raw);
13918
- if (!Array.isArray(parsed)) return [];
13919
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13920
- } catch {
13921
- return [];
13922
- }
12998
+ function parseSlides(raw) {
12999
+ if (!raw) return [];
13000
+ try {
13001
+ const parsed = JSON.parse(raw);
13002
+ if (!Array.isArray(parsed)) return [];
13003
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13004
+ } catch {
13005
+ return [];
13006
+ }
13923
13007
  }
13924
13008
  function readCarouselValue(key) {
13925
13009
  const container = containersForKey(key)[0];
@@ -13952,8 +13036,8 @@ function applyCarouselNode(key, val) {
13952
13036
  return true;
13953
13037
  }
13954
13038
  function useOhwCarousel(key, initial) {
13955
- const [images, setImages] = (0, import_react16.useState)(initial);
13956
- (0, import_react16.useEffect)(() => {
13039
+ const [images, setImages] = (0, import_react15.useState)(initial);
13040
+ (0, import_react15.useEffect)(() => {
13957
13041
  const el = document.querySelector(
13958
13042
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13959
13043
  );
@@ -14035,7 +13119,6 @@ function collectEditableNodes(extraContent, root = document) {
14035
13119
  NAV_ORDER_KEY,
14036
13120
  FOOTER_ORDER_KEY,
14037
13121
  NAV_COUNT_KEY,
14038
- SECTION_ORDER_KEY,
14039
13122
  // A socials row's order and its icons-vs-words setting live under keys no element carries,
14040
13123
  // so collecting the DOM alone left them behind: the draft knew the row was showing icons and
14041
13124
  // had gained an item, and the published page went back to the template's own (OHH-736).
@@ -14083,18 +13166,6 @@ function collectEditableNodes(extraContent, root = document) {
14083
13166
  }
14084
13167
  if (extraContent && !isScoped) {
14085
13168
  applyNavFooterDeleteOverrides(byKey, extraContent);
14086
- for (const key of LOGO_IMAGE_KEYS) {
14087
- if (!(key in extraContent)) continue;
14088
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
14089
- }
14090
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
14091
- if (!(key in extraContent)) continue;
14092
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
14093
- }
14094
- for (const key of LOGO_SIZE_KEYS) {
14095
- if (!(key in extraContent)) continue;
14096
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
14097
- }
14098
13169
  }
14099
13170
  return Array.from(byKey.values());
14100
13171
  }
@@ -14499,7 +13570,6 @@ function fadeInImageElement(img, onReady) {
14499
13570
  function applyEditableImageSrc(img, url) {
14500
13571
  img.removeAttribute("srcset");
14501
13572
  img.removeAttribute("sizes");
14502
- if (img.loading === "lazy") img.loading = "eager";
14503
13573
  img.src = url;
14504
13574
  }
14505
13575
  function fadeInBgImage(el, url, onReady) {
@@ -14564,10 +13634,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14564
13634
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14565
13635
  };
14566
13636
  }
14567
- function resolveEntryAnchor(entry) {
14568
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14569
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14570
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13637
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13638
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13639
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13640
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13641
+ return { effectiveInsertAfter, insertBefore };
13642
+ }
13643
+ function getSchedulingMountPoint(insertAfter) {
13644
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13645
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13646
+ if (!anchorEl && anchor === "scheduling") {
13647
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13648
+ anchorEl = widgets.at(-1) ?? null;
13649
+ }
13650
+ if (!anchorEl) return null;
13651
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14571
13652
  }
14572
13653
  function schedulingMountDepth(insertAfter) {
14573
13654
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14584,7 +13665,8 @@ function getPageSchedulingEntries(raw) {
14584
13665
  }
14585
13666
  }
14586
13667
  function isSchedulingWidgetMissing(entry) {
14587
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13668
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13669
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14588
13670
  }
14589
13671
  function hasMissingSchedulingWidgets(entries) {
14590
13672
  return entries.some(isSchedulingWidgetMissing);
@@ -14614,17 +13696,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14614
13696
  } catch {
14615
13697
  }
14616
13698
  }
14617
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14618
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14619
- const sectionId = schedulingSectionId(widgetId);
13699
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13700
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13701
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14620
13702
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14621
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14622
- if (!anchorEl) return false;
14623
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13703
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13704
+ if (!mountPoint) return false;
14624
13705
  const container = document.createElement("div");
14625
13706
  container.dataset.ohwSectionContainer = "scheduling";
14626
- if (beforeId) {
14627
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13707
+ if (insertBefore) {
13708
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14628
13709
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14629
13710
  if (!beforePoint) return false;
14630
13711
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14635,25 +13716,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14635
13716
  }
14636
13717
  tail.insertAdjacentElement("afterend", container);
14637
13718
  }
14638
- try {
14639
- const root = (0, import_client2.createRoot)(container);
14640
- (0, import_react_dom3.flushSync)(() => {
14641
- root.render(
14642
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14643
- SchedulingWidget,
14644
- {
14645
- notifyOnConnect,
14646
- initialScheduleId: scheduleId,
14647
- insertAfter: widgetId
14648
- }
14649
- )
14650
- );
14651
- });
14652
- } catch (err) {
14653
- console.error("[ow:scheduling] render threw", err);
14654
- container.remove();
14655
- return false;
14656
- }
13719
+ const root = (0, import_client2.createRoot)(container);
13720
+ (0, import_react_dom3.flushSync)(() => {
13721
+ root.render(
13722
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13723
+ SchedulingWidget,
13724
+ {
13725
+ notifyOnConnect,
13726
+ initialScheduleId: scheduleId,
13727
+ insertAfter: effectiveInsertAfter
13728
+ }
13729
+ )
13730
+ );
13731
+ });
14657
13732
  const tracker = getSectionsTracker();
14658
13733
  let sections = [];
14659
13734
  try {
@@ -14661,12 +13736,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14661
13736
  } catch {
14662
13737
  }
14663
13738
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14664
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13739
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14665
13740
  sections.push({
14666
13741
  type: "scheduling",
14667
- insertAfter: widgetId,
14668
- anchorId,
14669
- beforeId: beforeId ?? null,
13742
+ insertAfter: effectiveInsertAfter,
14670
13743
  pagePath: window.location.pathname,
14671
13744
  ...scheduleId ? { scheduleId } : {}
14672
13745
  });
@@ -14680,8 +13753,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14680
13753
  for (let i = pending.length - 1; i >= 0; i--) {
14681
13754
  const entry = pending[i];
14682
13755
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14683
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14684
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13756
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14685
13757
  pending.splice(i, 1);
14686
13758
  }
14687
13759
  }
@@ -14827,11 +13899,6 @@ function applyLinkByKey(key, val) {
14827
13899
  hrefAnchors.forEach((el) => applyLinkHref(el, val));
14828
13900
  }
14829
13901
  }
14830
- function isInsideLinkEditor(target) {
14831
- return Boolean(
14832
- 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"]')
14833
- );
14834
- }
14835
13902
  function isInsideFloatingPanel(target) {
14836
13903
  return Boolean(target.closest("[data-ohw-floating-panel]"));
14837
13904
  }
@@ -14839,6 +13906,11 @@ function isPointOverFloatingPanel(clientX, clientY) {
14839
13906
  const el = document.elementFromPoint(clientX, clientY);
14840
13907
  return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14841
13908
  }
13909
+ function isInsideLinkEditor(target) {
13910
+ return Boolean(
13911
+ 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"]')
13912
+ );
13913
+ }
14842
13914
  function getHrefKeyFromElement(el) {
14843
13915
  if (!el) return null;
14844
13916
  const anchor = el.closest("[data-ohw-href-key]");
@@ -15097,7 +14169,7 @@ function getNavigationSelectionParent(el) {
15097
14169
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
15098
14170
  return getFooterLinksContainer();
15099
14171
  }
15100
- 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)) {
14172
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
15101
14173
  return getNavigationRoot(el);
15102
14174
  }
15103
14175
  return null;
@@ -15566,9 +14638,9 @@ function FloatingToolbar({
15566
14638
  showEditLink,
15567
14639
  onEditLink
15568
14640
  }) {
15569
- const localRef = import_react17.default.useRef(null);
15570
- const [measuredW, setMeasuredW] = import_react17.default.useState(330);
15571
- const setRefs = import_react17.default.useCallback(
14641
+ const localRef = import_react16.default.useRef(null);
14642
+ const [measuredW, setMeasuredW] = import_react16.default.useState(330);
14643
+ const setRefs = import_react16.default.useCallback(
15572
14644
  (node) => {
15573
14645
  localRef.current = node;
15574
14646
  if (typeof elRef === "function") elRef(node);
@@ -15580,7 +14652,7 @@ function FloatingToolbar({
15580
14652
  },
15581
14653
  [elRef]
15582
14654
  );
15583
- import_react17.default.useLayoutEffect(() => {
14655
+ import_react16.default.useLayoutEffect(() => {
15584
14656
  const node = localRef.current;
15585
14657
  if (!node) return;
15586
14658
  const update = () => {
@@ -15606,7 +14678,7 @@ function FloatingToolbar({
15606
14678
  pointerEvents: "auto"
15607
14679
  },
15608
14680
  children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
15609
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react17.default.Fragment, { children: [
14681
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
15610
14682
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
15611
14683
  btns.map((btn) => {
15612
14684
  const isActive = activeCommands.has(btn.cmd);
@@ -15690,45 +14762,6 @@ function StateToggle({
15690
14762
  );
15691
14763
  }
15692
14764
  var contentCache = /* @__PURE__ */ new Map();
15693
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15694
- var OHW_LOADER_STYLE = {
15695
- position: "fixed",
15696
- inset: 0,
15697
- background: "#fff",
15698
- zIndex: 2147483646,
15699
- display: "flex",
15700
- alignItems: "center",
15701
- justifyContent: "center"
15702
- };
15703
- function OhwLoaderSpinner() {
15704
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15705
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15706
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15707
- "circle",
15708
- {
15709
- cx: "14",
15710
- cy: "14",
15711
- r: "11",
15712
- stroke: "#1C1917",
15713
- strokeWidth: "3",
15714
- strokeDasharray: "17 52",
15715
- strokeLinecap: "round",
15716
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15717
- "animateTransform",
15718
- {
15719
- attributeName: "transform",
15720
- type: "rotate",
15721
- from: "0 14 14",
15722
- to: "360 14 14",
15723
- dur: "0.7s",
15724
- repeatCount: "indefinite"
15725
- }
15726
- )
15727
- }
15728
- )
15729
- ] });
15730
- }
15731
- 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){}})();`;
15732
14765
  function resolveSubdomain(subdomainFromQuery) {
15733
14766
  if (subdomainFromQuery) return subdomainFromQuery;
15734
14767
  if (typeof window !== "undefined") {
@@ -15751,8 +14784,8 @@ function OhhwellsBridge() {
15751
14784
  const router = (0, import_navigation3.useRouter)();
15752
14785
  const searchParams = (0, import_navigation3.useSearchParams)();
15753
14786
  const isEditMode = isEditSessionActive();
15754
- const [bridgeRoot, setBridgeRoot] = (0, import_react17.useState)(null);
15755
- (0, import_react17.useEffect)(() => {
14787
+ const [bridgeRoot, setBridgeRoot] = (0, import_react16.useState)(null);
14788
+ (0, import_react16.useEffect)(() => {
15756
14789
  const figtreeFontId = "ohw-figtree-font";
15757
14790
  if (!document.getElementById(figtreeFontId)) {
15758
14791
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15781,151 +14814,87 @@ function OhhwellsBridge() {
15781
14814
  const subdomain = resolveSubdomain(subdomainFromQuery);
15782
14815
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15783
14816
  useSavedLinkNavigation(isEditMode);
15784
- const postToParent2 = (0, import_react17.useCallback)((data) => {
14817
+ const postToParent2 = (0, import_react16.useCallback)((data) => {
15785
14818
  if (typeof window !== "undefined" && window.parent !== window) {
15786
14819
  window.parent.postMessage(data, "*");
15787
14820
  }
15788
14821
  }, []);
15789
- const [fetchState, setFetchState] = (0, import_react17.useState)("idle");
15790
- const autoSaveTimers = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
15791
- const activeElRef = (0, import_react17.useRef)(null);
15792
- const pointerHeldRef = (0, import_react17.useRef)(false);
15793
- const selectedElRef = (0, import_react17.useRef)(null);
15794
- const selectedHrefKeyRef = (0, import_react17.useRef)(null);
15795
- const selectedFooterColAttrRef = (0, import_react17.useRef)(null);
15796
- const originalContentRef = (0, import_react17.useRef)(null);
15797
- const activeStateElRef = (0, import_react17.useRef)(null);
15798
- const parentScrollRef = (0, import_react17.useRef)(null);
15799
- const visibleViewportRef = (0, import_react17.useRef)(null);
15800
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react17.useState)(null);
15801
- const attachVisibleViewport = (0, import_react17.useCallback)((node) => {
14822
+ const [fetchState, setFetchState] = (0, import_react16.useState)("idle");
14823
+ const autoSaveTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
14824
+ const activeElRef = (0, import_react16.useRef)(null);
14825
+ const pointerHeldRef = (0, import_react16.useRef)(false);
14826
+ const selectedElRef = (0, import_react16.useRef)(null);
14827
+ const selectedHrefKeyRef = (0, import_react16.useRef)(null);
14828
+ const selectedFooterColAttrRef = (0, import_react16.useRef)(null);
14829
+ const originalContentRef = (0, import_react16.useRef)(null);
14830
+ const activeStateElRef = (0, import_react16.useRef)(null);
14831
+ const parentScrollRef = (0, import_react16.useRef)(null);
14832
+ const visibleViewportRef = (0, import_react16.useRef)(null);
14833
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react16.useState)(null);
14834
+ const attachVisibleViewport = (0, import_react16.useCallback)((node) => {
15802
14835
  visibleViewportRef.current = node;
15803
14836
  setDialogPortalContainer(node);
15804
14837
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15805
14838
  }, []);
15806
- const toolbarElRef = (0, import_react17.useRef)(null);
15807
- const glowElRef = (0, import_react17.useRef)(null);
15808
- const hoveredImageRef = (0, import_react17.useRef)(null);
15809
- const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
15810
- const dragOverElRef = (0, import_react17.useRef)(null);
15811
- const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
15812
- const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
15813
- const selectedMediaElRef = (0, import_react17.useRef)(null);
15814
- const clearMediaSelection = (0, import_react17.useCallback)(() => {
15815
- const prev = selectedMediaElRef.current;
15816
- selectedMediaElRef.current = null;
15817
- setSelectedMedia(null);
15818
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15819
- if (sectionEl) {
15820
- postToParentRef.current({
15821
- type: "ow:section-selected",
15822
- sectionId: sectionEl.dataset.ohwSection ?? null,
15823
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15824
- key: null
15825
- });
15826
- }
15827
- }, []);
15828
- const clearMediaSelectionRef = (0, import_react17.useRef)(clearMediaSelection);
15829
- clearMediaSelectionRef.current = clearMediaSelection;
15830
- const selectMediaElement = (0, import_react17.useCallback)((el) => {
15831
- const r2 = el.getBoundingClientRect();
15832
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15833
- selectedMediaElRef.current = el;
15834
- setSelectedMedia({
15835
- key: el.dataset.ohwKey ?? "",
15836
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15837
- elementType: el.dataset.ohwEditable ?? "image",
15838
- hasTextOverlap: false,
15839
- isDragOver: false,
15840
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15841
- });
15842
- const sectionEl = el.closest("[data-ohw-section]");
15843
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15844
- postToParentRef.current({
15845
- type: "ow:section-selected",
15846
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15847
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15848
- key: el.dataset.ohwKey ?? null,
15849
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15850
- // bridge knows what the node IS, so it names it.
15851
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : el.dataset.ohwEditable === "bg-image" ? "Background" : "Image"
15852
- });
15853
- }, []);
15854
- const selectMediaElementRef = (0, import_react17.useRef)(selectMediaElement);
15855
- selectMediaElementRef.current = selectMediaElement;
15856
- (0, import_react17.useEffect)(() => {
15857
- if (!selectedMedia) return;
15858
- const update = () => {
15859
- const el = selectedMediaElRef.current;
15860
- if (!el || !el.isConnected) {
15861
- clearMediaSelection();
15862
- return;
15863
- }
15864
- const r2 = el.getBoundingClientRect();
15865
- setSelectedMedia(
15866
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15867
- );
15868
- };
15869
- window.addEventListener("scroll", update, true);
15870
- window.addEventListener("resize", update);
15871
- return () => {
15872
- window.removeEventListener("scroll", update, true);
15873
- window.removeEventListener("resize", update);
15874
- };
15875
- }, [selectedMedia !== null]);
15876
- const [carouselHover, setCarouselHover] = (0, import_react17.useState)(null);
15877
- const [uploadingRects, setUploadingRects] = (0, import_react17.useState)({});
15878
- const hoveredGapRef = (0, import_react17.useRef)(null);
15879
- const imageUnhoverTimerRef = (0, import_react17.useRef)(null);
15880
- const imageShowTimerRef = (0, import_react17.useRef)(null);
15881
- const editStylesRef = (0, import_react17.useRef)(null);
15882
- const activateRef = (0, import_react17.useRef)(() => {
15883
- });
15884
- const deactivateRef = (0, import_react17.useRef)(() => {
15885
- });
15886
- const selectRef = (0, import_react17.useRef)(() => {
15887
- });
15888
- const selectFrameRef = (0, import_react17.useRef)(() => {
15889
- });
15890
- const selectLogoRef = (0, import_react17.useRef)(() => {
15891
- });
15892
- const openLogoSizePanelRef = (0, import_react17.useRef)(() => {
15893
- });
15894
- const deselectRef = (0, import_react17.useRef)(() => {
15895
- });
15896
- const closeFloatingPanelOnlyRef = (0, import_react17.useRef)(() => {
15897
- });
15898
- const reselectNavigationItemRef = (0, import_react17.useRef)(() => {
15899
- });
15900
- const commitNavigationTextEditRef = (0, import_react17.useRef)(() => {
15901
- });
15902
- const handleDeleteSelectedRef = (0, import_react17.useRef)(() => false);
15903
- const runPendingDeleteUndoRef = (0, import_react17.useRef)(() => false);
15904
- const isFooterFrameSelectionRef = (0, import_react17.useRef)(false);
15905
- const refreshActiveCommandsRef = (0, import_react17.useRef)(() => {
15906
- });
15907
- const postToParentRef = (0, import_react17.useRef)(postToParent2);
15908
- postToParentRef.current = postToParent2;
15909
- const aiSectionApiRef = (0, import_react17.useRef)(null);
15910
- const sectionsLoadedRef = (0, import_react17.useRef)(false);
15911
- const pendingScheduleConfigRequests = (0, import_react17.useRef)([]);
15912
- const [toolbarRect, setToolbarRect] = (0, import_react17.useState)(null);
15913
- const [formPickRect, setFormPickRect] = (0, import_react17.useState)(null);
15914
- const formPickElRef = (0, import_react17.useRef)(null);
15915
- const [formViewState, setFormViewStateUi] = (0, import_react17.useState)("default");
15916
- const [formPickCount, setFormPickCount] = (0, import_react17.useState)(null);
15917
- const [formHoverRect, setFormHoverRect] = (0, import_react17.useState)(null);
15918
- const formHoverElRef = (0, import_react17.useRef)(null);
15919
- const [fieldPickRect, setFieldPickRect] = (0, import_react17.useState)(null);
15920
- const fieldPickElRef = (0, import_react17.useRef)(null);
15921
- const [fieldPickState, setFieldPickState] = (0, import_react17.useState)(null);
15922
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react17.useState)(false);
15923
- const clearFormPick = (0, import_react17.useCallback)(() => {
15924
- const form = formPickElRef.current;
15925
- const editing = fieldPickElRef.current;
15926
- if (commitPlaceholderEdit(editing) && editing) {
15927
- const owner = editing.closest('[data-ohw-editable="form"]');
15928
- if (owner) persistFieldsRef.current(owner);
14839
+ const toolbarElRef = (0, import_react16.useRef)(null);
14840
+ const glowElRef = (0, import_react16.useRef)(null);
14841
+ const hoveredImageRef = (0, import_react16.useRef)(null);
14842
+ const hoveredImageHasTextOverlapRef = (0, import_react16.useRef)(false);
14843
+ const dragOverElRef = (0, import_react16.useRef)(null);
14844
+ const [mediaHover, setMediaHover] = (0, import_react16.useState)(null);
14845
+ const [carouselHover, setCarouselHover] = (0, import_react16.useState)(null);
14846
+ const [uploadingRects, setUploadingRects] = (0, import_react16.useState)({});
14847
+ const hoveredGapRef = (0, import_react16.useRef)(null);
14848
+ const imageUnhoverTimerRef = (0, import_react16.useRef)(null);
14849
+ const imageShowTimerRef = (0, import_react16.useRef)(null);
14850
+ const editStylesRef = (0, import_react16.useRef)(null);
14851
+ const activateRef = (0, import_react16.useRef)(() => {
14852
+ });
14853
+ const deactivateRef = (0, import_react16.useRef)(() => {
14854
+ });
14855
+ const selectRef = (0, import_react16.useRef)(() => {
14856
+ });
14857
+ const selectFrameRef = (0, import_react16.useRef)(() => {
14858
+ });
14859
+ const selectLogoRef = (0, import_react16.useRef)(() => {
14860
+ });
14861
+ const openLogoSizePanelRef = (0, import_react16.useRef)(() => {
14862
+ });
14863
+ const deselectRef = (0, import_react16.useRef)(() => {
14864
+ });
14865
+ const closeFloatingPanelOnlyRef = (0, import_react16.useRef)(() => {
14866
+ });
14867
+ const reselectNavigationItemRef = (0, import_react16.useRef)(() => {
14868
+ });
14869
+ const commitNavigationTextEditRef = (0, import_react16.useRef)(() => {
14870
+ });
14871
+ const handleDeleteSelectedRef = (0, import_react16.useRef)(() => false);
14872
+ const runPendingDeleteUndoRef = (0, import_react16.useRef)(() => false);
14873
+ const isFooterFrameSelectionRef = (0, import_react16.useRef)(false);
14874
+ const refreshActiveCommandsRef = (0, import_react16.useRef)(() => {
14875
+ });
14876
+ const postToParentRef = (0, import_react16.useRef)(postToParent2);
14877
+ postToParentRef.current = postToParent2;
14878
+ const aiSectionApiRef = (0, import_react16.useRef)(null);
14879
+ const sectionsLoadedRef = (0, import_react16.useRef)(false);
14880
+ const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14881
+ const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
14882
+ const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
14883
+ const formPickElRef = (0, import_react16.useRef)(null);
14884
+ const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
14885
+ const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
14886
+ const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
14887
+ const formHoverElRef = (0, import_react16.useRef)(null);
14888
+ const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
14889
+ const fieldPickElRef = (0, import_react16.useRef)(null);
14890
+ const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
14891
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
14892
+ const clearFormPick = (0, import_react16.useCallback)(() => {
14893
+ const form = formPickElRef.current;
14894
+ const editing = fieldPickElRef.current;
14895
+ if (commitPlaceholderEdit(editing) && editing) {
14896
+ const owner = editing.closest('[data-ohw-editable="form"]');
14897
+ if (owner) persistFieldsRef.current(owner);
15929
14898
  }
15930
14899
  if (form) {
15931
14900
  const key = formKeyOf(form);
@@ -15940,7 +14909,7 @@ function OhhwellsBridge() {
15940
14909
  formPickElRef.current = null;
15941
14910
  setFormPickRect(null);
15942
14911
  }, []);
15943
- const clearFieldPick = (0, import_react17.useCallback)(() => {
14912
+ const clearFieldPick = (0, import_react16.useCallback)(() => {
15944
14913
  const wrapper = fieldPickElRef.current;
15945
14914
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15946
14915
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15950,9 +14919,9 @@ function OhhwellsBridge() {
15950
14919
  setFieldPickRect(null);
15951
14920
  setFieldPickState(null);
15952
14921
  }, []);
15953
- const persistFieldsRef = (0, import_react17.useRef)(() => {
14922
+ const persistFieldsRef = (0, import_react16.useRef)(() => {
15954
14923
  });
15955
- const persistFields = (0, import_react17.useCallback)(
14924
+ const persistFields = (0, import_react16.useCallback)(
15956
14925
  (form) => {
15957
14926
  const key = formKeyOf(form);
15958
14927
  if (!key) return;
@@ -15963,7 +14932,7 @@ function OhhwellsBridge() {
15963
14932
  []
15964
14933
  );
15965
14934
  persistFieldsRef.current = persistFields;
15966
- const selectField = (0, import_react17.useCallback)((wrapper) => {
14935
+ const selectField = (0, import_react16.useCallback)((wrapper) => {
15967
14936
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15968
14937
  commitPlaceholderEdit(fieldPickElRef.current);
15969
14938
  }
@@ -15976,7 +14945,7 @@ function OhhwellsBridge() {
15976
14945
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15977
14946
  setFieldTypePickerOpen(false);
15978
14947
  }, []);
15979
- const withSelectedField = (0, import_react17.useCallback)(
14948
+ const withSelectedField = (0, import_react16.useCallback)(
15980
14949
  (run) => {
15981
14950
  const wrapper = fieldPickElRef.current;
15982
14951
  const form = formPickElRef.current;
@@ -15989,28 +14958,28 @@ function OhhwellsBridge() {
15989
14958
  },
15990
14959
  [persistFields]
15991
14960
  );
15992
- const handleFieldTypeChange = (0, import_react17.useCallback)(
14961
+ const handleFieldTypeChange = (0, import_react16.useCallback)(
15993
14962
  (type) => withSelectedField((_form, wrapper) => {
15994
14963
  applyFieldType(wrapper, type);
15995
14964
  selectField(wrapper);
15996
14965
  }),
15997
14966
  [selectField, withSelectedField]
15998
14967
  );
15999
- const handleFieldRequiredToggle = (0, import_react17.useCallback)(
14968
+ const handleFieldRequiredToggle = (0, import_react16.useCallback)(
16000
14969
  () => withSelectedField((_form, wrapper) => {
16001
14970
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
16002
14971
  selectField(wrapper);
16003
14972
  }),
16004
14973
  [selectField, withSelectedField]
16005
14974
  );
16006
- const handleFieldDuplicate = (0, import_react17.useCallback)(
14975
+ const handleFieldDuplicate = (0, import_react16.useCallback)(
16007
14976
  () => withSelectedField((form, wrapper) => {
16008
14977
  const copy = duplicateField(form, wrapper);
16009
14978
  selectField(copy);
16010
14979
  }),
16011
14980
  [selectField, withSelectedField]
16012
14981
  );
16013
- const handleFieldDelete = (0, import_react17.useCallback)(
14982
+ const handleFieldDelete = (0, import_react16.useCallback)(
16014
14983
  () => withSelectedField((_form, wrapper) => {
16015
14984
  removeField(wrapper);
16016
14985
  clearFieldPick();
@@ -16018,7 +14987,7 @@ function OhhwellsBridge() {
16018
14987
  }),
16019
14988
  [clearFieldPick, withSelectedField]
16020
14989
  );
16021
- const handleAddField = (0, import_react17.useCallback)(
14990
+ const handleAddField = (0, import_react16.useCallback)(
16022
14991
  (type) => {
16023
14992
  const form = formPickElRef.current;
16024
14993
  if (!form) return;
@@ -16034,8 +15003,8 @@ function OhhwellsBridge() {
16034
15003
  },
16035
15004
  [persistFields, selectField]
16036
15005
  );
16037
- const fieldDragRef = (0, import_react17.useRef)(null);
16038
- const buildFieldDropSlots = (0, import_react17.useCallback)((form, draggedKey) => {
15006
+ const fieldDragRef = (0, import_react16.useRef)(null);
15007
+ const buildFieldDropSlots = (0, import_react16.useCallback)((form, draggedKey) => {
16039
15008
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
16040
15009
  const slots = others.map((el) => {
16041
15010
  const rect = el.getBoundingClientRect();
@@ -16048,7 +15017,7 @@ function OhhwellsBridge() {
16048
15017
  }
16049
15018
  return slots;
16050
15019
  }, []);
16051
- const handleFieldDragStart = (0, import_react17.useCallback)(() => {
15020
+ const handleFieldDragStart = (0, import_react16.useCallback)(() => {
16052
15021
  const wrapper = fieldPickElRef.current;
16053
15022
  const form = formPickElRef.current;
16054
15023
  if (!wrapper || !form) return;
@@ -16057,18 +15026,18 @@ function OhhwellsBridge() {
16057
15026
  setFieldDragging(true);
16058
15027
  setFieldDropSlots(buildFieldDropSlots(form, key));
16059
15028
  }, [buildFieldDropSlots]);
16060
- const handleFieldDragEnd = (0, import_react17.useCallback)(() => {
15029
+ const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
16061
15030
  fieldDragRef.current = null;
16062
15031
  setFieldDropIndex(null);
16063
15032
  setFieldDropSlots([]);
16064
15033
  setFieldDragging(false);
16065
15034
  }, []);
16066
- const [fieldDropIndex, setFieldDropIndex] = (0, import_react17.useState)(null);
16067
- const [fieldDropSlots, setFieldDropSlots] = (0, import_react17.useState)([]);
16068
- const [fieldDragging, setFieldDragging] = (0, import_react17.useState)(false);
16069
- const clearFormPickRef = (0, import_react17.useRef)(clearFormPick);
15035
+ const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
15036
+ const [fieldDropSlots, setFieldDropSlots] = (0, import_react16.useState)([]);
15037
+ const [fieldDragging, setFieldDragging] = (0, import_react16.useState)(false);
15038
+ const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
16070
15039
  clearFormPickRef.current = clearFormPick;
16071
- (0, import_react17.useEffect)(() => {
15040
+ (0, import_react16.useEffect)(() => {
16072
15041
  const el = fieldPickElRef.current;
16073
15042
  if (!el || fieldPickRect === null) return;
16074
15043
  const observer = new ResizeObserver(() => {
@@ -16077,7 +15046,7 @@ function OhhwellsBridge() {
16077
15046
  observer.observe(el);
16078
15047
  return () => observer.disconnect();
16079
15048
  }, [fieldPickRect !== null, fieldPickState]);
16080
- (0, import_react17.useEffect)(() => {
15049
+ (0, import_react16.useEffect)(() => {
16081
15050
  const el = formPickElRef.current;
16082
15051
  if (!el || formPickRect === null) return;
16083
15052
  const observer = new ResizeObserver(() => {
@@ -16086,25 +15055,25 @@ function OhhwellsBridge() {
16086
15055
  observer.observe(el);
16087
15056
  return () => observer.disconnect();
16088
15057
  }, [formPickRect !== null, formViewState]);
16089
- const [toolbarVariant, setToolbarVariant] = (0, import_react17.useState)("none");
16090
- const toolbarVariantRef = (0, import_react17.useRef)("none");
15058
+ const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
15059
+ const toolbarVariantRef = (0, import_react16.useRef)("none");
16091
15060
  toolbarVariantRef.current = toolbarVariant;
16092
- const [selectedIsCta, setSelectedIsCta] = (0, import_react17.useState)(false);
16093
- const [selectedIsSocial, setSelectedIsSocial] = (0, import_react17.useState)(false);
16094
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react17.useState)(false);
16095
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react17.useState)(null);
16096
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react17.useState)(false);
16097
- const [toggleState, setToggleState] = (0, import_react17.useState)(null);
16098
- const [maxBadge, setMaxBadge] = (0, import_react17.useState)(null);
16099
- const [activeCommands, setActiveCommands] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
16100
- const [sectionGap, setSectionGap] = (0, import_react17.useState)(null);
16101
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react17.useState)(false);
16102
- const hoveredNavContainerRef = (0, import_react17.useRef)(null);
16103
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react17.useState)(null);
16104
- const hoveredItemElRef = (0, import_react17.useRef)(null);
16105
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react17.useState)(null);
16106
- const [hoveredTextRect, setHoveredTextRect] = (0, import_react17.useState)(null);
16107
- (0, import_react17.useEffect)(() => {
15061
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react16.useState)(false);
15062
+ const [selectedIsSocial, setSelectedIsSocial] = (0, import_react16.useState)(false);
15063
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react16.useState)(false);
15064
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react16.useState)(null);
15065
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react16.useState)(false);
15066
+ const [toggleState, setToggleState] = (0, import_react16.useState)(null);
15067
+ const [maxBadge, setMaxBadge] = (0, import_react16.useState)(null);
15068
+ const [activeCommands, setActiveCommands] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
15069
+ const [sectionGap, setSectionGap] = (0, import_react16.useState)(null);
15070
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react16.useState)(false);
15071
+ const hoveredNavContainerRef = (0, import_react16.useRef)(null);
15072
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
15073
+ const hoveredItemElRef = (0, import_react16.useRef)(null);
15074
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
15075
+ const [hoveredTextRect, setHoveredTextRect] = (0, import_react16.useState)(null);
15076
+ (0, import_react16.useEffect)(() => {
16108
15077
  const sync = () => {
16109
15078
  const el = document.querySelector(
16110
15079
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -16125,56 +15094,43 @@ function OhhwellsBridge() {
16125
15094
  });
16126
15095
  return () => observer.disconnect();
16127
15096
  }, []);
16128
- const siblingHintElRef = (0, import_react17.useRef)(null);
16129
- const [siblingHintRect, setSiblingHintRect] = (0, import_react17.useState)(null);
16130
- const [siblingHintRects, setSiblingHintRects] = (0, import_react17.useState)([]);
16131
- const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
16132
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
15097
+ const siblingHintElRef = (0, import_react16.useRef)(null);
15098
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
15099
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
15100
+ const [isItemDragging, setIsItemDragging] = (0, import_react16.useState)(false);
15101
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react16.useState)(false);
16133
15102
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
16134
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
16135
- const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
16136
- const footerDragRef = (0, import_react17.useRef)(null);
16137
- const [footerDropSlots, setFooterDropSlots] = (0, import_react17.useState)([]);
16138
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react17.useState)(null);
16139
- const [draggedItemRect, setDraggedItemRect] = (0, import_react17.useState)(null);
16140
- const footerPointerDragRef = (0, import_react17.useRef)(null);
16141
- const suppressNextClickRef = (0, import_react17.useRef)(false);
16142
- const suppressClickUntilRef = (0, import_react17.useRef)(0);
16143
- const [linkPopover, setLinkPopover] = (0, import_react17.useState)(null);
16144
- const linkPopoverSessionRef = (0, import_react17.useRef)(null);
16145
- const addNavAfterAnchorRef = (0, import_react17.useRef)(null);
16146
- const editContentRef = (0, import_react17.useRef)({});
16147
- const aiSectionsRef = (0, import_react17.useRef)("");
16148
- const brandKitRef = (0, import_react17.useRef)("");
16149
- const stylesRef = (0, import_react17.useRef)("");
16150
- const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
16151
- const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
16152
- const floatingPanelOpenRef = (0, import_react17.useRef)(false);
16153
- const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
16154
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
16155
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
16156
- const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
16157
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
16158
- const [sitePages, setSitePages] = (0, import_react17.useState)([]);
16159
- const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
16160
- const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
16161
- const setLinkPopoverRef = (0, import_react17.useRef)(setLinkPopover);
16162
- const linkPopoverPanelRef = (0, import_react17.useRef)(null);
16163
- const linkPopoverOpenRef = (0, import_react17.useRef)(false);
16164
- const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
15103
+ const [floatingPanel, setFloatingPanel] = (0, import_react16.useState)(null);
15104
+ const floatingPanelOpenRef = (0, import_react16.useRef)(false);
15105
+ floatingPanelOpenRef.current = floatingPanel !== null;
15106
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react16.useState)(null);
15107
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react16.useState)(null);
15108
+ const [editorViewport, setEditorViewport] = (0, import_react16.useState)("desktop");
15109
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react16.useState)(null);
15110
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react16.useState)(null);
15111
+ const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react16.useState)(null);
15112
+ const footerDragRef = (0, import_react16.useRef)(null);
15113
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react16.useState)([]);
15114
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react16.useState)(null);
15115
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react16.useState)(null);
15116
+ const footerPointerDragRef = (0, import_react16.useRef)(null);
15117
+ const suppressNextClickRef = (0, import_react16.useRef)(false);
15118
+ const suppressClickUntilRef = (0, import_react16.useRef)(0);
15119
+ const [linkPopover, setLinkPopover] = (0, import_react16.useState)(null);
15120
+ const linkPopoverSessionRef = (0, import_react16.useRef)(null);
15121
+ const addNavAfterAnchorRef = (0, import_react16.useRef)(null);
15122
+ const editContentRef = (0, import_react16.useRef)({});
15123
+ const aiSectionsRef = (0, import_react16.useRef)("");
15124
+ const pendingDeleteUndoRef = (0, import_react16.useRef)(null);
15125
+ const [sitePages, setSitePages] = (0, import_react16.useState)([]);
15126
+ const [sectionsByPath, setSectionsByPath] = (0, import_react16.useState)({});
15127
+ const sectionsPrefetchGenRef = (0, import_react16.useRef)(0);
15128
+ const setLinkPopoverRef = (0, import_react16.useRef)(setLinkPopover);
15129
+ const linkPopoverPanelRef = (0, import_react16.useRef)(null);
15130
+ const linkPopoverOpenRef = (0, import_react16.useRef)(false);
15131
+ const linkPopoverGraceUntilRef = (0, import_react16.useRef)(0);
16165
15132
  setLinkPopoverRef.current = setLinkPopover;
16166
- setFloatingPanelRef.current = setFloatingPanel;
16167
15133
  linkPopoverSessionRef.current = linkPopover;
16168
- floatingPanelOpenRef.current = Boolean(floatingPanel);
16169
- (0, import_react17.useEffect)(() => {
16170
- const syncViewport = () => {
16171
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
16172
- setEditorViewport((prev) => prev === next ? prev : next);
16173
- };
16174
- syncViewport();
16175
- window.addEventListener("resize", syncViewport);
16176
- return () => window.removeEventListener("resize", syncViewport);
16177
- }, []);
16178
15134
  const {
16179
15135
  navDragRef,
16180
15136
  navDropSlots,
@@ -16207,20 +15163,10 @@ function OhhwellsBridge() {
16207
15163
  getNavigationItemAnchor,
16208
15164
  isDragHandleDisabled
16209
15165
  });
16210
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
16211
- isEditMode,
16212
- editContentRef,
16213
- postToParentRef,
16214
- parentScrollRef,
16215
- navDragRef,
16216
- footerDragRef,
16217
- suppressNextClickRef,
16218
- suppressClickUntilRef
16219
- });
16220
15166
  const bumpLinkPopoverGrace = () => {
16221
15167
  linkPopoverGraceUntilRef.current = Date.now() + 350;
16222
15168
  };
16223
- const runSectionsPrefetch = (0, import_react17.useCallback)((pages) => {
15169
+ const runSectionsPrefetch = (0, import_react16.useCallback)((pages) => {
16224
15170
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
16225
15171
  const gen = ++sectionsPrefetchGenRef.current;
16226
15172
  const paths = pages.map((p) => p.path);
@@ -16239,9 +15185,9 @@ function OhhwellsBridge() {
16239
15185
  );
16240
15186
  });
16241
15187
  }, [isEditMode, pathname]);
16242
- const runSectionsPrefetchRef = (0, import_react17.useRef)(runSectionsPrefetch);
15188
+ const runSectionsPrefetchRef = (0, import_react16.useRef)(runSectionsPrefetch);
16243
15189
  runSectionsPrefetchRef.current = runSectionsPrefetch;
16244
- (0, import_react17.useEffect)(() => {
15190
+ (0, import_react16.useEffect)(() => {
16245
15191
  if (!linkPopover) {
16246
15192
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
16247
15193
  return;
@@ -16269,7 +15215,7 @@ function OhhwellsBridge() {
16269
15215
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
16270
15216
  };
16271
15217
  }, [linkPopover, postToParent2]);
16272
- (0, import_react17.useEffect)(() => {
15218
+ (0, import_react16.useEffect)(() => {
16273
15219
  if (!isEditMode) return;
16274
15220
  const useFixtures = shouldUseDevFixtures();
16275
15221
  if (useFixtures) {
@@ -16293,14 +15239,14 @@ function OhhwellsBridge() {
16293
15239
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
16294
15240
  return () => window.removeEventListener("message", onSitePages);
16295
15241
  }, [isEditMode, postToParent2]);
16296
- (0, import_react17.useEffect)(() => {
15242
+ (0, import_react16.useEffect)(() => {
16297
15243
  if (!isEditMode || shouldUseDevFixtures()) return;
16298
15244
  void loadAllSectionsManifest().then((manifest) => {
16299
15245
  if (Object.keys(manifest).length === 0) return;
16300
15246
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
16301
15247
  });
16302
15248
  }, [isEditMode]);
16303
- (0, import_react17.useEffect)(() => {
15249
+ (0, import_react16.useEffect)(() => {
16304
15250
  const update = () => {
16305
15251
  const el = activeElRef.current ?? selectedElRef.current;
16306
15252
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -16324,10 +15270,10 @@ function OhhwellsBridge() {
16324
15270
  vvp.removeEventListener("resize", update);
16325
15271
  };
16326
15272
  }, []);
16327
- const refreshStateRules = (0, import_react17.useCallback)(() => {
15273
+ const refreshStateRules = (0, import_react16.useCallback)(() => {
16328
15274
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
16329
15275
  }, []);
16330
- const processConfigRequest = (0, import_react17.useCallback)((insertAfterVal) => {
15276
+ const processConfigRequest = (0, import_react16.useCallback)((insertAfterVal) => {
16331
15277
  const tracker = getSectionsTracker();
16332
15278
  let entries = [];
16333
15279
  try {
@@ -16350,7 +15296,7 @@ function OhhwellsBridge() {
16350
15296
  }
16351
15297
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
16352
15298
  }, [isEditMode]);
16353
- const deactivate = (0, import_react17.useCallback)(() => {
15299
+ const deactivate = (0, import_react16.useCallback)(() => {
16354
15300
  const el = activeElRef.current;
16355
15301
  if (!el) return;
16356
15302
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16391,12 +15337,12 @@ function OhhwellsBridge() {
16391
15337
  setToolbarShowEditLink(false);
16392
15338
  postToParent2({ type: "ow:exit-edit" });
16393
15339
  }, [postToParent2]);
16394
- const clearSelectedAttr = (0, import_react17.useCallback)(() => {
15340
+ const clearSelectedAttr = (0, import_react16.useCallback)(() => {
16395
15341
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16396
15342
  el.removeAttribute("data-ohw-selected");
16397
15343
  });
16398
15344
  }, []);
16399
- const deselect = (0, import_react17.useCallback)(() => {
15345
+ const deselect = (0, import_react16.useCallback)(() => {
16400
15346
  clearSelectedAttr();
16401
15347
  selectedElRef.current = null;
16402
15348
  selectedHrefKeyRef.current = null;
@@ -16425,12 +15371,12 @@ function OhhwellsBridge() {
16425
15371
  setToolbarVariant("none");
16426
15372
  }
16427
15373
  }, [clearSelectedAttr]);
16428
- const markSelected = (0, import_react17.useCallback)((el) => {
15374
+ const markSelected = (0, import_react16.useCallback)((el) => {
16429
15375
  clearSelectedAttr();
16430
15376
  el.removeAttribute("data-ohw-hovered");
16431
15377
  el.setAttribute("data-ohw-selected", "");
16432
15378
  }, [clearSelectedAttr]);
16433
- const resolveHrefKeyElement = (0, import_react17.useCallback)((hrefKey) => {
15379
+ const resolveHrefKeyElement = (0, import_react16.useCallback)((hrefKey) => {
16434
15380
  if (isFooterHrefKey(hrefKey)) {
16435
15381
  return document.querySelector(
16436
15382
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16445,7 +15391,7 @@ function OhhwellsBridge() {
16445
15391
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16446
15392
  );
16447
15393
  }, []);
16448
- const resyncSelectedNavigationItem = (0, import_react17.useCallback)(() => {
15394
+ const resyncSelectedNavigationItem = (0, import_react16.useCallback)(() => {
16449
15395
  const hrefKey = selectedHrefKeyRef.current;
16450
15396
  if (hrefKey) {
16451
15397
  const link = resolveHrefKeyElement(hrefKey);
@@ -16483,7 +15429,7 @@ function OhhwellsBridge() {
16483
15429
  );
16484
15430
  }
16485
15431
  }, [resolveHrefKeyElement]);
16486
- const reselectNavigationItem = (0, import_react17.useCallback)((navAnchor) => {
15432
+ const reselectNavigationItem = (0, import_react16.useCallback)((navAnchor) => {
16487
15433
  selectedElRef.current = navAnchor;
16488
15434
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16489
15435
  selectedFooterColAttrRef.current = null;
@@ -16514,7 +15460,7 @@ function OhhwellsBridge() {
16514
15460
  setToolbarShowEditLink(false);
16515
15461
  setActiveCommands(/* @__PURE__ */ new Set());
16516
15462
  }, [markSelected]);
16517
- const commitNavigationTextEdit = (0, import_react17.useCallback)((navAnchor) => {
15463
+ const commitNavigationTextEdit = (0, import_react16.useCallback)((navAnchor) => {
16518
15464
  const el = activeElRef.current;
16519
15465
  if (!el) return;
16520
15466
  const key = el.dataset.ohwKey;
@@ -16547,7 +15493,7 @@ function OhhwellsBridge() {
16547
15493
  postToParent2({ type: "ow:exit-edit" });
16548
15494
  reselectNavigationItem(navAnchor);
16549
15495
  }, [postToParent2, reselectNavigationItem]);
16550
- const handleAddTopLevelNavItem = (0, import_react17.useCallback)(() => {
15496
+ const handleAddTopLevelNavItem = (0, import_react16.useCallback)(() => {
16551
15497
  const items = listNavbarRootItems();
16552
15498
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16553
15499
  deselectRef.current();
@@ -16559,7 +15505,7 @@ function OhhwellsBridge() {
16559
15505
  intent: "add-nav"
16560
15506
  });
16561
15507
  }, []);
16562
- const maybeWarnNavLinkDropdownConflict = (0, import_react17.useCallback)(
15508
+ const maybeWarnNavLinkDropdownConflict = (0, import_react16.useCallback)(
16563
15509
  (anchor) => {
16564
15510
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16565
15511
  if (!navDropdownsOpenOnClick()) return;
@@ -16572,7 +15518,7 @@ function OhhwellsBridge() {
16572
15518
  },
16573
15519
  [postToParent2]
16574
15520
  );
16575
- const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
15521
+ const handleNavDropdownOpenChange = (0, import_react16.useCallback)((open) => {
16576
15522
  const selected = selectedElRef.current;
16577
15523
  if (!selected || !isNavigationItem2(selected)) return;
16578
15524
  setNavGroupForceOpen(selected, open);
@@ -16584,7 +15530,7 @@ function OhhwellsBridge() {
16584
15530
  }
16585
15531
  });
16586
15532
  }, []);
16587
- const handleFooterHeadingVisibleChange = (0, import_react17.useCallback)(
15533
+ const handleFooterHeadingVisibleChange = (0, import_react16.useCallback)(
16588
15534
  (visible) => {
16589
15535
  const selected = selectedElRef.current;
16590
15536
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16608,7 +15554,7 @@ function OhhwellsBridge() {
16608
15554
  },
16609
15555
  [postToParent2]
16610
15556
  );
16611
- const enterEditOnNewItem = (0, import_react17.useCallback)((anchor) => {
15557
+ const enterEditOnNewItem = (0, import_react16.useCallback)((anchor) => {
16612
15558
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16613
15559
  if (!label) {
16614
15560
  selectRef.current(anchor);
@@ -16617,8 +15563,8 @@ function OhhwellsBridge() {
16617
15563
  setNavGroupForceOpen(anchor, true);
16618
15564
  activateRef.current(label);
16619
15565
  }, []);
16620
- const pendingSocialAddRef = (0, import_react17.useRef)(null);
16621
- const handleAddChildItem = (0, import_react17.useCallback)(() => {
15566
+ const pendingSocialAddRef = (0, import_react16.useRef)(null);
15567
+ const handleAddChildItem = (0, import_react16.useCallback)(() => {
16622
15568
  const selected = selectedElRef.current;
16623
15569
  if (!selected) return;
16624
15570
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16727,7 +15673,7 @@ function OhhwellsBridge() {
16727
15673
  enterEditOnNewItem(result.anchor);
16728
15674
  });
16729
15675
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16730
- const handleAddFooterColumn = (0, import_react17.useCallback)(() => {
15676
+ const handleAddFooterColumn = (0, import_react16.useCallback)(() => {
16731
15677
  if (!canAddFooterColumn()) {
16732
15678
  postToParent2({
16733
15679
  type: "ow:toast",
@@ -16748,7 +15694,7 @@ function OhhwellsBridge() {
16748
15694
  selectRef.current(result.firstLink);
16749
15695
  });
16750
15696
  }, [postToParent2]);
16751
- const clearFooterDragVisuals = (0, import_react17.useCallback)(() => {
15697
+ const clearFooterDragVisuals = (0, import_react16.useCallback)(() => {
16752
15698
  footerDragRef.current = null;
16753
15699
  setSiblingHintRects([]);
16754
15700
  setFooterDropSlots([]);
@@ -16757,7 +15703,7 @@ function OhhwellsBridge() {
16757
15703
  setIsItemDragging(false);
16758
15704
  unlockFooterDragInteraction();
16759
15705
  }, []);
16760
- const refreshFooterDragVisuals = (0, import_react17.useCallback)((session, activeSlot, clientX, clientY) => {
15706
+ const refreshFooterDragVisuals = (0, import_react16.useCallback)((session, activeSlot, clientX, clientY) => {
16761
15707
  const dragged = session.draggedEl;
16762
15708
  setDraggedItemRect(dragged.getBoundingClientRect());
16763
15709
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16789,13 +15735,13 @@ function OhhwellsBridge() {
16789
15735
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16790
15736
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16791
15737
  }, []);
16792
- const refreshFooterDragVisualsRef = (0, import_react17.useRef)(refreshFooterDragVisuals);
15738
+ const refreshFooterDragVisualsRef = (0, import_react16.useRef)(refreshFooterDragVisuals);
16793
15739
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16794
- const commitFooterDragRef = (0, import_react17.useRef)(() => {
15740
+ const commitFooterDragRef = (0, import_react16.useRef)(() => {
16795
15741
  });
16796
- const beginFooterDragRef = (0, import_react17.useRef)(() => {
15742
+ const beginFooterDragRef = (0, import_react16.useRef)(() => {
16797
15743
  });
16798
- const beginFooterDrag = (0, import_react17.useCallback)(
15744
+ const beginFooterDrag = (0, import_react16.useCallback)(
16799
15745
  (session) => {
16800
15746
  const rect = session.draggedEl.getBoundingClientRect();
16801
15747
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16815,7 +15761,7 @@ function OhhwellsBridge() {
16815
15761
  [refreshFooterDragVisuals]
16816
15762
  );
16817
15763
  beginFooterDragRef.current = beginFooterDrag;
16818
- const commitFooterDrag = (0, import_react17.useCallback)(
15764
+ const commitFooterDrag = (0, import_react16.useCallback)(
16819
15765
  (clientX, clientY) => {
16820
15766
  const session = footerDragRef.current;
16821
15767
  if (!session) {
@@ -16944,7 +15890,7 @@ function OhhwellsBridge() {
16944
15890
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16945
15891
  );
16946
15892
  commitFooterDragRef.current = commitFooterDrag;
16947
- const startFooterLinkDrag = (0, import_react17.useCallback)(
15893
+ const startFooterLinkDrag = (0, import_react16.useCallback)(
16948
15894
  (anchor, clientX, clientY, wasSelected) => {
16949
15895
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16950
15896
  if (!hrefKey) return false;
@@ -16980,7 +15926,7 @@ function OhhwellsBridge() {
16980
15926
  },
16981
15927
  [beginFooterDrag]
16982
15928
  );
16983
- const startFooterColumnDrag = (0, import_react17.useCallback)(
15929
+ const startFooterColumnDrag = (0, import_react16.useCallback)(
16984
15930
  (columnEl, clientX, clientY, wasSelected) => {
16985
15931
  const columns = listFooterColumns();
16986
15932
  const idx = columns.indexOf(columnEl);
@@ -17000,7 +15946,7 @@ function OhhwellsBridge() {
17000
15946
  },
17001
15947
  [beginFooterDrag]
17002
15948
  );
17003
- const handleItemDragStart = (0, import_react17.useCallback)(
15949
+ const handleItemDragStart = (0, import_react16.useCallback)(
17004
15950
  (e) => {
17005
15951
  const selected = selectedElRef.current;
17006
15952
  if (!selected) {
@@ -17020,7 +15966,7 @@ function OhhwellsBridge() {
17020
15966
  },
17021
15967
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
17022
15968
  );
17023
- const handleItemDragEnd = (0, import_react17.useCallback)(
15969
+ const handleItemDragEnd = (0, import_react16.useCallback)(
17024
15970
  (e) => {
17025
15971
  if (footerDragRef.current) {
17026
15972
  const x = e?.clientX;
@@ -17046,7 +15992,7 @@ function OhhwellsBridge() {
17046
15992
  },
17047
15993
  [commitFooterDrag, commitNavDrag, navDragRef]
17048
15994
  );
17049
- const handleItemChromePointerDown = (0, import_react17.useCallback)((e) => {
15995
+ const handleItemChromePointerDown = (0, import_react16.useCallback)((e) => {
17050
15996
  if (e.button !== 0) return;
17051
15997
  const selected = selectedElRef.current;
17052
15998
  if (!selected) return;
@@ -17077,7 +16023,7 @@ function OhhwellsBridge() {
17077
16023
  }
17078
16024
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
17079
16025
  }, [armNavPressFromChrome]);
17080
- const handleItemChromeClick = (0, import_react17.useCallback)((clientX, clientY) => {
16026
+ const handleItemChromeClick = (0, import_react16.useCallback)((clientX, clientY) => {
17081
16027
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
17082
16028
  suppressNextClickRef.current = false;
17083
16029
  return;
@@ -17090,7 +16036,7 @@ function OhhwellsBridge() {
17090
16036
  }, []);
17091
16037
  reselectNavigationItemRef.current = reselectNavigationItem;
17092
16038
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
17093
- const select = (0, import_react17.useCallback)((anchor) => {
16039
+ const select = (0, import_react16.useCallback)((anchor) => {
17094
16040
  if (!isNavigationItem2(anchor)) return;
17095
16041
  if (activeElRef.current) deactivate();
17096
16042
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -17133,7 +16079,7 @@ function OhhwellsBridge() {
17133
16079
  setFloatingPanel(null);
17134
16080
  setLogoSizeDraft(null);
17135
16081
  }, [deactivate, markSelected]);
17136
- const selectFrame = (0, import_react17.useCallback)((el) => {
16082
+ const selectFrame = (0, import_react16.useCallback)((el) => {
17137
16083
  if (!isNavigationContainer(el)) return;
17138
16084
  if (activeElRef.current) deactivate();
17139
16085
  aiSectionApiRef.current?.selectFromElement(el);
@@ -17184,7 +16130,7 @@ function OhhwellsBridge() {
17184
16130
  setFloatingPanel(null);
17185
16131
  setLogoSizeDraft(null);
17186
16132
  }, [deactivate, markSelected, postToParent2]);
17187
- const selectLogo = (0, import_react17.useCallback)(
16133
+ const selectLogo = (0, import_react16.useCallback)(
17188
16134
  (logoEl) => {
17189
16135
  if (activeElRef.current) deactivate();
17190
16136
  selectedElRef.current = logoEl;
@@ -17213,7 +16159,7 @@ function OhhwellsBridge() {
17213
16159
  },
17214
16160
  [deactivate, markSelected]
17215
16161
  );
17216
- const openLogoSizePanel = (0, import_react17.useCallback)((logoEl) => {
16162
+ const openLogoSizePanel = (0, import_react16.useCallback)((logoEl) => {
17217
16163
  const placement = getLogoPlacement(logoEl);
17218
16164
  const draft = readLogoSizeState(editContentRef.current, placement);
17219
16165
  setLogoSizeDraft(draft);
@@ -17226,7 +16172,7 @@ function OhhwellsBridge() {
17226
16172
  placement
17227
16173
  });
17228
16174
  }, []);
17229
- const openSocialsDisplayPanel = (0, import_react17.useCallback)((row) => {
16175
+ const openSocialsDisplayPanel = (0, import_react16.useCallback)((row) => {
17230
16176
  setParentScrollSnap(parentScrollRef.current);
17231
16177
  setFloatingPanel({
17232
16178
  key: "socials-display",
@@ -17236,11 +16182,11 @@ function OhhwellsBridge() {
17236
16182
  row
17237
16183
  });
17238
16184
  }, []);
17239
- const isEditModeRef = (0, import_react17.useRef)(false);
17240
- const requestMissingSocialIconsRef = (0, import_react17.useRef)(() => {
16185
+ const isEditModeRef = (0, import_react16.useRef)(false);
16186
+ const requestMissingSocialIconsRef = (0, import_react16.useRef)(() => {
17241
16187
  });
17242
- const askedSocialIconsRef = (0, import_react17.useRef)(/* @__PURE__ */ new Set());
17243
- const requestMissingSocialIcons = (0, import_react17.useCallback)(() => {
16188
+ const askedSocialIconsRef = (0, import_react16.useRef)(/* @__PURE__ */ new Set());
16189
+ const requestMissingSocialIcons = (0, import_react16.useCallback)(() => {
17244
16190
  const items = Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).filter((row) => socialsDisplayFor(row, editContentRef.current).icon).flatMap((row) => {
17245
16191
  const missing = socialsMissingIcons(row);
17246
16192
  listSocialItems(row).forEach((item) => ensureIconSlot(item));
@@ -17252,7 +16198,7 @@ function OhhwellsBridge() {
17252
16198
  }, []);
17253
16199
  requestMissingSocialIconsRef.current = requestMissingSocialIcons;
17254
16200
  isEditModeRef.current = isEditMode;
17255
- const changeSocialsDisplay = (0, import_react17.useCallback)(
16201
+ const changeSocialsDisplay = (0, import_react16.useCallback)(
17256
16202
  (row, next) => {
17257
16203
  if (next.icon) {
17258
16204
  const missing = socialsMissingIcons(row);
@@ -17276,17 +16222,17 @@ function OhhwellsBridge() {
17276
16222
  },
17277
16223
  []
17278
16224
  );
17279
- const closeFloatingPanelOnly = (0, import_react17.useCallback)(() => {
16225
+ const closeFloatingPanelOnly = (0, import_react16.useCallback)(() => {
17280
16226
  setFloatingPanel(null);
17281
16227
  setLogoSizeDraft(null);
17282
16228
  }, []);
17283
16229
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17284
- const closeFloatingPanelAndDeselect = (0, import_react17.useCallback)(() => {
16230
+ const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
17285
16231
  setFloatingPanel(null);
17286
16232
  setLogoSizeDraft(null);
17287
16233
  deselectRef.current();
17288
16234
  }, []);
17289
- (0, import_react17.useEffect)(() => {
16235
+ (0, import_react16.useEffect)(() => {
17290
16236
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
17291
16237
  if (!session || !logoSizeDraft) {
17292
16238
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -17305,7 +16251,7 @@ function OhhwellsBridge() {
17305
16251
  max: LOGO_SIZE_MAX
17306
16252
  });
17307
16253
  }, [floatingPanel, logoSizeDraft, editorViewport]);
17308
- const persistLogoSizeDraft = (0, import_react17.useCallback)(
16254
+ const persistLogoSizeDraft = (0, import_react16.useCallback)(
17309
16255
  (placement, draft) => {
17310
16256
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
17311
16257
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -17345,7 +16291,7 @@ function OhhwellsBridge() {
17345
16291
  },
17346
16292
  [postToParent2]
17347
16293
  );
17348
- const activate = (0, import_react17.useCallback)((el, options) => {
16294
+ const activate = (0, import_react16.useCallback)((el, options) => {
17349
16295
  if (activeElRef.current === el) return;
17350
16296
  if (isIconEditable(el)) {
17351
16297
  const social = getSocialItem(el);
@@ -17437,8 +16383,8 @@ function OhhwellsBridge() {
17437
16383
  openLogoSizePanelRef.current = openLogoSizePanel;
17438
16384
  deselectRef.current = deselect;
17439
16385
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17440
- const lastSiteWideScopeRef = (0, import_react17.useRef)(null);
17441
- (0, import_react17.useEffect)(() => {
16386
+ const lastSiteWideScopeRef = (0, import_react16.useRef)(null);
16387
+ (0, import_react16.useEffect)(() => {
17442
16388
  if (!isEditMode) {
17443
16389
  if (lastSiteWideScopeRef.current !== false) {
17444
16390
  lastSiteWideScopeRef.current = false;
@@ -17464,34 +16410,22 @@ function OhhwellsBridge() {
17464
16410
  isFooterFrameSelection,
17465
16411
  postToParent2
17466
16412
  ]);
17467
- (0, import_react17.useLayoutEffect)(() => {
16413
+ (0, import_react16.useLayoutEffect)(() => {
17468
16414
  if (!subdomain || isEditMode) {
17469
16415
  setFetchState("done");
17470
16416
  return;
17471
16417
  }
17472
16418
  const applyContent = (content) => {
17473
16419
  const imageLoads = [];
17474
- if (typeof content[BRAND_KIT_KEY] === "string") {
17475
- brandKitRef.current = content[BRAND_KIT_KEY];
17476
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17477
- }
17478
16420
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17479
16421
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17480
16422
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17481
16423
  }
17482
- if (typeof content[STYLE_STORE_KEY] === "string") {
17483
- stylesRef.current = content[STYLE_STORE_KEY];
17484
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17485
- }
17486
- applyBrandChrome(content);
17487
16424
  for (const [key, val] of Object.entries(content)) {
17488
16425
  if (key === "__ohw_sections") continue;
17489
16426
  if (key === AI_SECTIONS_KEY) continue;
17490
16427
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17491
16428
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17492
- if (key === BRAND_KIT_KEY) continue;
17493
- if (key === STYLE_STORE_KEY) continue;
17494
- if (BRAND_CHROME_KEYS.has(key)) continue;
17495
16429
  if (applyVideoSettingNode(key, val)) continue;
17496
16430
  if (applyCarouselNode(key, val)) continue;
17497
16431
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17552,9 +16486,7 @@ function OhhwellsBridge() {
17552
16486
  let cancelled = false;
17553
16487
  setFetchState("loading");
17554
16488
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17555
- const initialPath = pathname;
17556
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17557
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16489
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17558
16490
  if (cancelled) return;
17559
16491
  const content = data?.content ?? {};
17560
16492
  contentCache.set(subdomain, content);
@@ -17567,7 +16499,7 @@ function OhhwellsBridge() {
17567
16499
  cancelled = true;
17568
16500
  };
17569
16501
  }, [subdomain, isEditMode]);
17570
- (0, import_react17.useEffect)(() => {
16502
+ (0, import_react16.useEffect)(() => {
17571
16503
  if (!isEditMode) return;
17572
16504
  const resolveIndex = (form, clientY) => {
17573
16505
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17608,7 +16540,7 @@ function OhhwellsBridge() {
17608
16540
  window.removeEventListener("drop", onDrop, true);
17609
16541
  };
17610
16542
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17611
- (0, import_react17.useEffect)(() => {
16543
+ (0, import_react16.useEffect)(() => {
17612
16544
  if (!isEditMode) return;
17613
16545
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17614
16546
  markFormFields(form);
@@ -17620,7 +16552,7 @@ function OhhwellsBridge() {
17620
16552
  });
17621
16553
  return () => observer.disconnect();
17622
16554
  }, [isEditMode, fetchState, pathname]);
17623
- (0, import_react17.useEffect)(() => {
16555
+ (0, import_react16.useEffect)(() => {
17624
16556
  if (!isEditMode) return;
17625
16557
  let saveTimer = null;
17626
16558
  const onInput = (e) => {
@@ -17642,14 +16574,14 @@ function OhhwellsBridge() {
17642
16574
  document.addEventListener("input", onInput, true);
17643
16575
  return () => document.removeEventListener("input", onInput, true);
17644
16576
  }, [isEditMode, persistFields]);
17645
- (0, import_react17.useEffect)(() => {
16577
+ (0, import_react16.useEffect)(() => {
17646
16578
  if (isEditMode || fetchState !== "done") return;
17647
16579
  const content = contentCache.get(subdomain) ?? {};
17648
16580
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17649
16581
  reconcileFieldsFromContent(form, content);
17650
16582
  });
17651
16583
  }, [isEditMode, fetchState, subdomain]);
17652
- (0, import_react17.useEffect)(() => {
16584
+ (0, import_react16.useEffect)(() => {
17653
16585
  if (!isEditMode) return;
17654
16586
  const swallow = (e) => {
17655
16587
  const target = e.target;
@@ -17658,12 +16590,12 @@ function OhhwellsBridge() {
17658
16590
  document.addEventListener("submit", swallow, true);
17659
16591
  return () => document.removeEventListener("submit", swallow, true);
17660
16592
  }, [isEditMode]);
17661
- (0, import_react17.useEffect)(() => {
16593
+ (0, import_react16.useEffect)(() => {
17662
16594
  if (isEditMode || fetchState !== "done") return;
17663
16595
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17664
16596
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17665
16597
  }, [isEditMode, fetchState, subdomain]);
17666
- (0, import_react17.useEffect)(() => {
16598
+ (0, import_react16.useEffect)(() => {
17667
16599
  if (!subdomain || isEditMode) return;
17668
16600
  let debounceTimer = null;
17669
16601
  let observer = null;
@@ -17674,25 +16606,10 @@ function OhhwellsBridge() {
17674
16606
  initSectionInstancesFromContent(content, window.location.pathname);
17675
16607
  observer?.disconnect();
17676
16608
  try {
17677
- applyBrandChrome(content);
17678
- if (typeof content[BRAND_KIT_KEY] === "string") {
17679
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17680
- }
17681
- if (typeof content[AI_SECTIONS_KEY] === "string") {
17682
- applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17683
- }
17684
- if (typeof content[STYLE_STORE_KEY] === "string") {
17685
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17686
- }
17687
16609
  for (const [key, val] of Object.entries(content)) {
17688
16610
  if (key === "__ohw_sections") continue;
17689
- if (key === AI_SECTIONS_KEY) continue;
17690
16611
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17691
16612
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17692
- if (key === BRAND_KIT_KEY) continue;
17693
- if (key === STYLE_STORE_KEY) continue;
17694
- if (key === STYLE_STORE_KEY) continue;
17695
- if (BRAND_CHROME_KEYS.has(key)) continue;
17696
16613
  if (applyVideoSettingNode(key, val)) continue;
17697
16614
  if (applyCarouselNode(key, val)) continue;
17698
16615
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17738,17 +16655,6 @@ function OhhwellsBridge() {
17738
16655
  debounceTimer = setTimeout(applyFromCache, 150);
17739
16656
  };
17740
16657
  applyFromCache();
17741
- const pathCacheKey = `${subdomain}::${pathname}`;
17742
- if (!fetchedContentPaths.has(pathCacheKey)) {
17743
- fetchedContentPaths.add(pathCacheKey);
17744
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17745
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17746
- if (!data?.content) return;
17747
- contentCache.set(subdomain, data.content);
17748
- applyFromCache();
17749
- }).catch(() => {
17750
- });
17751
- }
17752
16658
  observer = new MutationObserver(scheduleApply);
17753
16659
  observer.observe(document.body, { childList: true, subtree: true });
17754
16660
  return () => {
@@ -17756,16 +16662,16 @@ function OhhwellsBridge() {
17756
16662
  if (debounceTimer) clearTimeout(debounceTimer);
17757
16663
  };
17758
16664
  }, [subdomain, isEditMode, pathname]);
17759
- (0, import_react17.useLayoutEffect)(() => {
16665
+ (0, import_react16.useLayoutEffect)(() => {
17760
16666
  const el = document.getElementById("ohw-loader");
17761
16667
  if (!el) return;
17762
16668
  const visible = Boolean(subdomain) && fetchState !== "done";
17763
16669
  el.style.display = visible ? "flex" : "none";
17764
16670
  }, [subdomain, fetchState]);
17765
- (0, import_react17.useEffect)(() => {
16671
+ (0, import_react16.useEffect)(() => {
17766
16672
  postToParent2({ type: "ow:navigation", path: pathname });
17767
16673
  }, [pathname, postToParent2]);
17768
- (0, import_react17.useEffect)(() => {
16674
+ (0, import_react16.useEffect)(() => {
17769
16675
  if (!isEditMode) return;
17770
16676
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17771
16677
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17773,7 +16679,7 @@ function OhhwellsBridge() {
17773
16679
  deselectRef.current();
17774
16680
  deactivateRef.current();
17775
16681
  }, [pathname, isEditMode]);
17776
- (0, import_react17.useEffect)(() => {
16682
+ (0, import_react16.useEffect)(() => {
17777
16683
  const contentForNav = () => {
17778
16684
  if (isEditMode) return editContentRef.current;
17779
16685
  if (!subdomain) return {};
@@ -17842,36 +16748,31 @@ function OhhwellsBridge() {
17842
16748
  observer?.disconnect();
17843
16749
  };
17844
16750
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17845
- (0, import_react17.useEffect)(() => {
16751
+ (0, import_react16.useEffect)(() => {
17846
16752
  if (!isEditMode) return;
17847
- let lastPosted = 0;
17848
16753
  const measure = () => {
17849
16754
  const h = document.body.scrollHeight;
17850
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17851
- lastPosted = h;
17852
- postToParent2({ type: "ow:height", height: h });
17853
- }
17854
- };
17855
- let raf = null;
17856
- const schedule = () => {
17857
- if (raf != null) return;
17858
- raf = requestAnimationFrame(() => {
17859
- raf = null;
17860
- measure();
17861
- });
16755
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17862
16756
  };
17863
16757
  const t1 = setTimeout(measure, 50);
17864
16758
  const t2 = setTimeout(measure, 500);
17865
- const ro = new ResizeObserver(schedule);
17866
- ro.observe(document.body);
16759
+ let lastWidth = window.innerWidth;
16760
+ let resizeTimer = null;
16761
+ const handleResize = () => {
16762
+ if (window.innerWidth === lastWidth) return;
16763
+ lastWidth = window.innerWidth;
16764
+ if (resizeTimer) clearTimeout(resizeTimer);
16765
+ resizeTimer = setTimeout(measure, 150);
16766
+ };
16767
+ window.addEventListener("resize", handleResize);
17867
16768
  return () => {
17868
16769
  clearTimeout(t1);
17869
16770
  clearTimeout(t2);
17870
- if (raf != null) cancelAnimationFrame(raf);
17871
- ro.disconnect();
16771
+ if (resizeTimer) clearTimeout(resizeTimer);
16772
+ window.removeEventListener("resize", handleResize);
17872
16773
  };
17873
16774
  }, [pathname, isEditMode, postToParent2]);
17874
- (0, import_react17.useEffect)(() => {
16775
+ (0, import_react16.useEffect)(() => {
17875
16776
  if (!subdomainFromQuery || isEditMode) return;
17876
16777
  const handleClick = (e) => {
17877
16778
  const anchor = e.target.closest("a");
@@ -17887,7 +16788,7 @@ function OhhwellsBridge() {
17887
16788
  document.addEventListener("click", handleClick, true);
17888
16789
  return () => document.removeEventListener("click", handleClick, true);
17889
16790
  }, [subdomainFromQuery, isEditMode, router]);
17890
- (0, import_react17.useEffect)(() => {
16791
+ (0, import_react16.useEffect)(() => {
17891
16792
  if (!isEditMode) {
17892
16793
  editStylesRef.current?.base.remove();
17893
16794
  editStylesRef.current?.forceHover.remove();
@@ -18109,7 +17010,6 @@ function OhhwellsBridge() {
18109
17010
  return;
18110
17011
  }
18111
17012
  const target = e.target;
18112
- if (target.closest("[data-ohw-ai-review]")) return;
18113
17013
  if (target.closest("[data-ohw-toolbar]")) return;
18114
17014
  if (target.closest("[data-ohw-state-toggle]")) return;
18115
17015
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18121,9 +17021,6 @@ function OhhwellsBridge() {
18121
17021
  )) {
18122
17022
  return;
18123
17023
  }
18124
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
18125
- clearMediaSelectionRef.current();
18126
- }
18127
17024
  {
18128
17025
  const formEl = getFormElement(target);
18129
17026
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -18278,11 +17175,8 @@ function OhhwellsBridge() {
18278
17175
  if (isMediaEditable(editable) && !buttonOnMedia) {
18279
17176
  e.preventDefault();
18280
17177
  e.stopPropagation();
18281
- if (selectedMediaElRef.current === editable) {
18282
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18283
- } else {
18284
- selectMediaElementRef.current(editable);
18285
- }
17178
+ aiSectionApiRef.current?.selectFromElement(editable);
17179
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18286
17180
  return;
18287
17181
  }
18288
17182
  const socialItem = getSocialItem(editable);
@@ -18418,7 +17312,6 @@ function OhhwellsBridge() {
18418
17312
  };
18419
17313
  const handleDblClick = (e) => {
18420
17314
  const target = e.target;
18421
- if (target.closest("[data-ohw-ai-review]")) return;
18422
17315
  if (target.closest("[data-ohw-toolbar]")) return;
18423
17316
  if (target.closest("[data-ohw-state-toggle]")) return;
18424
17317
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18470,9 +17363,6 @@ function OhhwellsBridge() {
18470
17363
  setHoveredItemRect(null);
18471
17364
  hoveredNavContainerRef.current = null;
18472
17365
  setHoveredNavContainerRect(null);
18473
- siblingHintElRef.current = null;
18474
- setSiblingHintRect(null);
18475
- setSiblingHintRects([]);
18476
17366
  return;
18477
17367
  }
18478
17368
  {
@@ -18591,6 +17481,7 @@ function OhhwellsBridge() {
18591
17481
  hoveredNavContainerRef.current = null;
18592
17482
  setHoveredNavContainerRect(null);
18593
17483
  hoveredItemElRef.current = editable;
17484
+ setHoveredItemRect(editable.getBoundingClientRect());
18594
17485
  }
18595
17486
  }
18596
17487
  }
@@ -18887,7 +17778,7 @@ function OhhwellsBridge() {
18887
17778
  }
18888
17779
  };
18889
17780
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18890
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17781
+ if (linkPopoverOpenRef.current) {
18891
17782
  if (hoveredImageRef.current) {
18892
17783
  hoveredImageRef.current = null;
18893
17784
  hoveredImageHasTextOverlapRef.current = false;
@@ -19221,9 +18112,7 @@ function OhhwellsBridge() {
19221
18112
  return;
19222
18113
  }
19223
18114
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
19224
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
19225
- (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
19226
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18115
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
19227
18116
  const ZONE = 20;
19228
18117
  for (let i = 0; i < sections.length; i++) {
19229
18118
  const a = sections[i];
@@ -19252,7 +18141,8 @@ function OhhwellsBridge() {
19252
18141
  };
19253
18142
  const handleMouseMove = (e) => {
19254
18143
  const { clientX, clientY } = e;
19255
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
18144
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18145
+ if (isOverEditorChrome(clientX, clientY)) {
19256
18146
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
19257
18147
  formHoverElRef.current = null;
19258
18148
  setFormHoverRect(null);
@@ -19260,12 +18150,6 @@ function OhhwellsBridge() {
19260
18150
  setHoveredItemRect(null);
19261
18151
  hoveredNavContainerRef.current = null;
19262
18152
  setHoveredNavContainerRect(null);
19263
- siblingHintElRef.current = null;
19264
- setSiblingHintRect(null);
19265
- setSiblingHintRects([]);
19266
- dismissImageHover();
19267
- clearImageHover();
19268
- setSectionGap(null);
19269
18153
  return;
19270
18154
  }
19271
18155
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -19277,11 +18161,7 @@ function OhhwellsBridge() {
19277
18161
  if (e.data?.type !== "ow:pointer-sync") return;
19278
18162
  const { clientX, clientY } = e.data;
19279
18163
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
19280
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
19281
- dismissImageHover();
19282
- clearImageHover();
19283
- return;
19284
- }
18164
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
19285
18165
  if (probeSocialsRowAt(clientX, clientY)) return;
19286
18166
  probeSectionGapAt(clientX, clientY);
19287
18167
  probeImageAt(clientX, clientY);
@@ -19564,19 +18444,10 @@ function OhhwellsBridge() {
19564
18444
  if (e.data?.type !== "ow:hydrate") return;
19565
18445
  const content = e.data.content;
19566
18446
  if (!content) return;
19567
- if (typeof content[BRAND_KIT_KEY] === "string") {
19568
- brandKitRef.current = content[BRAND_KIT_KEY];
19569
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19570
- }
19571
18447
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19572
18448
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19573
18449
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19574
18450
  }
19575
- if (typeof content[STYLE_STORE_KEY] === "string") {
19576
- stylesRef.current = content[STYLE_STORE_KEY];
19577
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19578
- }
19579
- applyBrandChrome(content);
19580
18451
  let sectionsJson = null;
19581
18452
  for (const [key, val] of Object.entries(content)) {
19582
18453
  if (key === "__ohw_sections") {
@@ -19586,9 +18457,6 @@ function OhhwellsBridge() {
19586
18457
  if (key === AI_SECTIONS_KEY) continue;
19587
18458
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19588
18459
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19589
- if (key === BRAND_KIT_KEY) continue;
19590
- if (key === STYLE_STORE_KEY) continue;
19591
- if (BRAND_CHROME_KEYS.has(key)) continue;
19592
18460
  if (applyVideoSettingNode(key, val)) continue;
19593
18461
  if (applyCarouselNode(key, val)) continue;
19594
18462
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19602,8 +18470,6 @@ function OhhwellsBridge() {
19602
18470
  if (video && video.src !== val) applyVideoSrc(video, val);
19603
18471
  } else if (el.dataset.ohwEditable === "link") {
19604
18472
  applyLinkHref(el, val);
19605
- } else if (el.dataset.ohwEditable === "icon") {
19606
- applyIconMarkup(el, val);
19607
18473
  } else if (isIconMarkupValue(val)) {
19608
18474
  } else {
19609
18475
  el.innerHTML = val;
@@ -19688,21 +18554,12 @@ function OhhwellsBridge() {
19688
18554
  nodes: collectEditableNodes(editContentRef.current)
19689
18555
  });
19690
18556
  };
19691
- const clearInteractionChrome = () => {
19692
- deactivateRef.current();
19693
- deselectRef.current();
19694
- clearMediaSelectionRef.current();
19695
- };
19696
18557
  const handleAiApplyTree = (e) => {
19697
18558
  if (e.data?.type !== "ow:ai-apply-tree") return;
19698
18559
  const payload = e.data.payload;
19699
18560
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19700
- clearInteractionChrome();
19701
18561
  const previous = aiSectionsRef.current;
19702
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19703
- ...payload,
19704
- path: payload.path ?? window.location.pathname
19705
- });
18562
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19706
18563
  const nextValue = serializeAiSectionsState(nextState);
19707
18564
  aiSectionsRef.current = nextValue;
19708
18565
  applyAiSectionsToDom(nextState);
@@ -19722,7 +18579,6 @@ function OhhwellsBridge() {
19722
18579
  if (!sectionId || sectionId === "navbar" || sectionId === "footer") return;
19723
18580
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
19724
18581
  if (!exists) return;
19725
- clearInteractionChrome();
19726
18582
  const previous = aiSectionsRef.current;
19727
18583
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
19728
18584
  const nextValue = serializeAiSectionsState(nextState);
@@ -19738,58 +18594,14 @@ function OhhwellsBridge() {
19738
18594
  const handleAiSetSections = (e) => {
19739
18595
  if (e.data?.type !== "ow:ai-set-sections") return;
19740
18596
  const value = typeof e.data.value === "string" ? e.data.value : "";
19741
- clearInteractionChrome();
19742
18597
  aiSectionsRef.current = value;
19743
18598
  applyAiSectionsToDom(parseAiSectionsState(value));
19744
- applyStylesToDom(parseStyleStore(stylesRef.current));
19745
18599
  const restoredHeight = document.documentElement.scrollHeight;
19746
18600
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19747
18601
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19748
18602
  postAiSectionsChanged();
19749
18603
  };
19750
18604
  window.addEventListener("message", handleAiSetSections);
19751
- const handleMoveSection = (e) => {
19752
- if (e.data?.type !== "ow:move-section") return;
19753
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19754
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19755
- if (!instanceId || !direction) return;
19756
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19757
- if (!entries) return;
19758
- const orderJson = JSON.stringify(entries);
19759
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19760
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19761
- window.dispatchEvent(new Event("resize"));
19762
- };
19763
- window.addEventListener("message", handleMoveSection);
19764
- const handleAiSetBrand = (e) => {
19765
- if (e.data?.type !== "ow:ai-set-brand") return;
19766
- const value = typeof e.data.value === "string" ? e.data.value : "";
19767
- const previous = brandKitRef.current;
19768
- brandKitRef.current = value;
19769
- applyBrandToDom(parseBrandKit(value));
19770
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19771
- applyStylesToDom(parseStyleStore(stylesRef.current));
19772
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19773
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19774
- };
19775
- window.addEventListener("message", handleAiSetBrand);
19776
- const handleAiSetStyles = (e) => {
19777
- if (e.data?.type !== "ow:ai-set-styles") return;
19778
- const value = typeof e.data.value === "string" ? e.data.value : "";
19779
- const previous = stylesRef.current;
19780
- stylesRef.current = value;
19781
- applyStylesToDom(parseStyleStore(value));
19782
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19783
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19784
- };
19785
- window.addEventListener("message", handleAiSetStyles);
19786
- const handleGetBrand = (e) => {
19787
- if (e.data?.type !== "ow:get-brand") return;
19788
- const template = deriveTemplateBrand();
19789
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19790
- postToParentRef.current({ type: "ow:brand-value", value });
19791
- };
19792
- window.addEventListener("message", handleGetBrand);
19793
18605
  const handlePanelDragging = (e) => {
19794
18606
  if (e.data?.type !== "ow:panel-dragging") return;
19795
18607
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
@@ -19805,15 +18617,8 @@ function OhhwellsBridge() {
19805
18617
  closeLinkPopoverRef.current();
19806
18618
  return;
19807
18619
  }
19808
- if (floatingPanelOpenRef.current) {
19809
- setFloatingPanelRef.current(null);
19810
- deselectRef.current();
19811
- deactivateRef.current();
19812
- return;
19813
- }
19814
18620
  deselectRef.current();
19815
18621
  deactivateRef.current();
19816
- clearMediaSelectionRef.current();
19817
18622
  };
19818
18623
  window.addEventListener("message", handleDeactivate);
19819
18624
  const handleToastAction = (e) => {
@@ -19899,10 +18704,6 @@ function OhhwellsBridge() {
19899
18704
  const handleKeyDown = (e) => {
19900
18705
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19901
18706
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19902
- if (e.key === "Escape" && selectedMediaElRef.current) {
19903
- clearMediaSelectionRef.current();
19904
- return;
19905
- }
19906
18707
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19907
18708
  e.preventDefault();
19908
18709
  selectAllTextInEditable(activeElRef.current);
@@ -20062,12 +18863,6 @@ function OhhwellsBridge() {
20062
18863
  if (aiSectionsRef.current) {
20063
18864
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
20064
18865
  }
20065
- if (stylesRef.current) {
20066
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
20067
- }
20068
- if (brandKitRef.current) {
20069
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
20070
- }
20071
18866
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
20072
18867
  const formKey = formKeyOf(form);
20073
18868
  if (!formKey) return;
@@ -20085,12 +18880,8 @@ function OhhwellsBridge() {
20085
18880
  if (inserted) {
20086
18881
  const tracker = getSectionsTracker();
20087
18882
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
20088
- const reportHeight = () => {
20089
- const h = document.body.scrollHeight;
20090
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20091
- };
20092
- reportHeight();
20093
- setTimeout(reportHeight, 500);
18883
+ const h = document.documentElement.scrollHeight;
18884
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20094
18885
  }
20095
18886
  };
20096
18887
  const handleSwitchSchedule = (e) => {
@@ -20477,23 +19268,19 @@ function OhhwellsBridge() {
20477
19268
  window.removeEventListener("message", handleAiApplyTree);
20478
19269
  window.removeEventListener("message", handleAiDeleteSection);
20479
19270
  window.removeEventListener("message", handleAiSetSections);
20480
- window.removeEventListener("message", handleMoveSection);
20481
- window.removeEventListener("message", handleAiSetBrand);
20482
- window.removeEventListener("message", handleAiSetStyles);
20483
- window.removeEventListener("message", handleGetBrand);
20484
19271
  window.removeEventListener("message", handlePanelDragging);
20485
19272
  window.removeEventListener("message", handleDeactivate);
19273
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
20486
19274
  window.removeEventListener("message", handleToastAction);
20487
19275
  window.removeEventListener("message", handleFormCount);
20488
19276
  window.removeEventListener("message", handleUiEscape);
20489
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
20490
19277
  autoSaveTimers.current.forEach(clearTimeout);
20491
19278
  autoSaveTimers.current.clear();
20492
19279
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
20493
19280
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
20494
19281
  };
20495
19282
  }, [isEditMode, refreshStateRules]);
20496
- (0, import_react17.useEffect)(() => {
19283
+ (0, import_react16.useEffect)(() => {
20497
19284
  if (!isEditMode) return;
20498
19285
  const THRESHOLD = 10;
20499
19286
  const resolveWasSelected = (el) => {
@@ -20649,7 +19436,7 @@ function OhhwellsBridge() {
20649
19436
  unlockFooterDragInteraction();
20650
19437
  };
20651
19438
  }, [isEditMode]);
20652
- (0, import_react17.useEffect)(() => {
19439
+ (0, import_react16.useEffect)(() => {
20653
19440
  const handler = (e) => {
20654
19441
  if (e.data?.type !== "ow:request-schedule-config") return;
20655
19442
  const insertAfterVal = e.data.insertAfter;
@@ -20665,7 +19452,7 @@ function OhhwellsBridge() {
20665
19452
  window.addEventListener("message", handler);
20666
19453
  return () => window.removeEventListener("message", handler);
20667
19454
  }, [processConfigRequest]);
20668
- (0, import_react17.useEffect)(() => {
19455
+ (0, import_react16.useEffect)(() => {
20669
19456
  if (!isEditMode) return;
20670
19457
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20671
19458
  el.removeAttribute("data-ohw-active-state");
@@ -20689,7 +19476,7 @@ function OhhwellsBridge() {
20689
19476
  postToParent2({
20690
19477
  type: "ow:ready",
20691
19478
  version: "1",
20692
- bridgeVersion: "0.1.70",
19479
+ bridgeVersion: "0.1.69",
20693
19480
  path: pathname,
20694
19481
  nodes: collectEditableNodes(editContentRef.current),
20695
19482
  sections
@@ -20701,13 +19488,13 @@ function OhhwellsBridge() {
20701
19488
  clearTimeout(timer);
20702
19489
  };
20703
19490
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20704
- (0, import_react17.useEffect)(() => {
19491
+ (0, import_react16.useEffect)(() => {
20705
19492
  scrollToHashSectionWhenReady();
20706
19493
  const onHashChange = () => scrollToHashSectionWhenReady();
20707
19494
  window.addEventListener("hashchange", onHashChange);
20708
19495
  return () => window.removeEventListener("hashchange", onHashChange);
20709
19496
  }, [pathname]);
20710
- const handleCommand = (0, import_react17.useCallback)((cmd) => {
19497
+ const handleCommand = (0, import_react16.useCallback)((cmd) => {
20711
19498
  const el = activeElRef.current;
20712
19499
  const selBefore = window.getSelection();
20713
19500
  let savedOffsets = null;
@@ -20743,7 +19530,7 @@ function OhhwellsBridge() {
20743
19530
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20744
19531
  refreshActiveCommandsRef.current();
20745
19532
  }, []);
20746
- (0, import_react17.useEffect)(() => {
19533
+ (0, import_react16.useEffect)(() => {
20747
19534
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20748
19535
  if (!session || !logoSizeDraft) return;
20749
19536
  const onPanelAction = (e) => {
@@ -20781,7 +19568,7 @@ function OhhwellsBridge() {
20781
19568
  window.addEventListener("message", onPanelAction);
20782
19569
  return () => window.removeEventListener("message", onPanelAction);
20783
19570
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20784
- const handleStateChange = (0, import_react17.useCallback)((state) => {
19571
+ const handleStateChange = (0, import_react16.useCallback)((state) => {
20785
19572
  if (!activeStateElRef.current) return;
20786
19573
  const el = activeStateElRef.current;
20787
19574
  if (state === "Default") {
@@ -20794,7 +19581,7 @@ function OhhwellsBridge() {
20794
19581
  }
20795
19582
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20796
19583
  }, [deactivate]);
20797
- const reselectAfterLinkPopover = (0, import_react17.useCallback)(
19584
+ const reselectAfterLinkPopover = (0, import_react16.useCallback)(
20798
19585
  (hrefKey) => {
20799
19586
  requestAnimationFrame(() => {
20800
19587
  const el = resolveHrefKeyElement(hrefKey);
@@ -20803,7 +19590,7 @@ function OhhwellsBridge() {
20803
19590
  },
20804
19591
  [resolveHrefKeyElement]
20805
19592
  );
20806
- const closeLinkPopover = (0, import_react17.useCallback)(() => {
19593
+ const closeLinkPopover = (0, import_react16.useCallback)(() => {
20807
19594
  const session = linkPopoverSessionRef.current;
20808
19595
  addNavAfterAnchorRef.current = null;
20809
19596
  setLinkPopover(null);
@@ -20811,9 +19598,9 @@ function OhhwellsBridge() {
20811
19598
  reselectAfterLinkPopover(session.key);
20812
19599
  }
20813
19600
  }, [reselectAfterLinkPopover]);
20814
- const closeLinkPopoverRef = (0, import_react17.useRef)(closeLinkPopover);
19601
+ const closeLinkPopoverRef = (0, import_react16.useRef)(closeLinkPopover);
20815
19602
  closeLinkPopoverRef.current = closeLinkPopover;
20816
- const openLinkPopoverForActive = (0, import_react17.useCallback)(() => {
19603
+ const openLinkPopoverForActive = (0, import_react16.useCallback)(() => {
20817
19604
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20818
19605
  if (!hrefCtx) return;
20819
19606
  bumpLinkPopoverGrace();
@@ -20824,7 +19611,7 @@ function OhhwellsBridge() {
20824
19611
  });
20825
19612
  deactivate();
20826
19613
  }, [deactivate]);
20827
- const openLinkPopoverForSelected = (0, import_react17.useCallback)(() => {
19614
+ const openLinkPopoverForSelected = (0, import_react16.useCallback)(() => {
20828
19615
  const anchor = selectedElRef.current;
20829
19616
  if (!anchor) return;
20830
19617
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20841,7 +19628,7 @@ function OhhwellsBridge() {
20841
19628
  });
20842
19629
  deselect();
20843
19630
  }, [deselect]);
20844
- const handleSelectParent = (0, import_react17.useCallback)(() => {
19631
+ const handleSelectParent = (0, import_react16.useCallback)(() => {
20845
19632
  const selected = selectedElRef.current;
20846
19633
  if (!selected) return;
20847
19634
  if (toolbarVariantRef.current === "select-frame") {
@@ -20868,7 +19655,7 @@ function OhhwellsBridge() {
20868
19655
  }
20869
19656
  deselectRef.current();
20870
19657
  }, []);
20871
- const handleDuplicateSelected = (0, import_react17.useCallback)(() => {
19658
+ const handleDuplicateSelected = (0, import_react16.useCallback)(() => {
20872
19659
  const selected = selectedElRef.current;
20873
19660
  if (!selected || !isNavigationItem2(selected)) return;
20874
19661
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -21001,7 +19788,7 @@ function OhhwellsBridge() {
21001
19788
  });
21002
19789
  }
21003
19790
  }, [postToParent2]);
21004
- const runPendingDeleteUndo = (0, import_react17.useCallback)(() => {
19791
+ const runPendingDeleteUndo = (0, import_react16.useCallback)(() => {
21005
19792
  const pending = pendingDeleteUndoRef.current;
21006
19793
  if (!pending) return false;
21007
19794
  pendingDeleteUndoRef.current = null;
@@ -21009,7 +19796,7 @@ function OhhwellsBridge() {
21009
19796
  enforceLinkHrefs();
21010
19797
  return true;
21011
19798
  }, []);
21012
- const handleDeleteSelected = (0, import_react17.useCallback)(() => {
19799
+ const handleDeleteSelected = (0, import_react16.useCallback)(() => {
21013
19800
  const selected = selectedElRef.current;
21014
19801
  if (!selected) return false;
21015
19802
  return deleteSelectedNavFooterItem({
@@ -21030,7 +19817,7 @@ function OhhwellsBridge() {
21030
19817
  }, [postToParent2]);
21031
19818
  handleDeleteSelectedRef.current = handleDeleteSelected;
21032
19819
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
21033
- const handleLinkPopoverSubmit = (0, import_react17.useCallback)(
19820
+ const handleLinkPopoverSubmit = (0, import_react16.useCallback)(
21034
19821
  (target) => {
21035
19822
  const session = linkPopoverSessionRef.current;
21036
19823
  if (!session) return;
@@ -21096,30 +19883,19 @@ function OhhwellsBridge() {
21096
19883
  const showEditLink = toolbarShowEditLink;
21097
19884
  const currentSections = sectionsByPath[pathname] ?? [];
21098
19885
  linkPopoverOpenRef.current = linkPopover !== null;
21099
- const handleMediaSelect = (0, import_react17.useCallback)((key) => {
21100
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
21101
- (m) => (m.dataset.ohwKey ?? "") === key
21102
- ) ?? null;
21103
- if (!el) return;
21104
- selectMediaElementRef.current(el);
21105
- }, []);
21106
- const handleMediaReplace = (0, import_react17.useCallback)(
19886
+ const handleMediaReplace = (0, import_react16.useCallback)(
21107
19887
  (key) => {
21108
- postToParent2({
21109
- type: "ow:image-pick",
21110
- key,
21111
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
21112
- });
19888
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
21113
19889
  },
21114
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19890
+ [postToParent2, mediaHover?.elementType]
21115
19891
  );
21116
- const handleEditCarousel = (0, import_react17.useCallback)(
19892
+ const handleEditCarousel = (0, import_react16.useCallback)(
21117
19893
  (key) => {
21118
19894
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
21119
19895
  },
21120
19896
  [postToParent2]
21121
19897
  );
21122
- const handleMediaFadeOutComplete = (0, import_react17.useCallback)((key) => {
19898
+ const handleMediaFadeOutComplete = (0, import_react16.useCallback)((key) => {
21123
19899
  setUploadingRects((prev) => {
21124
19900
  if (!(key in prev)) return prev;
21125
19901
  const next = { ...prev };
@@ -21127,7 +19903,7 @@ function OhhwellsBridge() {
21127
19903
  return next;
21128
19904
  });
21129
19905
  }, []);
21130
- const handleVideoSettingsChange = (0, import_react17.useCallback)(
19906
+ const handleVideoSettingsChange = (0, import_react16.useCallback)(
21131
19907
  (key, settings) => {
21132
19908
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
21133
19909
  const video = getVideoEl2(el);
@@ -21149,516 +19925,430 @@ function OhhwellsBridge() {
21149
19925
  },
21150
19926
  [postToParent2]
21151
19927
  );
21152
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21153
- /* @__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, {}) }),
21154
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
21155
- bridgeRoot ? (0, import_react_dom4.createPortal)(
21156
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21157
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
21158
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
21159
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21160
- "div",
21161
- {
21162
- className: "pointer-events-none fixed z-2147483646",
21163
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
21164
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21165
- DropIndicator,
21166
- {
21167
- direction: "horizontal",
21168
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
21169
- className: "!h-full !w-full"
21170
- }
21171
- )
21172
- },
21173
- `section-drop-${slot.insertIndex}-${i}`
21174
- )),
21175
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21176
- MediaOverlay,
21177
- {
21178
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
21179
- isUploading: true,
21180
- fadingOut,
21181
- onFadeOutComplete: handleMediaFadeOutComplete,
21182
- onReplace: handleMediaReplace
21183
- },
21184
- `uploading-${key}`
21185
- )),
21186
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21187
- MediaOverlay,
21188
- {
21189
- hover: mediaHover,
21190
- isUploading: false,
21191
- onReplace: handleMediaReplace,
21192
- onSelect: handleMediaSelect,
21193
- onVideoSettingsChange: handleVideoSettingsChange
21194
- }
21195
- ),
21196
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21197
- MediaOverlay,
21198
- {
21199
- hover: selectedMedia,
21200
- selected: true,
21201
- hovered: mediaHover?.key === selectedMedia.key,
21202
- isUploading: false,
21203
- onReplace: handleMediaReplace,
21204
- onSelect: handleMediaSelect,
21205
- onVideoSettingsChange: handleVideoSettingsChange
21206
- }
21207
- ),
21208
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
21209
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
21210
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
21211
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
21212
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21213
- "div",
21214
- {
21215
- className: "pointer-events-none fixed z-2147483646",
21216
- style: {
21217
- left: slot.left,
21218
- top: slot.top,
21219
- width: slot.width,
21220
- height: slot.height
21221
- },
21222
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21223
- DropIndicator,
21224
- {
21225
- direction: slot.direction,
21226
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
21227
- className: "!h-full !w-full"
21228
- }
21229
- )
21230
- },
21231
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
21232
- )),
21233
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21234
- "div",
21235
- {
21236
- className: "pointer-events-none fixed z-2147483646",
21237
- style: {
21238
- left: slot.left,
21239
- top: slot.top,
21240
- width: slot.width,
21241
- height: slot.height
21242
- },
21243
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21244
- DropIndicator,
21245
- {
21246
- direction: slot.direction,
21247
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
21248
- className: "!h-full !w-full"
21249
- }
21250
- )
19928
+ return bridgeRoot ? (0, import_react_dom4.createPortal)(
19929
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19930
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19931
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19932
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19933
+ MediaOverlay,
19934
+ {
19935
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19936
+ isUploading: true,
19937
+ fadingOut,
19938
+ onFadeOutComplete: handleMediaFadeOutComplete,
19939
+ onReplace: handleMediaReplace
19940
+ },
19941
+ `uploading-${key}`
19942
+ )),
19943
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19944
+ MediaOverlay,
19945
+ {
19946
+ hover: mediaHover,
19947
+ isUploading: false,
19948
+ onReplace: handleMediaReplace,
19949
+ onVideoSettingsChange: handleVideoSettingsChange
19950
+ }
19951
+ ),
19952
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19953
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19954
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19955
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19956
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19957
+ "div",
19958
+ {
19959
+ className: "pointer-events-none fixed z-2147483646",
19960
+ style: {
19961
+ left: slot.left,
19962
+ top: slot.top,
19963
+ width: slot.width,
19964
+ height: slot.height
21251
19965
  },
21252
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
21253
- )),
21254
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
21255
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
21256
- hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
21257
- formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21258
- ItemInteractionLayer,
21259
- {
21260
- rect: formPickRect,
21261
- state: "active-top",
21262
- itemDragSurface: false,
21263
- toolbarAlign: "left",
21264
- chromeGap: 24,
21265
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21266
- "div",
21267
- {
21268
- "data-ohw-form-toolbar": "",
21269
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
21270
- children: [
21271
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21272
- "button",
21273
- {
21274
- type: "button",
21275
- "aria-label": "Add field",
21276
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
21277
- onClick: () => setFieldTypePickerOpen((open) => !open),
21278
- "data-ohw-add-field": "",
21279
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
21280
- }
21281
- ),
21282
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
21283
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21284
- "button",
21285
- {
21286
- type: "button",
21287
- 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",
21288
- onClick: () => {
21289
- setFieldTypePickerOpen(false);
21290
- const form = formPickElRef.current;
21291
- if (!form) return;
21292
- postToParent2({
21293
- type: "ow:form-pick",
21294
- formKey: formKeyOf(form),
21295
- hasLongText: formHasLongText(form)
21296
- });
21297
- },
21298
- children: [
21299
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
21300
- "Form settings",
21301
- formPickCount ? (
21302
- // Counter pill, per the design — not a text suffix.
21303
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21304
- "span",
21305
- {
21306
- "data-ohw-form-count": "",
21307
- 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",
21308
- children: formPickCount
21309
- }
21310
- )
21311
- ) : null
21312
- ]
21313
- }
21314
- ),
21315
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
21316
- /* @__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)(
21317
- "button",
21318
- {
21319
- type: "button",
21320
- "aria-pressed": formViewState === state,
21321
- 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"),
21322
- onClick: () => {
21323
- setFieldTypePickerOpen(false);
21324
- const form = formPickElRef.current;
21325
- const key = form ? formKeyOf(form) : null;
21326
- if (!form || !key) return;
21327
- const initial = successInitialFor(form, key, editContentRef.current);
21328
- setFormViewState(form, key, state, initial);
21329
- setFormViewStateUi(state);
21330
- setFormPickRect(form.getBoundingClientRect());
21331
- if (state === "success") {
21332
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
21333
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
21334
- } else {
21335
- deactivateRef.current();
21336
- }
21337
- },
21338
- children: state
21339
- },
21340
- state
21341
- )) })
21342
- ]
21343
- }
21344
- )
21345
- }
21346
- ),
21347
- formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21348
- ItemInteractionLayer,
21349
- {
21350
- rect: formHoverRect,
21351
- state: "hover",
21352
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
21353
- }
21354
- ),
21355
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21356
- ItemInteractionLayer,
21357
- {
21358
- rect: fieldPickRect,
21359
- state: fieldDragging ? "dragging" : "active-top",
21360
- itemDragSurface: false,
21361
- toolbarAlign: "left",
21362
- chromeGap: 10,
21363
- showHandle: true,
21364
- dragHandleLabel: "Reorder field",
21365
- onDragHandleDragStart: handleFieldDragStart,
21366
- onDragHandleDragEnd: handleFieldDragEnd,
21367
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21368
- FormFieldToolbar,
21369
- {
21370
- type: fieldPickState.type,
21371
- required: fieldPickState.required,
21372
- onTypeChange: handleFieldTypeChange,
21373
- onRequiredToggle: handleFieldRequiredToggle,
21374
- onDuplicate: handleFieldDuplicate,
21375
- onDelete: handleFieldDelete
21376
- }
21377
- )
21378
- }
21379
- ),
21380
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21381
- "div",
21382
- {
21383
- className: "pointer-events-none fixed z-[2147483644]",
21384
- style: { top: slot.top, left: slot.left, width: slot.width },
21385
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21386
- DropIndicator,
21387
- {
21388
- direction: "horizontal",
21389
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
21390
- className: "!w-full"
21391
- }
21392
- )
19966
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19967
+ DropIndicator,
19968
+ {
19969
+ direction: slot.direction,
19970
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19971
+ className: "!h-full !w-full"
19972
+ }
19973
+ )
19974
+ },
19975
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19976
+ )),
19977
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19978
+ "div",
19979
+ {
19980
+ className: "pointer-events-none fixed z-2147483646",
19981
+ style: {
19982
+ left: slot.left,
19983
+ top: slot.top,
19984
+ width: slot.width,
19985
+ height: slot.height
21393
19986
  },
21394
- `field-drop-${i}`
21395
- )) : null,
21396
- fieldTypePickerOpen && formPickRect ? (() => {
21397
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
21398
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21399
- "div",
19987
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19988
+ DropIndicator,
21400
19989
  {
21401
- className: "pointer-events-none fixed z-[2147483645]",
21402
- style: {
21403
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
21404
- left: toolbar ? toolbar.left : formPickRect.left + 24
21405
- },
21406
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
19990
+ direction: slot.direction,
19991
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19992
+ className: "!h-full !w-full"
21407
19993
  }
21408
- );
21409
- })() : null,
21410
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
21411
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21412
- FooterContainerChrome,
21413
- {
21414
- rect: toolbarRect,
21415
- onAdd: handleAddFooterColumn,
21416
- addDisabled: !canAddFooterColumn()
21417
- }
21418
- ),
21419
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21420
- ItemInteractionLayer,
21421
- {
21422
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
21423
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
21424
- elRef: glowElRef,
21425
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
21426
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
21427
- dragDisabled: reorderDragDisabled,
21428
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
21429
- onDragHandleDragStart: handleItemDragStart,
21430
- onDragHandleDragEnd: handleItemDragEnd,
21431
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
21432
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
21433
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
21434
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21435
- ItemActionToolbar,
21436
- {
21437
- onEditLink: openLinkPopoverForSelected,
21438
- onStyle: () => {
21439
- const row = selectedElRef.current;
21440
- if (!row) return;
21441
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
21442
- else openSocialsDisplayPanel(row);
21443
- },
21444
- showStyle: selectedIsSocialsRow,
21445
- styleActive: floatingPanel?.kind === "socials-display",
21446
- onAddItem: handleAddChildItem,
21447
- onSelectParent: handleSelectParent,
21448
- onDuplicate: handleDuplicateSelected,
21449
- onDelete: handleDeleteSelected,
21450
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
21451
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
21452
- return row ? !canAddSocialItem(row) : false;
21453
- })(),
21454
- editLinkDisabled: false,
21455
- moreDisabled: false,
21456
- deleteDisabled: selectedElRef.current !== null && (() => {
21457
- const social = getSocialItem(selectedElRef.current);
21458
- return social ? !canRemoveSocialItem(social) : false;
21459
- })(),
21460
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
21461
- const social = getSocialItem(selectedElRef.current);
21462
- const row = social ? findSocialsRow(social) : null;
21463
- return row ? !canAddSocialItem(row) : false;
21464
- })(),
21465
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
21466
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
21467
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19994
+ )
19995
+ },
19996
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19997
+ )),
19998
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19999
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20000
+ hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20001
+ formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20002
+ ItemInteractionLayer,
20003
+ {
20004
+ rect: formPickRect,
20005
+ state: "active-top",
20006
+ itemDragSurface: false,
20007
+ toolbarAlign: "left",
20008
+ chromeGap: 24,
20009
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20010
+ "div",
20011
+ {
20012
+ "data-ohw-form-toolbar": "",
20013
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20014
+ children: [
20015
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20016
+ "button",
20017
+ {
20018
+ type: "button",
20019
+ "aria-label": "Add field",
20020
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20021
+ onClick: () => setFieldTypePickerOpen((open) => !open),
20022
+ "data-ohw-add-field": "",
20023
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
20024
+ }
21468
20025
  ),
21469
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
21470
- dropdownOpen: navDropdownPreviewOpen,
21471
- onDropdownOpenChange: handleNavDropdownOpenChange,
21472
- headingVisible: footerHeadingVisible,
21473
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
21474
- }
21475
- ) : void 0
21476
- }
21477
- ),
21478
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21479
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21480
- EditGlowChrome,
20026
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20027
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20028
+ "button",
20029
+ {
20030
+ type: "button",
20031
+ 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",
20032
+ onClick: () => {
20033
+ setFieldTypePickerOpen(false);
20034
+ const form = formPickElRef.current;
20035
+ if (!form) return;
20036
+ postToParent2({
20037
+ type: "ow:form-pick",
20038
+ formKey: formKeyOf(form),
20039
+ hasLongText: formHasLongText(form)
20040
+ });
20041
+ },
20042
+ children: [
20043
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
20044
+ "Form settings",
20045
+ formPickCount ? (
20046
+ // Counter pill, per the design — not a text suffix.
20047
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20048
+ "span",
20049
+ {
20050
+ "data-ohw-form-count": "",
20051
+ 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",
20052
+ children: formPickCount
20053
+ }
20054
+ )
20055
+ ) : null
20056
+ ]
20057
+ }
20058
+ ),
20059
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20060
+ /* @__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)(
20061
+ "button",
20062
+ {
20063
+ type: "button",
20064
+ "aria-pressed": formViewState === state,
20065
+ 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"),
20066
+ onClick: () => {
20067
+ setFieldTypePickerOpen(false);
20068
+ const form = formPickElRef.current;
20069
+ const key = form ? formKeyOf(form) : null;
20070
+ if (!form || !key) return;
20071
+ const initial = successInitialFor(form, key, editContentRef.current);
20072
+ setFormViewState(form, key, state, initial);
20073
+ setFormViewStateUi(state);
20074
+ setFormPickRect(form.getBoundingClientRect());
20075
+ if (state === "success") {
20076
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20077
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20078
+ } else {
20079
+ deactivateRef.current();
20080
+ }
20081
+ },
20082
+ children: state
20083
+ },
20084
+ state
20085
+ )) })
20086
+ ]
20087
+ }
20088
+ )
20089
+ }
20090
+ ),
20091
+ formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20092
+ ItemInteractionLayer,
20093
+ {
20094
+ rect: formHoverRect,
20095
+ state: "hover",
20096
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20097
+ }
20098
+ ),
20099
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20100
+ ItemInteractionLayer,
20101
+ {
20102
+ rect: fieldPickRect,
20103
+ state: fieldDragging ? "dragging" : "active-top",
20104
+ itemDragSurface: false,
20105
+ toolbarAlign: "left",
20106
+ chromeGap: 10,
20107
+ showHandle: true,
20108
+ dragHandleLabel: "Reorder field",
20109
+ onDragHandleDragStart: handleFieldDragStart,
20110
+ onDragHandleDragEnd: handleFieldDragEnd,
20111
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20112
+ FormFieldToolbar,
21481
20113
  {
21482
- rect: toolbarRect,
21483
- elRef: glowElRef,
21484
- reorderHrefKey,
21485
- dragDisabled: reorderDragDisabled,
21486
- hideHandle: isItemDragging
20114
+ type: fieldPickState.type,
20115
+ required: fieldPickState.required,
20116
+ onTypeChange: handleFieldTypeChange,
20117
+ onRequiredToggle: handleFieldRequiredToggle,
20118
+ onDuplicate: handleFieldDuplicate,
20119
+ onDelete: handleFieldDelete
21487
20120
  }
21488
- ),
21489
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21490
- FloatingToolbar,
20121
+ )
20122
+ }
20123
+ ),
20124
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20125
+ "div",
20126
+ {
20127
+ className: "pointer-events-none fixed z-[2147483644]",
20128
+ style: { top: slot.top, left: slot.left, width: slot.width },
20129
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20130
+ DropIndicator,
21491
20131
  {
21492
- rect: toolbarRect,
21493
- parentScroll: parentScrollRef.current,
21494
- elRef: toolbarElRef,
21495
- onCommand: handleCommand,
21496
- activeCommands,
21497
- showEditLink,
21498
- onEditLink: openLinkPopoverForActive
20132
+ direction: "horizontal",
20133
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20134
+ className: "!w-full"
21499
20135
  }
21500
20136
  )
21501
- ] }),
21502
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20137
+ },
20138
+ `field-drop-${i}`
20139
+ )) : null,
20140
+ fieldTypePickerOpen && formPickRect ? (() => {
20141
+ const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20142
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21503
20143
  "div",
21504
20144
  {
21505
- "data-ohw-max-badge": "",
20145
+ className: "pointer-events-none fixed z-[2147483645]",
21506
20146
  style: {
21507
- position: "fixed",
21508
- top: maxBadge.rect.bottom + 4,
21509
- left: maxBadge.rect.right,
21510
- transform: "translateX(-100%)",
21511
- zIndex: 2147483647,
21512
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
21513
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
21514
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
21515
- borderRadius: 4,
21516
- padding: "2px 6px",
21517
- fontSize: 11,
21518
- fontWeight: 500,
21519
- pointerEvents: "none"
20147
+ top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20148
+ left: toolbar ? toolbar.left : formPickRect.left + 24
21520
20149
  },
21521
- children: [
21522
- maxBadge.current,
21523
- "/",
21524
- maxBadge.max
21525
- ]
20150
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
21526
20151
  }
21527
- ),
21528
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21529
- StateToggle,
20152
+ );
20153
+ })() : null,
20154
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20155
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20156
+ FooterContainerChrome,
20157
+ {
20158
+ rect: toolbarRect,
20159
+ onAdd: handleAddFooterColumn,
20160
+ addDisabled: !canAddFooterColumn()
20161
+ }
20162
+ ),
20163
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20164
+ ItemInteractionLayer,
20165
+ {
20166
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20167
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20168
+ elRef: glowElRef,
20169
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20170
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20171
+ dragDisabled: reorderDragDisabled,
20172
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20173
+ onDragHandleDragStart: handleItemDragStart,
20174
+ onDragHandleDragEnd: handleItemDragEnd,
20175
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20176
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20177
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
20178
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20179
+ ItemActionToolbar,
20180
+ {
20181
+ onEditLink: openLinkPopoverForSelected,
20182
+ onStyle: () => {
20183
+ const row = selectedElRef.current;
20184
+ if (!row) return;
20185
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20186
+ else openSocialsDisplayPanel(row);
20187
+ },
20188
+ showStyle: selectedIsSocialsRow,
20189
+ styleActive: floatingPanel?.kind === "socials-display",
20190
+ onAddItem: handleAddChildItem,
20191
+ onSelectParent: handleSelectParent,
20192
+ onDuplicate: handleDuplicateSelected,
20193
+ onDelete: handleDeleteSelected,
20194
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20195
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20196
+ return row ? !canAddSocialItem(row) : false;
20197
+ })(),
20198
+ editLinkDisabled: false,
20199
+ moreDisabled: false,
20200
+ deleteDisabled: selectedElRef.current !== null && (() => {
20201
+ const social = getSocialItem(selectedElRef.current);
20202
+ return social ? !canRemoveSocialItem(social) : false;
20203
+ })(),
20204
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
20205
+ const social = getSocialItem(selectedElRef.current);
20206
+ const row = social ? findSocialsRow(social) : null;
20207
+ return row ? !canAddSocialItem(row) : false;
20208
+ })(),
20209
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20210
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20211
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
20212
+ ),
20213
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20214
+ dropdownOpen: navDropdownPreviewOpen,
20215
+ onDropdownOpenChange: handleNavDropdownOpenChange,
20216
+ headingVisible: footerHeadingVisible,
20217
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
20218
+ }
20219
+ ) : void 0
20220
+ }
20221
+ ),
20222
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20223
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20224
+ EditGlowChrome,
21530
20225
  {
21531
- rect: toggleState.rect,
21532
- activeState: toggleState.activeState,
21533
- states: toggleState.states,
21534
- onStateChange: handleStateChange
20226
+ rect: toolbarRect,
20227
+ elRef: glowElRef,
20228
+ reorderHrefKey,
20229
+ dragDisabled: reorderDragDisabled,
20230
+ hideHandle: isItemDragging
21535
20231
  }
21536
20232
  ),
21537
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21538
- "div",
20233
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20234
+ FloatingToolbar,
21539
20235
  {
21540
- "data-ohw-section-insert-line": "",
21541
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
21542
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
21543
- children: [
21544
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
21545
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21546
- Badge,
21547
- {
21548
- 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",
21549
- onClick: () => {
21550
- window.parent.postMessage(
21551
- {
21552
- type: "ow:add-section",
21553
- insertAfter: sectionGap.insertAfter,
21554
- insertBefore: sectionGap.insertBefore
21555
- },
21556
- "*"
21557
- );
21558
- },
21559
- children: "Add Section"
21560
- }
21561
- ),
21562
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
21563
- ]
20236
+ rect: toolbarRect,
20237
+ parentScroll: parentScrollRef.current,
20238
+ elRef: toolbarElRef,
20239
+ onCommand: handleCommand,
20240
+ activeCommands,
20241
+ showEditLink,
20242
+ onEditLink: openLinkPopoverForActive
21564
20243
  }
21565
- ),
21566
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21567
- LinkPopover,
21568
- {
21569
- panelRef: linkPopoverPanelRef,
21570
- portalContainer: dialogPortalContainer,
21571
- open: true,
21572
- mode: linkPopover.mode ?? "edit",
21573
- pages: sitePages,
21574
- sections: currentSections,
21575
- sectionsByPath,
21576
- initialTarget: linkPopover.target,
21577
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21578
- onClose: closeLinkPopover,
21579
- onSubmit: handleLinkPopoverSubmit
20244
+ )
20245
+ ] }),
20246
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20247
+ "div",
20248
+ {
20249
+ "data-ohw-max-badge": "",
20250
+ style: {
20251
+ position: "fixed",
20252
+ top: maxBadge.rect.bottom + 4,
20253
+ left: maxBadge.rect.right,
20254
+ transform: "translateX(-100%)",
20255
+ zIndex: 2147483647,
20256
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20257
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20258
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20259
+ borderRadius: 4,
20260
+ padding: "2px 6px",
20261
+ fontSize: 11,
20262
+ fontWeight: 500,
20263
+ pointerEvents: "none"
21580
20264
  },
21581
- linkPopover.key
21582
- ) : null,
21583
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21584
- FloatingPanel,
21585
- {
21586
- open: true,
21587
- title: floatingPanel.title,
21588
- context: floatingPanel.context,
21589
- position: floatingPanelPos,
21590
- onPositionChange: setFloatingPanelPos,
21591
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21592
- onClose: closeFloatingPanelOnly,
21593
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21594
- SocialsDisplayPanel,
20265
+ children: [
20266
+ maxBadge.current,
20267
+ "/",
20268
+ maxBadge.max
20269
+ ]
20270
+ }
20271
+ ),
20272
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20273
+ StateToggle,
20274
+ {
20275
+ rect: toggleState.rect,
20276
+ activeState: toggleState.activeState,
20277
+ states: toggleState.states,
20278
+ onStateChange: handleStateChange
20279
+ }
20280
+ ),
20281
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20282
+ "div",
20283
+ {
20284
+ "data-ohw-section-insert-line": "",
20285
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20286
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
20287
+ children: [
20288
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20289
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20290
+ Badge,
21595
20291
  {
21596
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21597
- onChange: (next) => {
21598
- changeSocialsDisplay(floatingPanel.row, next);
21599
- setFloatingPanel({ ...floatingPanel });
21600
- }
20292
+ 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",
20293
+ onClick: () => {
20294
+ window.parent.postMessage(
20295
+ {
20296
+ type: "ow:add-section",
20297
+ insertAfter: sectionGap.insertAfter,
20298
+ insertBefore: sectionGap.insertBefore
20299
+ },
20300
+ "*"
20301
+ );
20302
+ },
20303
+ children: "Add Section"
21601
20304
  }
21602
- )
21603
- }
21604
- ) : null
21605
- ] }),
21606
- bridgeRoot
21607
- ) : null
21608
- ] });
21609
- }
21610
-
21611
- // src/ui/EmptySection.tsx
21612
- var import_link = __toESM(require("next/link"), 1);
21613
- var import_jsx_runtime34 = require("react/jsx-runtime");
21614
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21615
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
21616
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21617
- "p",
21618
- {
21619
- style: {
21620
- fontFamily: "var(--brand-font-body)",
21621
- fontSize: "0.75rem",
21622
- fontWeight: 500,
21623
- letterSpacing: "0.15em",
21624
- textTransform: "uppercase",
21625
- color: "var(--brand-accent)",
21626
- marginBottom: "1.5rem"
21627
- },
21628
- 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" }) })
21629
- }
21630
- ),
21631
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21632
- "h1",
21633
- {
21634
- style: {
21635
- fontFamily: "var(--brand-font-heading)",
21636
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21637
- lineHeight: 1.1,
21638
- letterSpacing: "-0.025em",
21639
- color: "var(--brand-text)",
21640
- marginBottom: "1rem"
21641
- },
21642
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21643
- children: title
21644
- }
21645
- ),
21646
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21647
- "p",
21648
- {
21649
- style: {
21650
- fontFamily: "var(--brand-font-body)",
21651
- fontSize: "1rem",
21652
- lineHeight: 1.7,
21653
- fontWeight: 300,
21654
- color: "var(--brand-text-muted)",
21655
- maxWidth: "340px"
20305
+ ),
20306
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20307
+ ]
20308
+ }
20309
+ ),
20310
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20311
+ LinkPopover,
20312
+ {
20313
+ panelRef: linkPopoverPanelRef,
20314
+ portalContainer: dialogPortalContainer,
20315
+ open: true,
20316
+ mode: linkPopover.mode ?? "edit",
20317
+ pages: sitePages,
20318
+ sections: currentSections,
20319
+ sectionsByPath,
20320
+ initialTarget: linkPopover.target,
20321
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
20322
+ onClose: closeLinkPopover,
20323
+ onSubmit: handleLinkPopoverSubmit
21656
20324
  },
21657
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21658
- children: "This page doesn't have any content yet."
21659
- }
21660
- )
21661
- ] });
20325
+ linkPopover.key
20326
+ ) : null,
20327
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20328
+ FloatingPanel,
20329
+ {
20330
+ open: true,
20331
+ title: floatingPanel.title,
20332
+ context: floatingPanel.context,
20333
+ position: floatingPanelPos,
20334
+ onPositionChange: setFloatingPanelPos,
20335
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
20336
+ onClose: closeFloatingPanelOnly,
20337
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20338
+ SocialsDisplayPanel,
20339
+ {
20340
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
20341
+ onChange: (next) => {
20342
+ changeSocialsDisplay(floatingPanel.row, next);
20343
+ setFloatingPanel({ ...floatingPanel });
20344
+ }
20345
+ }
20346
+ )
20347
+ }
20348
+ ) : null
20349
+ ] }),
20350
+ bridgeRoot
20351
+ ) : null;
21662
20352
  }
21663
20353
  // Annotate the CommonJS export names for ESM import in node:
21664
20354
  0 && (module.exports = {
@@ -21677,7 +20367,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
21677
20367
  DropdownMenuItem,
21678
20368
  DropdownMenuSeparator,
21679
20369
  DropdownMenuTrigger,
21680
- EmptySection,
21681
20370
  ItemActionToolbar,
21682
20371
  ItemInteractionLayer,
21683
20372
  LinkEditorPanel,