@ohhwells/bridge 0.1.71-next.218 → 0.1.72

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" },
@@ -1293,44 +922,13 @@ function AccordionBlock({ node, ctx, path }) {
1293
922
  ) })
1294
923
  ] }, i)) });
1295
924
  }
1296
- function useIsMobile() {
1297
- const [mobile, setMobile] = import_react.default.useState(
1298
- () => typeof window !== "undefined" && window.matchMedia("(max-width: 768px)").matches
1299
- );
1300
- import_react.default.useEffect(() => {
1301
- const mq = window.matchMedia("(max-width: 768px)");
1302
- const update = () => setMobile(mq.matches);
1303
- update();
1304
- mq.addEventListener("change", update);
1305
- return () => mq.removeEventListener("change", update);
1306
- }, []);
1307
- return mobile;
1308
- }
1309
925
  function Carousel({ items, itemsPerRow, ctx }) {
1310
- const isMobile = useIsMobile();
1311
- const perPage = isMobile ? 1 : itemsPerRow;
1312
- const pages = Math.max(1, Math.ceil(items.length / perPage));
1313
926
  const [page, setPage] = import_react.default.useState(0);
927
+ const pages = Math.max(1, Math.ceil(items.length / itemsPerRow));
1314
928
  const current = Math.min(page, pages - 1);
1315
- if (pages <= 1) {
1316
- const cols = Math.max(1, Math.min(items.length, itemsPerRow));
1317
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1318
- "div",
1319
- {
1320
- "data-ai-grid": String(cols),
1321
- style: {
1322
- display: "grid",
1323
- gridTemplateColumns: `repeat(${cols}, 1fr)`,
1324
- gap: AI_TREE_TOKENS.spacing8,
1325
- alignItems: "start"
1326
- },
1327
- children: items
1328
- }
1329
- );
1330
- }
1331
929
  const pageGroups = Array.from(
1332
930
  { length: pages },
1333
- (_, p) => items.slice(p * perPage, (p + 1) * perPage)
931
+ (_, p) => items.slice(p * itemsPerRow, (p + 1) * itemsPerRow)
1334
932
  );
1335
933
  const chrome = (enabled) => ({
1336
934
  border: `1px solid ${ctx.brand.palette.dark}`,
@@ -1355,69 +953,55 @@ function Carousel({ items, itemsPerRow, ctx }) {
1355
953
  cursor: "pointer",
1356
954
  padding: 0
1357
955
  });
1358
- const viewport = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: isMobile ? "0 0 auto" : 1, minWidth: 0, width: "100%", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1359
- "div",
1360
- {
1361
- style: {
1362
- display: "flex",
1363
- transform: `translateX(-${current * 100}%)`,
1364
- transition: "transform 0.4s ease"
1365
- },
1366
- children: pageGroups.map((group, p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
956
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing8, alignItems: "center" }, children: [
957
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: AI_TREE_TOKENS.spacing6, width: "100%" }, children: [
958
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
959
+ "button",
960
+ {
961
+ type: "button",
962
+ "aria-label": "Previous",
963
+ onClick: () => setPage((p) => Math.max(0, p - 1)),
964
+ style: chrome(current > 0),
965
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
966
+ }
967
+ ),
968
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1367
969
  "div",
1368
970
  {
1369
- "data-ai-grid": String(perPage),
1370
971
  style: {
1371
- flex: "0 0 100%",
1372
- display: "grid",
1373
- gridTemplateColumns: `repeat(${perPage}, 1fr)`,
1374
- gap: AI_TREE_TOKENS.spacing8,
1375
- alignItems: "start"
972
+ display: "flex",
973
+ transform: `translateX(-${current * 100}%)`,
974
+ transition: "transform 0.4s ease"
1376
975
  },
1377
- children: group
1378
- },
1379
- p
1380
- ))
1381
- }
1382
- ) });
1383
- const prevBtn = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1384
- "button",
1385
- {
1386
- type: "button",
1387
- "aria-label": "Previous",
1388
- onClick: () => setPage((p) => Math.max(0, p - 1)),
1389
- style: chrome(current > 0),
1390
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowLeft, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
1391
- }
1392
- );
1393
- const nextBtn = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1394
- "button",
1395
- {
1396
- type: "button",
1397
- "aria-label": "Next",
1398
- onClick: () => setPage((p) => Math.min(pages - 1, p + 1)),
1399
- style: chrome(current < pages - 1),
1400
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
1401
- }
1402
- );
1403
- const dots = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 9, justifyContent: "center" }, children: pageGroups.map((_, p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", "aria-label": `Page ${p + 1}`, onClick: () => setPage(p), style: dot(p === current) }, p)) });
1404
- if (isMobile) {
1405
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing6, alignItems: "center" }, children: [
1406
- viewport,
1407
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: AI_TREE_TOKENS.spacing6, justifyContent: "center" }, children: [
1408
- prevBtn,
1409
- nextBtn
1410
- ] }),
1411
- dots
1412
- ] });
1413
- }
1414
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-ai-carousel": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing8, alignItems: "center" }, children: [
1415
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: AI_TREE_TOKENS.spacing6, width: "100%" }, children: [
1416
- prevBtn,
1417
- viewport,
1418
- nextBtn
976
+ children: pageGroups.map((group, p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
977
+ "div",
978
+ {
979
+ "data-ai-grid": String(itemsPerRow),
980
+ style: {
981
+ flex: "0 0 100%",
982
+ display: "grid",
983
+ gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
984
+ gap: AI_TREE_TOKENS.spacing8,
985
+ alignItems: "start"
986
+ },
987
+ children: group
988
+ },
989
+ p
990
+ ))
991
+ }
992
+ ) }),
993
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
994
+ "button",
995
+ {
996
+ type: "button",
997
+ "aria-label": "Next",
998
+ onClick: () => setPage((p) => Math.min(pages - 1, p + 1)),
999
+ style: chrome(current < pages - 1),
1000
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { size: 24, strokeWidth: 1.5, "aria-hidden": true })
1001
+ }
1002
+ )
1419
1003
  ] }),
1420
- dots
1004
+ pages > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 9, justifyContent: "center" }, children: pageGroups.map((_, p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", "aria-label": `Page ${p + 1}`, onClick: () => setPage(p), style: dot(p === current) }, p)) })
1421
1005
  ] });
1422
1006
  }
1423
1007
  function CollectionBlock({ node, ctx, path }) {
@@ -1511,49 +1095,6 @@ function renderNode(node, ctx, path) {
1511
1095
  switch (node.type) {
1512
1096
  case "text":
1513
1097
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextBlock, { slots, ctx, path });
1514
- // Layout container: arranges child blocks, contributes no content of its own. `grid` is a
1515
- // nested 12-column grid the children span (a collage is 3–5 media on it, bottom-aligned so
1516
- // mixed aspects read as a composition); `split` is exactly two children at a ratio; `stack`
1517
- // is a column. Children render through this same dispatcher, so edit markers, media
1518
- // resolution, and copy paths all work unchanged inside a group.
1519
- case "group": {
1520
- const layout = str(slots.layout);
1521
- const gap = slots.spacing === "tight" ? AI_TREE_TOKENS.spacing3 : slots.spacing === "airy" ? AI_TREE_TOKENS.spacing8 : AI_TREE_TOKENS.spacing6;
1522
- const kids = (node.children ?? []).map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1523
- "div",
1524
- {
1525
- style: layout === "grid" ? {
1526
- gridColumn: `span ${typeof child.span === "number" ? Math.min(12, Math.max(1, child.span)) : 12}`,
1527
- minWidth: 0
1528
- } : { minWidth: 0 },
1529
- children: renderNode(child, ctx, `${path}.c${i}`)
1530
- },
1531
- i
1532
- ));
1533
- if (layout === "grid") {
1534
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1535
- "div",
1536
- {
1537
- "data-ai-group": "grid",
1538
- style: { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap, alignItems: "end" },
1539
- children: kids
1540
- }
1541
- );
1542
- }
1543
- if (layout === "split") {
1544
- const ratio = str(slots.ratio);
1545
- const cols = ratio === "3:5" ? "3fr 5fr" : ratio === "5:3" ? "5fr 3fr" : "1fr 1fr";
1546
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1547
- "div",
1548
- {
1549
- "data-ai-group": "split",
1550
- style: { display: "grid", gridTemplateColumns: cols, gap, alignItems: "center" },
1551
- children: kids
1552
- }
1553
- );
1554
- }
1555
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-ai-group": "stack", style: { display: "flex", flexDirection: "column", gap }, children: kids });
1556
- }
1557
1098
  case "button":
1558
1099
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonEl, { slots, ctx, path });
1559
1100
  case "button-row":
@@ -1634,81 +1175,33 @@ function renderNode(node, ctx, path) {
1634
1175
  }
1635
1176
  );
1636
1177
  }
1637
- case "form": {
1638
- const formAttrs = ctx.keyFor ? {
1639
- "data-ohw-editable": "form",
1640
- "data-ohw-key": ctx.keyFor(`${path}.form`),
1641
- "data-ohw-success-text": "Thanks \u2014 we'll be in touch shortly."
1642
- } : {};
1643
- const fieldStyle = {
1644
- width: "100%",
1645
- boxSizing: "border-box",
1646
- border: `1px solid ${ctx.brand.palette.accent}`,
1647
- borderRadius: AI_TREE_TOKENS.radiusButton,
1648
- padding: "12px 14px",
1649
- background: "#fff",
1650
- color: ctx.brand.palette.dark,
1651
- outline: "none",
1652
- ...typeStyle(AI_TREE_TOKENS.type.bodyM, ctx.brand.fonts.body)
1653
- };
1654
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("form", { ...formAttrs, style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing4 }, children: (node.children ?? []).map((child, i) => {
1178
+ case "form":
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing4 }, children: (node.children ?? []).map((child, i) => {
1655
1180
  if (child.type === "input") {
1656
- const cs2 = child.slots ?? {};
1657
- const kind = str(cs2.kind);
1658
- const label = str(cs2.label);
1659
- const placeholder = str(cs2.placeholder);
1660
- const name = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "") || `field-${i}`;
1661
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1181
+ const cs = child.slots ?? {};
1182
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1662
1183
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1663
- "label",
1184
+ "div",
1664
1185
  {
1665
1186
  ...textAttrs(ctx, `${path}.c${i}.label`),
1666
- style: {
1667
- ...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body),
1668
- color: ctx.brand.palette.dark
1669
- },
1670
- children: label
1187
+ style: { ...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body), color: ctx.brand.palette.dark, marginBottom: 6 },
1188
+ children: str(cs.label)
1671
1189
  }
1672
1190
  ),
1673
- kind === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1674
- "textarea",
1675
- {
1676
- name,
1677
- placeholder,
1678
- style: { ...fieldStyle, height: 140, resize: "vertical" }
1679
- }
1680
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1681
- "input",
1191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1192
+ "div",
1682
1193
  {
1683
- name,
1684
- type: kind === "email" ? "email" : "text",
1685
- placeholder,
1686
- style: { ...fieldStyle, height: 48 }
1194
+ style: {
1195
+ border: `1px solid ${ctx.brand.palette.accent}`,
1196
+ borderRadius: AI_TREE_TOKENS.radiusButton,
1197
+ height: cs.kind === "textarea" ? 96 : 42
1198
+ }
1687
1199
  }
1688
1200
  )
1689
1201
  ] }, i);
1690
1202
  }
1691
- const cs = child.slots ?? {};
1692
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1693
- "button",
1694
- {
1695
- type: "submit",
1696
- style: {
1697
- alignSelf: "flex-start",
1698
- border: "none",
1699
- cursor: "pointer",
1700
- padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
1701
- borderRadius: AI_TREE_TOKENS.radiusButton,
1702
- background: ctx.brand.palette.primary,
1703
- color: AI_TREE_TOKENS.textPrimaryForeground,
1704
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
1705
- },
1706
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
1707
- },
1708
- i
1709
- );
1203
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }) }, i);
1710
1204
  }) });
1711
- }
1712
1205
  case "schedule-widget":
1713
1206
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1714
1207
  "div",
@@ -1734,14 +1227,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1734
1227
  return null;
1735
1228
  }
1736
1229
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1737
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1738
- const blockBrand = band?.brand ?? resolvedBrand;
1739
1230
  const ctx = {
1740
- brand: blockBrand,
1231
+ brand: resolvedBrand,
1741
1232
  resolveMedia: resolveMedia ?? (() => null),
1742
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1743
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1744
- ...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
1745
1235
  };
1746
1236
  const settings = tree.settings ?? {};
1747
1237
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1749,20 +1239,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1749
1239
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1750
1240
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1751
1241
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1752
- const toneBackground = (() => {
1753
- const { dark, primary, light } = resolvedBrand.palette;
1754
- switch (settings.sectionBackground) {
1755
- case "surface":
1756
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1757
- case "accent":
1758
- return primary;
1759
- case "accent-soft":
1760
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1761
- default:
1762
- return void 0;
1763
- }
1764
- })();
1765
- const distributed = !isOverlay && settings.textDistribution;
1766
1242
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1767
1243
  "section",
1768
1244
  {
@@ -1772,11 +1248,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1772
1248
  style: {
1773
1249
  position: "relative",
1774
1250
  padding: `${pad}px 0`,
1775
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1251
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1776
1252
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1777
1253
  backgroundSize: "cover",
1778
- backgroundPosition: "center",
1779
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1254
+ backgroundPosition: "center"
1780
1255
  },
1781
1256
  children: [
1782
1257
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
@@ -1800,24 +1275,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1800
1275
  display: "grid",
1801
1276
  gridTemplateColumns: "repeat(12, 1fr)",
1802
1277
  gap: AI_TREE_TOKENS.spacing6,
1803
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1278
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1804
1279
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1805
1280
  },
1806
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1807
- "div",
1808
- {
1809
- "data-ai-cell": "",
1810
- style: {
1811
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1812
- minWidth: 0,
1813
- // space-between: each column becomes a flex column whose content spreads over
1814
- // the full row height instead of clumping at the top.
1815
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1816
- },
1817
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1818
- },
1819
- b
1820
- ))
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))
1821
1282
  },
1822
1283
  r2
1823
1284
  ))
@@ -1833,36 +1294,17 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1833
1294
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1834
1295
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1835
1296
  var REMOVED_ATTR = "data-ohw-ai-removed";
1836
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1837
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1838
- function readRootVar(name) {
1839
- if (typeof document === "undefined") return "";
1840
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1841
- }
1842
- function deriveBrandOverride() {
1843
- const dark = readRootVar("--ohw-brand-dark");
1844
- const primary = readRootVar("--ohw-brand-primary");
1845
- const light = readRootVar("--ohw-brand-light");
1846
- if (!dark || !primary || !light) return null;
1847
- const accent = readRootVar("--ohw-brand-accent");
1848
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1849
- const body = readRootVar("--font-body");
1850
- return {
1851
- palette: { dark, primary, accent: accent || dark, light },
1852
- fonts: {
1853
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1854
- body: body || AI_DEFAULT_BRAND.fonts.body
1855
- }
1856
- };
1857
- }
1858
1297
  function deriveTemplateBrand() {
1859
- const dark = readRootVar("--color-dark");
1860
- const primary = readRootVar("--color-primary");
1861
- 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");
1862
1304
  if (!dark || !primary || !light) return null;
1863
- const accent = readRootVar("--color-accent");
1864
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1865
- 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");
1866
1308
  return {
1867
1309
  palette: { dark, primary, accent: accent || dark, light },
1868
1310
  fonts: {
@@ -1934,24 +1376,6 @@ function syncRemovedSections(state) {
1934
1376
  }
1935
1377
  }
1936
1378
  }
1937
- function syncTemplateHidden(state, pageHasSections) {
1938
- const hide = state.hideTemplate === true && pageHasSections;
1939
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1940
- if (!hide) {
1941
- el.style.removeProperty("display");
1942
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1943
- }
1944
- }
1945
- if (!hide) return;
1946
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1947
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1948
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1949
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1950
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1951
- el.style.display = "none";
1952
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1953
- }
1954
- }
1955
1379
  function syncReplacedOriginals(state) {
1956
1380
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1957
1381
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1970,40 +1394,10 @@ function syncReplacedOriginals(state) {
1970
1394
  }
1971
1395
  }
1972
1396
  }
1973
- function orderByChain(sections) {
1974
- const ids = new Set(sections.map((entry) => entry.id));
1975
- const after = /* @__PURE__ */ new Map();
1976
- const roots = [];
1977
- for (const entry of sections) {
1978
- const anchor = entry.replaces ?? entry.beforeSection ?? entry.afterSection ?? null;
1979
- if (anchor && ids.has(anchor)) {
1980
- const bucket = after.get(anchor);
1981
- if (bucket) bucket.push(entry);
1982
- else after.set(anchor, [entry]);
1983
- } else {
1984
- roots.push(entry);
1985
- }
1986
- }
1987
- const out = [];
1988
- const seen = /* @__PURE__ */ new Set();
1989
- const visit = (entry) => {
1990
- if (seen.has(entry.id)) return;
1991
- seen.add(entry.id);
1992
- out.push(entry);
1993
- for (const child of after.get(entry.id) ?? []) visit(child);
1994
- };
1995
- for (const root of roots) visit(root);
1996
- return out.length === sections.length ? out : sections;
1997
- }
1998
1397
  function applyAiSectionsToDom(state, options) {
1999
1398
  if (typeof document === "undefined") return;
2000
- const brandOverride = deriveBrandOverride();
2001
1399
  const templateBrand = deriveTemplateBrand();
2002
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
2003
- const pagePath = window.location.pathname;
2004
- const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
2005
- const activeIds = new Set(pageSections.map((entry) => entry.id));
2006
- const ordered = state.hideTemplate === true ? orderByChain(pageSections) : pageSections;
1400
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
2007
1401
  for (const [id, section] of mounted) {
2008
1402
  if (!activeIds.has(id)) {
2009
1403
  section.root.unmount();
@@ -2011,8 +1405,8 @@ function applyAiSectionsToDom(state, options) {
2011
1405
  mounted.delete(id);
2012
1406
  }
2013
1407
  }
2014
- for (const entry of ordered) {
2015
- const serialized = JSON.stringify(entry) + brandKey;
1408
+ for (const entry of state.sections) {
1409
+ const serialized = JSON.stringify(entry);
2016
1410
  const existing = mounted.get(entry.id);
2017
1411
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
2018
1412
  continue;
@@ -2026,7 +1420,6 @@ function applyAiSectionsToDom(state, options) {
2026
1420
  mounted.delete(entry.id);
2027
1421
  }
2028
1422
  container.setAttribute("data-ohw-section", entry.id);
2029
- container.setAttribute("data-ohw-instance", entry.id);
2030
1423
  container.setAttribute("data-ohw-section-label", entry.label);
2031
1424
  placeContainer(container, entry);
2032
1425
  const root = mounted.get(entry.id)?.root ?? (0, import_client.createRoot)(container);
@@ -2037,7 +1430,7 @@ function applyAiSectionsToDom(state, options) {
2037
1430
  AiTreeRenderer,
2038
1431
  {
2039
1432
  tree: entry.tree,
2040
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1433
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
2041
1434
  resolveMedia,
2042
1435
  editKeyPrefix: `ai.${entry.id}`
2043
1436
  }
@@ -2046,20 +1439,8 @@ function applyAiSectionsToDom(state, options) {
2046
1439
  });
2047
1440
  mounted.set(entry.id, { root, container, serialized });
2048
1441
  }
2049
- if (state.hideTemplate === true) {
2050
- let prev = null;
2051
- for (const entry of ordered) {
2052
- const el = mounted.get(entry.id)?.container;
2053
- if (!el) continue;
2054
- if (prev && !(prev.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) {
2055
- prev.insertAdjacentElement("afterend", el);
2056
- }
2057
- prev = el;
2058
- }
2059
- }
2060
1442
  syncReplacedOriginals(state);
2061
1443
  syncRemovedSections(state);
2062
- syncTemplateHidden(state, pageSections.length > 0);
2063
1444
  }
2064
1445
 
2065
1446
  // src/useLinkHrefGuardian.ts
@@ -2666,7 +2047,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2666
2047
  const autoId = (0, import_react5.useId)();
2667
2048
  const insertAfter = insertAfterProp ?? autoId;
2668
2049
  const [schedule, setSchedule] = (0, import_react5.useState)(null);
2669
- const [loading, setLoading] = (0, import_react5.useState)(initialScheduleId !== null);
2050
+ const [loading, setLoading] = (0, import_react5.useState)(true);
2670
2051
  const [inEditor, setInEditor] = (0, import_react5.useState)(false);
2671
2052
  const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
2672
2053
  const [modalState, setModalState] = (0, import_react5.useState)(null);
@@ -2840,10 +2221,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2840
2221
  "*"
2841
2222
  );
2842
2223
  };
2224
+ if (!inEditor && !loading && !schedule) return null;
2843
2225
  const sectionId = `scheduling-${insertAfter}`;
2844
- if (!inEditor && !loading && !schedule) {
2845
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2846
- }
2847
2226
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2848
2227
  "section",
2849
2228
  {
@@ -7760,17 +7139,13 @@ function MediaOverlay({
7760
7139
  hover,
7761
7140
  isUploading,
7762
7141
  fadingOut = false,
7763
- selected = false,
7764
- hovered = false,
7765
7142
  onFadeOutComplete,
7766
7143
  onReplace,
7767
- onSelect,
7768
7144
  onVideoSettingsChange
7769
7145
  }) {
7770
7146
  const { rect } = hover;
7771
7147
  const skeletonRef = React8.useRef(null);
7772
7148
  const isVideo = hover.elementType === "video";
7773
- const showChrome = !selected || hovered;
7774
7149
  const autoplay = hover.videoAutoplay ?? true;
7775
7150
  const muted = hover.videoMuted ?? true;
7776
7151
  const probeRef = React8.useRef(null);
@@ -7784,7 +7159,6 @@ function MediaOverlay({
7784
7159
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
7785
7160
  );
7786
7161
  }, [isVideo]);
7787
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
7788
7162
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
7789
7163
  const box = {
7790
7164
  position: "fixed",
@@ -7818,7 +7192,7 @@ function MediaOverlay({
7818
7192
  }
7819
7193
  );
7820
7194
  }
7821
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7195
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7822
7196
  "div",
7823
7197
  {
7824
7198
  "data-ohw-bridge": "",
@@ -7888,12 +7262,10 @@ function MediaOverlay({
7888
7262
  // in-document, pointer-events does it natively. The button below opts back in, so
7889
7263
  // Replace still works.
7890
7264
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7891
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7892
- // than hovered. Hover keeps the existing tinted preview.
7893
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7894
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7265
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7266
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7895
7267
  },
7896
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7268
+ onClick: () => onReplace(hover.key),
7897
7269
  children: [
7898
7270
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7899
7271
  Button,
@@ -7914,17 +7286,17 @@ function MediaOverlay({
7914
7286
  },
7915
7287
  children: [
7916
7288
  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 }),
7917
- replaceLabel
7289
+ isVideo ? "Replace video" : "Replace image"
7918
7290
  ]
7919
7291
  }
7920
7292
  ),
7921
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7293
+ replaceMode === "none" ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7922
7294
  Button,
7923
7295
  {
7924
7296
  "data-ohw-media-overlay": "",
7925
7297
  variant: "outline",
7926
7298
  size: "sm",
7927
- "aria-label": replaceLabel,
7299
+ "aria-label": isVideo ? "Replace video" : "Replace image",
7928
7300
  className: "gap-1.5 cursor-pointer hover:bg-background",
7929
7301
  style: {
7930
7302
  ...OVERLAY_BUTTON_STYLE,
@@ -7947,7 +7319,7 @@ function MediaOverlay({
7947
7319
  },
7948
7320
  children: [
7949
7321
  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 }),
7950
- replaceMode === "full" ? replaceLabel : null
7322
+ replaceMode === "full" ? isVideo ? "Replace video" : "Replace image" : null
7951
7323
  ]
7952
7324
  }
7953
7325
  )
@@ -8018,9 +7390,6 @@ var import_lucide_react7 = require("lucide-react");
8018
7390
 
8019
7391
  // src/lib/sections.ts
8020
7392
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
8021
- function isChromeSection(el) {
8022
- return el.matches("header, nav, footer, aside");
8023
- }
8024
7393
  function titleCaseSectionId(id) {
8025
7394
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
8026
7395
  }
@@ -8031,8 +7400,6 @@ function parseSectionsFromRoot(root) {
8031
7400
  const id = el.getAttribute("data-ohw-section") ?? "";
8032
7401
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
8033
7402
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
8034
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
8035
- continue;
8036
7403
  seen.add(id);
8037
7404
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
8038
7405
  sections.push({ id, label });
@@ -8048,169 +7415,21 @@ function parseSectionsFromHtml(html) {
8048
7415
  return parseSectionsFromRoot(doc);
8049
7416
  }
8050
7417
 
8051
- // src/lib/section-instances.ts
8052
- var SECTION_ORDER_KEY = "__ohw_section_order";
8053
- var REMOVED_ATTR2 = "data-ohw-section-removed";
8054
- function isRemovedSection(el) {
8055
- return el.hasAttribute(REMOVED_ATTR2);
8056
- }
8057
- function topLevelSections() {
8058
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8059
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el) && !isRemovedSection(el)
8060
- );
8061
- }
8062
- function instanceIdOf(el) {
8063
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8064
- }
8065
- function planSectionMove(instanceId, targetIndex, currentPath) {
8066
- const sections = topLevelSections();
8067
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8068
- if (index === -1) return null;
8069
- const dragged = sections[index];
8070
- const others = sections.filter((_, i) => i !== index);
8071
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8072
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8073
- return reordered.map((el, order) => ({
8074
- instanceId: instanceIdOf(el),
8075
- type: el.getAttribute("data-ohw-section") ?? "",
8076
- order,
8077
- pagePath: currentPath
8078
- }));
8079
- }
8080
- function moveSectionInstance(instanceId, direction, currentPath) {
8081
- const sections = topLevelSections();
8082
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8083
- if (index === -1) return null;
8084
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8085
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8086
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8087
- if (!entries) return null;
8088
- applyPersistedOrder(entries);
8089
- return entries;
8090
- }
8091
- function syncRemovedFlags(entries) {
8092
- const removedIds = new Set(entries.filter((e) => e.removed).map((e) => e.instanceId));
8093
- document.querySelectorAll(`[${REMOVED_ATTR2}]`).forEach((el) => {
8094
- if (!removedIds.has(instanceIdOf(el))) {
8095
- el.style.removeProperty("display");
8096
- el.removeAttribute(REMOVED_ATTR2);
8097
- }
8098
- });
8099
- for (const id of removedIds) {
8100
- const el = document.querySelector(`[data-ohw-instance="${CSS.escape(id)}"]`);
8101
- if (el) {
8102
- el.style.display = "none";
8103
- el.setAttribute(REMOVED_ATTR2, "");
8104
- }
8105
- }
8106
- }
8107
- function applyPersistedOrder(entries) {
8108
- syncRemovedFlags(entries);
8109
- if (entries.length === 0) return;
8110
- const sections = topLevelSections();
8111
- if (sections.length === 0) return;
8112
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8113
- const ordered = [...sections].sort((a, b) => {
8114
- const aOrder = orderIndex.get(instanceIdOf(a));
8115
- const bOrder = orderIndex.get(instanceIdOf(b));
8116
- if (aOrder === void 0 && bOrder === void 0) return 0;
8117
- if (aOrder === void 0) return 1;
8118
- if (bOrder === void 0) return -1;
8119
- return aOrder - bOrder;
8120
- });
8121
- let prev = null;
8122
- for (const el of ordered) {
8123
- if (prev) prev.after(el);
8124
- prev = el;
8125
- }
7418
+ // src/ui/ai-section/AiSectionOverlay.tsx
7419
+ var import_jsx_runtime17 = require("react/jsx-runtime");
7420
+ function readRect(sectionId) {
7421
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7422
+ if (!el) return null;
7423
+ const r2 = el.getBoundingClientRect();
7424
+ if (r2.width <= 0 || r2.height <= 0) return null;
7425
+ return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
8126
7426
  }
8127
- function setSectionRemoved(instanceId, currentPath, existingEntries, removed) {
8128
- if (!document.querySelector(`[data-ohw-instance="${CSS.escape(instanceId)}"]`)) return null;
8129
- const byId = new Map(existingEntries.map((e) => [e.instanceId, e]));
8130
- const allSections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8131
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8132
- );
8133
- allSections.forEach((el, order) => {
8134
- const id = instanceIdOf(el);
8135
- if (!byId.has(id)) {
8136
- byId.set(id, { instanceId: id, type: el.getAttribute("data-ohw-section") ?? "", order, pagePath: currentPath });
8137
- }
8138
- });
8139
- const target = byId.get(instanceId);
8140
- if (!target) return null;
8141
- byId.set(instanceId, { ...target, removed });
8142
- const entries = Array.from(byId.values());
8143
- applyPersistedOrder(entries);
8144
- return entries;
8145
- }
8146
- function deleteSectionInstance(instanceId, currentPath, existingEntries) {
8147
- return setSectionRemoved(instanceId, currentPath, existingEntries, true);
8148
- }
8149
- function restoreSectionInstance(instanceId, currentPath, existingEntries) {
8150
- return setSectionRemoved(instanceId, currentPath, existingEntries, false);
8151
- }
8152
- function newInstanceId() {
8153
- return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `instance-${Date.now()}-${Math.random().toString(36).slice(2)}`;
8154
- }
8155
- function getPageSectionOrderEntries(raw, currentPath) {
8156
- if (!raw) return [];
8157
- try {
8158
- const entries = JSON.parse(raw);
8159
- return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
8160
- } catch {
8161
- return [];
8162
- }
8163
- }
8164
- function rekeySectionSubtree(root, instanceId) {
8165
- const suffix = `::${instanceId}`;
8166
- const rekey = (el, attr) => {
8167
- const current = el.getAttribute(attr);
8168
- if (current) el.setAttribute(attr, `${current}${suffix}`);
8169
- };
8170
- if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
8171
- if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
8172
- root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
8173
- root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
8174
- }
8175
- function initSectionInstancesFromContent(content, currentPath) {
8176
- document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
8177
- el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
8178
- });
8179
- const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
8180
- for (const entry of entries) {
8181
- if (entry.instanceId === entry.type) continue;
8182
- if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
8183
- const original = document.querySelector(
8184
- `[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
8185
- );
8186
- if (!original) continue;
8187
- const clone = original.cloneNode(true);
8188
- clone.setAttribute("data-ohw-instance", entry.instanceId);
8189
- rekeySectionSubtree(clone, entry.instanceId);
8190
- original.insertAdjacentElement("afterend", clone);
8191
- }
8192
- applyPersistedOrder(entries);
8193
- }
8194
-
8195
- // src/ui/ai-section/AiSectionOverlay.tsx
8196
- var import_jsx_runtime17 = require("react/jsx-runtime");
8197
- function findSectionElement(instanceId) {
8198
- const escaped = CSS.escape(instanceId);
8199
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
8200
- }
8201
- function readRect(instanceId) {
8202
- const el = findSectionElement(instanceId);
8203
- if (!el) return null;
8204
- const r2 = el.getBoundingClientRect();
8205
- if (r2.width <= 0 || r2.height <= 0) return null;
8206
- return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
8207
- }
8208
- function useLiveSectionRect(sectionId) {
8209
- const [rect, setRect] = (0, import_react8.useState)(null);
8210
- (0, import_react8.useEffect)(() => {
8211
- if (!sectionId) {
8212
- setRect(null);
8213
- return;
7427
+ function useLiveSectionRect(sectionId) {
7428
+ const [rect, setRect] = (0, import_react8.useState)(null);
7429
+ (0, import_react8.useEffect)(() => {
7430
+ if (!sectionId) {
7431
+ setRect(null);
7432
+ return;
8214
7433
  }
8215
7434
  const update = () => {
8216
7435
  const next = readRect(sectionId);
@@ -8222,7 +7441,7 @@ function useLiveSectionRect(sectionId) {
8222
7441
  const opts = { capture: true, passive: true };
8223
7442
  window.addEventListener("scroll", update, opts);
8224
7443
  window.addEventListener("resize", update);
8225
- const el = findSectionElement(sectionId);
7444
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
8226
7445
  const ro = el ? new ResizeObserver(update) : null;
8227
7446
  if (el && ro) ro.observe(el);
8228
7447
  const interval = setInterval(update, 500);
@@ -8235,12 +7454,6 @@ function useLiveSectionRect(sectionId) {
8235
7454
  }, [sectionId]);
8236
7455
  return rect;
8237
7456
  }
8238
- function computeSectionBoundaryFlags(instanceId) {
8239
- const topLevel = topLevelSections();
8240
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
8241
- if (index === -1) return { isFirst: true, isLast: true };
8242
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
8243
- }
8244
7457
  var PRIMARY2 = "#0885FE";
8245
7458
  function edgeAwareRadius(rect) {
8246
7459
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -8314,7 +7527,6 @@ function AiSectionOverlay({
8314
7527
  }) {
8315
7528
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
8316
7529
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
8317
- const [reviewButtonsHidden, setReviewButtonsHidden] = (0, import_react8.useState)(false);
8318
7530
  const reviewIdRef = (0, import_react8.useRef)(null);
8319
7531
  reviewIdRef.current = reviewId;
8320
7532
  const selectedIdRef = (0, import_react8.useRef)(null);
@@ -8323,7 +7535,7 @@ function AiSectionOverlay({
8323
7535
  (el) => {
8324
7536
  postToParent2({
8325
7537
  type: "ow:section-selected",
8326
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7538
+ sectionId: el?.dataset.ohwSection ?? null,
8327
7539
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
8328
7540
  });
8329
7541
  },
@@ -8332,7 +7544,7 @@ function AiSectionOverlay({
8332
7544
  const selectFromElement = (0, import_react8.useCallback)(
8333
7545
  (el, options) => {
8334
7546
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
8335
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7547
+ const id = sectionEl?.dataset.ohwSection ?? null;
8336
7548
  if (id === selectedIdRef.current) return;
8337
7549
  setSelectedId(id);
8338
7550
  if (options?.report !== false) report(sectionEl);
@@ -8353,15 +7565,12 @@ function AiSectionOverlay({
8353
7565
  selectFromElement(sectionEl);
8354
7566
  return sectionEl != null;
8355
7567
  },
8356
- clear: () => {
8357
- setSelectedId(null);
8358
- report(null);
8359
- }
7568
+ clear: () => setSelectedId(null)
8360
7569
  };
8361
7570
  return () => {
8362
7571
  apiRef.current = null;
8363
7572
  };
8364
- }, [apiRef, selectFromElement, report]);
7573
+ }, [apiRef, selectFromElement]);
8365
7574
  (0, import_react8.useEffect)(() => {
8366
7575
  const onMessage = (e) => {
8367
7576
  if (e.data?.type === "ow:ai-select" && e.data.sectionId === null) {
@@ -8376,10 +7585,9 @@ function AiSectionOverlay({
8376
7585
  }
8377
7586
  const found = readRect(sectionId) != null;
8378
7587
  setReviewId(found ? sectionId : null);
8379
- setReviewButtonsHidden(e.data.hideButtons === true);
8380
7588
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
8381
7589
  if (found) {
8382
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7590
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
8383
7591
  }
8384
7592
  }
8385
7593
  };
@@ -8398,7 +7606,7 @@ function AiSectionOverlay({
8398
7606
  return;
8399
7607
  }
8400
7608
  const sec = t.closest("[data-ohw-section]");
8401
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7609
+ setHoveredId(sec?.dataset.ohwSection ?? null);
8402
7610
  };
8403
7611
  const onLeave = () => setHoveredId(null);
8404
7612
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -8430,30 +7638,9 @@ function AiSectionOverlay({
8430
7638
  },
8431
7639
  [postToParent2]
8432
7640
  );
8433
- const activeSelectionId = reviewId ? null : selectedId;
8434
- const selectionRect = useLiveSectionRect(activeSelectionId);
7641
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
8435
7642
  const reviewRect = useLiveSectionRect(reviewId);
8436
7643
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
8437
- (0, import_react8.useEffect)(() => {
8438
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
8439
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
8440
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
8441
- return;
8442
- }
8443
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
8444
- postToParent2({
8445
- type: "ow:section-rect",
8446
- instanceId: activeSelectionId,
8447
- rect: {
8448
- top: selectionRect.top + window.scrollY,
8449
- left: selectionRect.left + window.scrollX,
8450
- width: selectionRect.width,
8451
- height: selectionRect.height
8452
- },
8453
- isFirst,
8454
- isLast
8455
- });
8456
- }, [activeSelectionId, selectionRect, postToParent2]);
8457
7644
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8458
7645
  hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8459
7646
  "div",
@@ -8504,16 +7691,13 @@ function AiSectionOverlay({
8504
7691
  border: `2px solid ${PRIMARY2}`,
8505
7692
  borderRadius: edgeAwareRadius(reviewRect),
8506
7693
  zIndex: 2147483200,
8507
- // The veil itself: swallows clicks so the section stays locked until decided. This
8508
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8509
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8510
- // Accept/Discard resolves to the media beneath and opens the file picker.
7694
+ // The veil itself: swallows clicks so the section stays locked until decided.
8511
7695
  background: "rgba(8, 133, 254, 0.04)",
8512
7696
  pointerEvents: "auto",
8513
7697
  cursor: "default"
8514
7698
  },
8515
7699
  onClick: (e) => e.stopPropagation(),
8516
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7700
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8517
7701
  "div",
8518
7702
  {
8519
7703
  style: {
@@ -8536,6 +7720,47 @@ function AiSectionOverlay({
8536
7720
  ] });
8537
7721
  }
8538
7722
 
7723
+ // src/lib/section-instances.ts
7724
+ var SECTION_ORDER_KEY = "__ohw_section_order";
7725
+ function getPageSectionOrderEntries(raw, currentPath) {
7726
+ if (!raw) return [];
7727
+ try {
7728
+ const entries = JSON.parse(raw);
7729
+ return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
7730
+ } catch {
7731
+ return [];
7732
+ }
7733
+ }
7734
+ function rekeySectionSubtree(root, instanceId) {
7735
+ const suffix = `::${instanceId}`;
7736
+ const rekey = (el, attr) => {
7737
+ const current = el.getAttribute(attr);
7738
+ if (current) el.setAttribute(attr, `${current}${suffix}`);
7739
+ };
7740
+ if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
7741
+ if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
7742
+ root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
7743
+ root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
7744
+ }
7745
+ function initSectionInstancesFromContent(content, currentPath) {
7746
+ document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
7747
+ el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
7748
+ });
7749
+ const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
7750
+ for (const entry of entries) {
7751
+ if (entry.instanceId === entry.type) continue;
7752
+ if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
7753
+ const original = document.querySelector(
7754
+ `[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
7755
+ );
7756
+ if (!original) continue;
7757
+ const clone = original.cloneNode(true);
7758
+ clone.setAttribute("data-ohw-instance", entry.instanceId);
7759
+ rekeySectionSubtree(clone, entry.instanceId);
7760
+ original.insertAdjacentElement("afterend", clone);
7761
+ }
7762
+ }
7763
+
8539
7764
  // src/OhhwellsBridge.tsx
8540
7765
  var import_react_dom4 = require("react-dom");
8541
7766
  var import_navigation3 = require("next/navigation");
@@ -11080,13 +10305,8 @@ function referenceBox(slot) {
11080
10305
  const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find(
11081
10306
  (el) => el !== slot && !el.hasAttribute("data-ohw-social-icon-placeholder")
11082
10307
  ) : null;
11083
- if (neighbour) {
11084
- const box2 = neighbour.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect();
11085
- if (box2?.width && box2.height) return box2;
11086
- }
11087
- const own = slot.getBoundingClientRect();
11088
- if (own.width && own.height) return own;
11089
- const box = slot.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect() ?? null;
10308
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
10309
+ const box = source?.getBoundingClientRect() ?? null;
11090
10310
  return box?.width && box.height ? box : null;
11091
10311
  }
11092
10312
  function iconMarkupSizedFor(slot, markup) {
@@ -12887,7 +12107,6 @@ function readLogoSizeState(content, placement) {
12887
12107
  function getLogoElement(el) {
12888
12108
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12889
12109
  if (marked) return marked;
12890
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12891
12110
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12892
12111
  if (!root) return null;
12893
12112
  const anchor = el.closest("a");
@@ -13761,333 +12980,6 @@ function useNavItemDrag({
13761
12980
  };
13762
12981
  }
13763
12982
 
13764
- // src/useSectionDrag.ts
13765
- var import_react15 = require("react");
13766
-
13767
- // src/lib/section-dnd.ts
13768
- function isFooterSection(el) {
13769
- return el.dataset.ohwSection === "footer";
13770
- }
13771
- function buildSectionDropSlots(draggedInstanceId) {
13772
- const sections = topLevelSections().filter(
13773
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
13774
- );
13775
- const slots = [];
13776
- if (sections.length === 0) return slots;
13777
- const left = 0;
13778
- const width = document.documentElement.clientWidth;
13779
- for (let i = 0; i <= sections.length; i++) {
13780
- let y;
13781
- if (i === 0) {
13782
- y = sections[0].getBoundingClientRect().top;
13783
- } else if (i === sections.length) {
13784
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13785
- } else {
13786
- const prev = sections[i - 1].getBoundingClientRect();
13787
- const next = sections[i].getBoundingClientRect();
13788
- y = (prev.bottom + next.top) / 2;
13789
- }
13790
- slots.push({ insertIndex: i, y, left, width });
13791
- }
13792
- return slots;
13793
- }
13794
- function hitTestSectionDropSlot(y, slots) {
13795
- let best = null;
13796
- for (const slot of slots) {
13797
- const dist = Math.abs(y - slot.y);
13798
- if (!best || dist < best.dist) best = { slot, dist };
13799
- }
13800
- return best?.slot ?? null;
13801
- }
13802
-
13803
- // src/useSectionDrag.ts
13804
- var PRESS_THRESHOLD = 10;
13805
- var EDGE_ZONE = 60;
13806
- var MAX_AUTO_SCROLL_SPEED = 18;
13807
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13808
- "[data-ohw-toolbar]",
13809
- "[data-ohw-edit-chrome]",
13810
- "[data-ohw-item-interaction]",
13811
- "[data-ohw-drag-handle-container]",
13812
- '[data-slot="drag-handle"]',
13813
- "[data-ohw-item-toolbar-anchor]",
13814
- "[data-ohw-item-drag-surface]",
13815
- "[data-ohw-more-menu]",
13816
- '[data-slot="dropdown-menu-content"]',
13817
- '[data-slot="dropdown-menu-item"]',
13818
- "[data-ohw-state-toggle]",
13819
- "[data-ohw-max-badge]",
13820
- "[data-ohw-floating-panel]",
13821
- "[data-ohw-section-picker]",
13822
- "[data-ohw-link-popover-root]",
13823
- "[data-ohw-link-modal-root]",
13824
- "[data-ohw-link-page-dropdown]",
13825
- '[data-slot="popover-content"]',
13826
- '[data-slot="dialog-content"]',
13827
- '[data-slot="dialog-overlay"]',
13828
- "[data-ohw-ai-review]",
13829
- "[data-ohw-editable]",
13830
- "[data-ohw-editable-state]",
13831
- "[contenteditable]",
13832
- "[data-ohw-href-key]",
13833
- "[data-ohw-footer-col]",
13834
- "[data-ohw-social-label]",
13835
- "a",
13836
- "button",
13837
- '[role="button"]',
13838
- '[data-ohw-role="navbar-button"]',
13839
- '[data-ohw-role="button"]',
13840
- "[data-ohw-carousel]",
13841
- "[data-ohw-carousel-value]",
13842
- "[data-ohw-carousel-slide]",
13843
- "[data-ohw-carousel-overlay]",
13844
- "[data-ohw-media-chrome]",
13845
- "[data-ohw-media-overlay]",
13846
- "[data-ohw-media-skeleton]"
13847
- ].join(", ");
13848
- function visibleClip(ps) {
13849
- if (!ps) return null;
13850
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13851
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13852
- return { top, bottom: Math.max(top, bottom) };
13853
- }
13854
- function useSectionDrag({
13855
- isEditMode,
13856
- editContentRef,
13857
- postToParentRef,
13858
- parentScrollRef,
13859
- navDragRef,
13860
- footerDragRef,
13861
- suppressNextClickRef,
13862
- suppressClickUntilRef
13863
- }) {
13864
- const sectionDragRef = (0, import_react15.useRef)(null);
13865
- const [sectionDropSlots, setSectionDropSlots] = (0, import_react15.useState)([]);
13866
- const [activeSectionDropIndex, setActiveSectionDropIndex] = (0, import_react15.useState)(null);
13867
- const [isSectionDragging, setIsSectionDragging] = (0, import_react15.useState)(false);
13868
- const sectionPointerDragRef = (0, import_react15.useRef)(null);
13869
- const autoScrollRafRef = (0, import_react15.useRef)(null);
13870
- const autoScrollDeltaRef = (0, import_react15.useRef)(0);
13871
- const stopAutoScroll = (0, import_react15.useCallback)(() => {
13872
- if (autoScrollRafRef.current != null) {
13873
- cancelAnimationFrame(autoScrollRafRef.current);
13874
- autoScrollRafRef.current = null;
13875
- }
13876
- autoScrollDeltaRef.current = 0;
13877
- }, []);
13878
- const tickAutoScroll = (0, import_react15.useCallback)(() => {
13879
- if (!sectionDragRef.current) {
13880
- stopAutoScroll();
13881
- return;
13882
- }
13883
- if (autoScrollDeltaRef.current !== 0) {
13884
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13885
- }
13886
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13887
- }, [postToParentRef, stopAutoScroll]);
13888
- const updateAutoScroll = (0, import_react15.useCallback)(
13889
- (clientY) => {
13890
- const clip = visibleClip(parentScrollRef.current);
13891
- let delta = 0;
13892
- if (clip) {
13893
- const distTop = clientY - clip.top;
13894
- const distBottom = clip.bottom - clientY;
13895
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13896
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13897
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13898
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13899
- }
13900
- }
13901
- autoScrollDeltaRef.current = delta;
13902
- if (delta !== 0 && autoScrollRafRef.current == null) {
13903
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13904
- } else if (delta === 0) {
13905
- stopAutoScroll();
13906
- }
13907
- },
13908
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13909
- );
13910
- const clearSectionDragVisuals = (0, import_react15.useCallback)(() => {
13911
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13912
- sectionDragRef.current = null;
13913
- setSectionDropSlots([]);
13914
- setActiveSectionDropIndex(null);
13915
- setIsSectionDragging(false);
13916
- stopAutoScroll();
13917
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13918
- unlockItemDragInteraction();
13919
- }, [stopAutoScroll]);
13920
- const refreshSectionDragVisuals = (0, import_react15.useCallback)(
13921
- (session, clientX, clientY) => {
13922
- session.lastClientX = clientX;
13923
- session.lastClientY = clientY;
13924
- const slots = buildSectionDropSlots(session.instanceId);
13925
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13926
- session.activeSlot = activeSlot;
13927
- setSectionDropSlots(slots);
13928
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13929
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13930
- updateAutoScroll(clientY);
13931
- },
13932
- [updateAutoScroll]
13933
- );
13934
- const beginSectionDrag = (0, import_react15.useCallback)(
13935
- (session) => {
13936
- sectionDragRef.current = session;
13937
- setIsSectionDragging(true);
13938
- lockItemDuringDrag();
13939
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13940
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13941
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13942
- },
13943
- [refreshSectionDragVisuals]
13944
- );
13945
- const commitSectionDrag = (0, import_react15.useCallback)(() => {
13946
- const session = sectionDragRef.current;
13947
- if (!session) {
13948
- clearSectionDragVisuals();
13949
- return;
13950
- }
13951
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13952
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13953
- if (!entries) {
13954
- clearSectionDragVisuals();
13955
- return;
13956
- }
13957
- const orderJson = JSON.stringify(entries);
13958
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13959
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13960
- applyPersistedOrder(entries);
13961
- clearSectionDragVisuals();
13962
- requestAnimationFrame(() => {
13963
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13964
- applyPersistedOrder(entries);
13965
- }
13966
- requestAnimationFrame(() => {
13967
- window.dispatchEvent(new Event("resize"));
13968
- });
13969
- });
13970
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13971
- const startSectionPressDrag = (0, import_react15.useCallback)(
13972
- (el, clientX, clientY, pointerId) => {
13973
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13974
- const instanceId = instanceIdOf(el);
13975
- if (!instanceId) return false;
13976
- sectionPointerDragRef.current = {
13977
- el,
13978
- instanceId,
13979
- startX: clientX,
13980
- startY: clientY,
13981
- pointerId,
13982
- started: false
13983
- };
13984
- return true;
13985
- },
13986
- [footerDragRef, navDragRef]
13987
- );
13988
- (0, import_react15.useEffect)(() => {
13989
- if (!isEditMode) return;
13990
- const onPointerDown = (e) => {
13991
- if (e.button !== 0) return;
13992
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13993
- if (sectionPointerDragRef.current) return;
13994
- const target = e.target;
13995
- if (!(target instanceof HTMLElement)) return;
13996
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13997
- const sectionEl = target.closest("[data-ohw-section]");
13998
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13999
- if (!topLevelSections().includes(sectionEl)) return;
14000
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
14001
- };
14002
- const onPointerMove = (e) => {
14003
- const pending = sectionPointerDragRef.current;
14004
- if (!pending) return;
14005
- if (pending.started) {
14006
- e.preventDefault();
14007
- clearTextSelection();
14008
- const session = sectionDragRef.current;
14009
- if (!session) return;
14010
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
14011
- return;
14012
- }
14013
- const dx = e.clientX - pending.startX;
14014
- const dy = e.clientY - pending.startY;
14015
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
14016
- e.preventDefault();
14017
- pending.started = true;
14018
- armItemPressDrag();
14019
- clearTextSelection();
14020
- try {
14021
- document.body.setPointerCapture(pending.pointerId);
14022
- } catch {
14023
- }
14024
- beginSectionDrag({
14025
- instanceId: pending.instanceId,
14026
- draggedEl: pending.el,
14027
- lastClientX: e.clientX,
14028
- lastClientY: e.clientY,
14029
- activeSlot: null
14030
- });
14031
- };
14032
- const endPointerDrag = (e) => {
14033
- const pending = sectionPointerDragRef.current;
14034
- sectionPointerDragRef.current = null;
14035
- try {
14036
- if (document.body.hasPointerCapture(e.pointerId)) {
14037
- document.body.releasePointerCapture(e.pointerId);
14038
- }
14039
- } catch {
14040
- }
14041
- if (!pending) return;
14042
- if (!pending.started) {
14043
- unlockItemDragInteraction();
14044
- return;
14045
- }
14046
- suppressNextClickRef.current = true;
14047
- suppressClickUntilRef.current = Date.now() + 500;
14048
- commitSectionDrag();
14049
- };
14050
- const onKeyDown = (e) => {
14051
- if (e.key !== "Escape") return;
14052
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
14053
- sectionPointerDragRef.current = null;
14054
- clearSectionDragVisuals();
14055
- };
14056
- document.addEventListener("pointerdown", onPointerDown, true);
14057
- document.addEventListener("pointermove", onPointerMove, true);
14058
- document.addEventListener("pointerup", endPointerDrag, true);
14059
- document.addEventListener("pointercancel", endPointerDrag, true);
14060
- document.addEventListener("keydown", onKeyDown, true);
14061
- return () => {
14062
- document.removeEventListener("pointerdown", onPointerDown, true);
14063
- document.removeEventListener("pointermove", onPointerMove, true);
14064
- document.removeEventListener("pointerup", endPointerDrag, true);
14065
- document.removeEventListener("pointercancel", endPointerDrag, true);
14066
- document.removeEventListener("keydown", onKeyDown, true);
14067
- unlockItemDragInteraction();
14068
- stopAutoScroll();
14069
- };
14070
- }, [
14071
- beginSectionDrag,
14072
- clearSectionDragVisuals,
14073
- commitSectionDrag,
14074
- footerDragRef,
14075
- isEditMode,
14076
- navDragRef,
14077
- refreshSectionDragVisuals,
14078
- startSectionPressDrag,
14079
- stopAutoScroll,
14080
- suppressClickUntilRef,
14081
- suppressNextClickRef
14082
- ]);
14083
- return {
14084
- sectionDragRef,
14085
- sectionDropSlots,
14086
- activeSectionDropIndex,
14087
- isSectionDragging
14088
- };
14089
- }
14090
-
14091
12983
  // src/ui/footer-container-chrome.tsx
14092
12984
  var import_lucide_react15 = require("lucide-react");
14093
12985
  var import_jsx_runtime29 = require("react/jsx-runtime");
@@ -14140,7 +13032,7 @@ function FooterContainerChrome({
14140
13032
  }
14141
13033
 
14142
13034
  // src/lib/carousel.ts
14143
- var import_react16 = require("react");
13035
+ var import_react15 = require("react");
14144
13036
  var CAROUSEL_ATTR = "data-ohw-carousel";
14145
13037
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
14146
13038
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -14202,8 +13094,8 @@ function applyCarouselNode(key, val) {
14202
13094
  return true;
14203
13095
  }
14204
13096
  function useOhwCarousel(key, initial) {
14205
- const [images, setImages] = (0, import_react16.useState)(initial);
14206
- (0, import_react16.useEffect)(() => {
13097
+ const [images, setImages] = (0, import_react15.useState)(initial);
13098
+ (0, import_react15.useEffect)(() => {
14207
13099
  const el = document.querySelector(
14208
13100
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
14209
13101
  );
@@ -14285,7 +13177,6 @@ function collectEditableNodes(extraContent, root = document) {
14285
13177
  NAV_ORDER_KEY,
14286
13178
  FOOTER_ORDER_KEY,
14287
13179
  NAV_COUNT_KEY,
14288
- SECTION_ORDER_KEY,
14289
13180
  // A socials row's order and its icons-vs-words setting live under keys no element carries,
14290
13181
  // so collecting the DOM alone left them behind: the draft knew the row was showing icons and
14291
13182
  // had gained an item, and the published page went back to the template's own (OHH-736).
@@ -14749,7 +13640,6 @@ function fadeInImageElement(img, onReady) {
14749
13640
  function applyEditableImageSrc(img, url) {
14750
13641
  img.removeAttribute("srcset");
14751
13642
  img.removeAttribute("sizes");
14752
- if (img.loading === "lazy") img.loading = "eager";
14753
13643
  img.src = url;
14754
13644
  }
14755
13645
  function fadeInBgImage(el, url, onReady) {
@@ -14814,10 +13704,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14814
13704
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14815
13705
  };
14816
13706
  }
14817
- function resolveEntryAnchor(entry) {
14818
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14819
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14820
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13707
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13708
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13709
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13710
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13711
+ return { effectiveInsertAfter, insertBefore };
13712
+ }
13713
+ function getSchedulingMountPoint(insertAfter) {
13714
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13715
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13716
+ if (!anchorEl && anchor === "scheduling") {
13717
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13718
+ anchorEl = widgets.at(-1) ?? null;
13719
+ }
13720
+ if (!anchorEl) return null;
13721
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14821
13722
  }
14822
13723
  function schedulingMountDepth(insertAfter) {
14823
13724
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14834,7 +13735,8 @@ function getPageSchedulingEntries(raw) {
14834
13735
  }
14835
13736
  }
14836
13737
  function isSchedulingWidgetMissing(entry) {
14837
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13738
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13739
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14838
13740
  }
14839
13741
  function hasMissingSchedulingWidgets(entries) {
14840
13742
  return entries.some(isSchedulingWidgetMissing);
@@ -14864,17 +13766,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14864
13766
  } catch {
14865
13767
  }
14866
13768
  }
14867
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14868
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14869
- const sectionId = schedulingSectionId(widgetId);
13769
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13770
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13771
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14870
13772
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14871
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14872
- if (!anchorEl) return false;
14873
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13773
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13774
+ if (!mountPoint) return false;
14874
13775
  const container = document.createElement("div");
14875
13776
  container.dataset.ohwSectionContainer = "scheduling";
14876
- if (beforeId) {
14877
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13777
+ if (insertBefore) {
13778
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14878
13779
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14879
13780
  if (!beforePoint) return false;
14880
13781
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14885,38 +13786,30 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14885
13786
  }
14886
13787
  tail.insertAdjacentElement("afterend", container);
14887
13788
  }
14888
- try {
14889
- const root = (0, import_client2.createRoot)(container);
14890
- (0, import_react_dom3.flushSync)(() => {
14891
- root.render(
14892
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14893
- SchedulingWidget,
14894
- {
14895
- notifyOnConnect,
14896
- initialScheduleId: scheduleId,
14897
- insertAfter: widgetId
14898
- }
14899
- )
14900
- );
14901
- });
14902
- } catch (err) {
14903
- console.error("[ow:scheduling] render threw", err);
14904
- container.remove();
14905
- return false;
14906
- }
14907
- const tracker = getSectionsTracker();
14908
- let sections = [];
13789
+ const root = (0, import_client2.createRoot)(container);
13790
+ (0, import_react_dom3.flushSync)(() => {
13791
+ root.render(
13792
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13793
+ SchedulingWidget,
13794
+ {
13795
+ notifyOnConnect,
13796
+ initialScheduleId: scheduleId,
13797
+ insertAfter: effectiveInsertAfter
13798
+ }
13799
+ )
13800
+ );
13801
+ });
13802
+ const tracker = getSectionsTracker();
13803
+ let sections = [];
14909
13804
  try {
14910
13805
  sections = JSON.parse(tracker.textContent || "[]");
14911
13806
  } catch {
14912
13807
  }
14913
13808
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14914
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13809
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14915
13810
  sections.push({
14916
13811
  type: "scheduling",
14917
- insertAfter: widgetId,
14918
- anchorId,
14919
- beforeId: beforeId ?? null,
13812
+ insertAfter: effectiveInsertAfter,
14920
13813
  pagePath: window.location.pathname,
14921
13814
  ...scheduleId ? { scheduleId } : {}
14922
13815
  });
@@ -14930,8 +13823,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14930
13823
  for (let i = pending.length - 1; i >= 0; i--) {
14931
13824
  const entry = pending[i];
14932
13825
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14933
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14934
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13826
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14935
13827
  pending.splice(i, 1);
14936
13828
  }
14937
13829
  }
@@ -15089,11 +13981,6 @@ function applyLinkByKey(key, val) {
15089
13981
  hrefAnchors.forEach((el) => applyLinkHref(el, val));
15090
13982
  }
15091
13983
  }
15092
- function isInsideLinkEditor(target) {
15093
- return Boolean(
15094
- 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"]')
15095
- );
15096
- }
15097
13984
  function isInsideFloatingPanel(target) {
15098
13985
  return Boolean(target.closest("[data-ohw-floating-panel]"));
15099
13986
  }
@@ -15101,6 +13988,11 @@ function isPointOverFloatingPanel(clientX, clientY) {
15101
13988
  const el = document.elementFromPoint(clientX, clientY);
15102
13989
  return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
15103
13990
  }
13991
+ function isInsideLinkEditor(target) {
13992
+ return Boolean(
13993
+ 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"]')
13994
+ );
13995
+ }
15104
13996
  function getHrefKeyFromElement(el) {
15105
13997
  if (!el) return null;
15106
13998
  const anchor = el.closest("[data-ohw-href-key]");
@@ -15359,7 +14251,7 @@ function getNavigationSelectionParent(el) {
15359
14251
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
15360
14252
  return getFooterLinksContainer();
15361
14253
  }
15362
- 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)) {
14254
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
15363
14255
  return getNavigationRoot(el);
15364
14256
  }
15365
14257
  return null;
@@ -15574,6 +14466,7 @@ var ICONS = {
15574
14466
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
15575
14467
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
15576
14468
  };
14469
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
15577
14470
  var SELECTION_CHROME_GAP2 = 4;
15578
14471
  var TOOLBAR_STROKE_GAP2 = 4;
15579
14472
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -15829,9 +14722,9 @@ function FloatingToolbar({
15829
14722
  showEditLink,
15830
14723
  onEditLink
15831
14724
  }) {
15832
- const localRef = import_react17.default.useRef(null);
15833
- const [measuredW, setMeasuredW] = import_react17.default.useState(330);
15834
- const setRefs = import_react17.default.useCallback(
14725
+ const localRef = import_react16.default.useRef(null);
14726
+ const [measuredW, setMeasuredW] = import_react16.default.useState(330);
14727
+ const setRefs = import_react16.default.useCallback(
15835
14728
  (node) => {
15836
14729
  localRef.current = node;
15837
14730
  if (typeof elRef === "function") elRef(node);
@@ -15843,7 +14736,7 @@ function FloatingToolbar({
15843
14736
  },
15844
14737
  [elRef]
15845
14738
  );
15846
- import_react17.default.useLayoutEffect(() => {
14739
+ import_react16.default.useLayoutEffect(() => {
15847
14740
  const node = localRef.current;
15848
14741
  if (!node) return;
15849
14742
  const update = () => {
@@ -15869,7 +14762,7 @@ function FloatingToolbar({
15869
14762
  pointerEvents: "auto"
15870
14763
  },
15871
14764
  children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
15872
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react17.default.Fragment, { children: [
14765
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
15873
14766
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
15874
14767
  btns.map((btn) => {
15875
14768
  const isActive = activeCommands.has(btn.cmd);
@@ -15953,45 +14846,6 @@ function StateToggle({
15953
14846
  );
15954
14847
  }
15955
14848
  var contentCache = /* @__PURE__ */ new Map();
15956
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15957
- var OHW_LOADER_STYLE = {
15958
- position: "fixed",
15959
- inset: 0,
15960
- background: "#fff",
15961
- zIndex: 2147483646,
15962
- display: "flex",
15963
- alignItems: "center",
15964
- justifyContent: "center"
15965
- };
15966
- function OhwLoaderSpinner() {
15967
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15968
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15969
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15970
- "circle",
15971
- {
15972
- cx: "14",
15973
- cy: "14",
15974
- r: "11",
15975
- stroke: "#1C1917",
15976
- strokeWidth: "3",
15977
- strokeDasharray: "17 52",
15978
- strokeLinecap: "round",
15979
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15980
- "animateTransform",
15981
- {
15982
- attributeName: "transform",
15983
- type: "rotate",
15984
- from: "0 14 14",
15985
- to: "360 14 14",
15986
- dur: "0.7s",
15987
- repeatCount: "indefinite"
15988
- }
15989
- )
15990
- }
15991
- )
15992
- ] });
15993
- }
15994
- 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){}})();`;
15995
14849
  function resolveSubdomain(subdomainFromQuery) {
15996
14850
  if (subdomainFromQuery) return subdomainFromQuery;
15997
14851
  if (typeof window !== "undefined") {
@@ -16014,8 +14868,8 @@ function OhhwellsBridge() {
16014
14868
  const router = (0, import_navigation3.useRouter)();
16015
14869
  const searchParams = (0, import_navigation3.useSearchParams)();
16016
14870
  const isEditMode = isEditSessionActive();
16017
- const [bridgeRoot, setBridgeRoot] = (0, import_react17.useState)(null);
16018
- (0, import_react17.useEffect)(() => {
14871
+ const [bridgeRoot, setBridgeRoot] = (0, import_react16.useState)(null);
14872
+ (0, import_react16.useEffect)(() => {
16019
14873
  const figtreeFontId = "ohw-figtree-font";
16020
14874
  if (!document.getElementById(figtreeFontId)) {
16021
14875
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -16044,146 +14898,82 @@ function OhhwellsBridge() {
16044
14898
  const subdomain = resolveSubdomain(subdomainFromQuery);
16045
14899
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
16046
14900
  useSavedLinkNavigation(isEditMode);
16047
- const postToParent2 = (0, import_react17.useCallback)((data) => {
14901
+ const postToParent2 = (0, import_react16.useCallback)((data) => {
16048
14902
  if (typeof window !== "undefined" && window.parent !== window) {
16049
14903
  window.parent.postMessage(data, "*");
16050
14904
  }
16051
14905
  }, []);
16052
- const [fetchState, setFetchState] = (0, import_react17.useState)("idle");
16053
- const autoSaveTimers = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
16054
- const activeElRef = (0, import_react17.useRef)(null);
16055
- const pointerHeldRef = (0, import_react17.useRef)(false);
16056
- const selectedElRef = (0, import_react17.useRef)(null);
16057
- const selectedHrefKeyRef = (0, import_react17.useRef)(null);
16058
- const selectedFooterColAttrRef = (0, import_react17.useRef)(null);
16059
- const originalContentRef = (0, import_react17.useRef)(null);
16060
- const activeStateElRef = (0, import_react17.useRef)(null);
16061
- const parentScrollRef = (0, import_react17.useRef)(null);
16062
- const visibleViewportRef = (0, import_react17.useRef)(null);
16063
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react17.useState)(null);
16064
- const attachVisibleViewport = (0, import_react17.useCallback)((node) => {
14906
+ const [fetchState, setFetchState] = (0, import_react16.useState)("idle");
14907
+ const autoSaveTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
14908
+ const activeElRef = (0, import_react16.useRef)(null);
14909
+ const pointerHeldRef = (0, import_react16.useRef)(false);
14910
+ const selectedElRef = (0, import_react16.useRef)(null);
14911
+ const selectedHrefKeyRef = (0, import_react16.useRef)(null);
14912
+ const selectedFooterColAttrRef = (0, import_react16.useRef)(null);
14913
+ const originalContentRef = (0, import_react16.useRef)(null);
14914
+ const activeStateElRef = (0, import_react16.useRef)(null);
14915
+ const parentScrollRef = (0, import_react16.useRef)(null);
14916
+ const visibleViewportRef = (0, import_react16.useRef)(null);
14917
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react16.useState)(null);
14918
+ const attachVisibleViewport = (0, import_react16.useCallback)((node) => {
16065
14919
  visibleViewportRef.current = node;
16066
14920
  setDialogPortalContainer(node);
16067
14921
  if (node) applyVisibleViewport(node, parentScrollRef.current);
16068
14922
  }, []);
16069
- const toolbarElRef = (0, import_react17.useRef)(null);
16070
- const glowElRef = (0, import_react17.useRef)(null);
16071
- const hoveredImageRef = (0, import_react17.useRef)(null);
16072
- const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
16073
- const dragOverElRef = (0, import_react17.useRef)(null);
16074
- const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
16075
- const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
16076
- const selectedMediaElRef = (0, import_react17.useRef)(null);
16077
- const clearMediaSelection = (0, import_react17.useCallback)(() => {
16078
- const prev = selectedMediaElRef.current;
16079
- selectedMediaElRef.current = null;
16080
- setSelectedMedia(null);
16081
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
16082
- if (sectionEl) {
16083
- postToParentRef.current({
16084
- type: "ow:section-selected",
16085
- sectionId: sectionEl.dataset.ohwSection ?? null,
16086
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
16087
- key: null
16088
- });
16089
- }
16090
- }, []);
16091
- const clearMediaSelectionRef = (0, import_react17.useRef)(clearMediaSelection);
16092
- clearMediaSelectionRef.current = clearMediaSelection;
16093
- const selectMediaElement = (0, import_react17.useCallback)((el) => {
16094
- const r2 = el.getBoundingClientRect();
16095
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
16096
- selectedMediaElRef.current = el;
16097
- setSelectedMedia({
16098
- key: el.dataset.ohwKey ?? "",
16099
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
16100
- elementType: el.dataset.ohwEditable ?? "image",
16101
- hasTextOverlap: false,
16102
- isDragOver: false,
16103
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
16104
- });
16105
- const sectionEl = el.closest("[data-ohw-section]");
16106
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
16107
- postToParentRef.current({
16108
- type: "ow:section-selected",
16109
- sectionId: sectionEl?.dataset.ohwSection ?? null,
16110
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
16111
- key: el.dataset.ohwKey ?? null,
16112
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
16113
- // bridge knows what the node IS, so it names it.
16114
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : el.dataset.ohwEditable === "bg-image" ? "Background" : "Image"
16115
- });
16116
- }, []);
16117
- const selectMediaElementRef = (0, import_react17.useRef)(selectMediaElement);
16118
- selectMediaElementRef.current = selectMediaElement;
16119
- (0, import_react17.useEffect)(() => {
16120
- if (!selectedMedia) return;
16121
- const update = () => {
16122
- const el = selectedMediaElRef.current;
16123
- if (!el || !el.isConnected) {
16124
- clearMediaSelection();
16125
- return;
16126
- }
16127
- const r2 = el.getBoundingClientRect();
16128
- setSelectedMedia(
16129
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
16130
- );
16131
- };
16132
- window.addEventListener("scroll", update, true);
16133
- window.addEventListener("resize", update);
16134
- return () => {
16135
- window.removeEventListener("scroll", update, true);
16136
- window.removeEventListener("resize", update);
16137
- };
16138
- }, [selectedMedia !== null]);
16139
- const [carouselHover, setCarouselHover] = (0, import_react17.useState)(null);
16140
- const [uploadingRects, setUploadingRects] = (0, import_react17.useState)({});
16141
- const hoveredGapRef = (0, import_react17.useRef)(null);
16142
- const imageUnhoverTimerRef = (0, import_react17.useRef)(null);
16143
- const imageShowTimerRef = (0, import_react17.useRef)(null);
16144
- const editStylesRef = (0, import_react17.useRef)(null);
16145
- const activateRef = (0, import_react17.useRef)(() => {
14923
+ const toolbarElRef = (0, import_react16.useRef)(null);
14924
+ const glowElRef = (0, import_react16.useRef)(null);
14925
+ const hoveredImageRef = (0, import_react16.useRef)(null);
14926
+ const hoveredImageHasTextOverlapRef = (0, import_react16.useRef)(false);
14927
+ const dragOverElRef = (0, import_react16.useRef)(null);
14928
+ const [mediaHover, setMediaHover] = (0, import_react16.useState)(null);
14929
+ const [carouselHover, setCarouselHover] = (0, import_react16.useState)(null);
14930
+ const [uploadingRects, setUploadingRects] = (0, import_react16.useState)({});
14931
+ const hoveredGapRef = (0, import_react16.useRef)(null);
14932
+ const imageUnhoverTimerRef = (0, import_react16.useRef)(null);
14933
+ const imageShowTimerRef = (0, import_react16.useRef)(null);
14934
+ const editStylesRef = (0, import_react16.useRef)(null);
14935
+ const activateRef = (0, import_react16.useRef)(() => {
16146
14936
  });
16147
- const deactivateRef = (0, import_react17.useRef)(() => {
14937
+ const deactivateRef = (0, import_react16.useRef)(() => {
16148
14938
  });
16149
- const selectRef = (0, import_react17.useRef)(() => {
14939
+ const selectRef = (0, import_react16.useRef)(() => {
16150
14940
  });
16151
- const selectFrameRef = (0, import_react17.useRef)(() => {
14941
+ const selectFrameRef = (0, import_react16.useRef)(() => {
16152
14942
  });
16153
- const selectLogoRef = (0, import_react17.useRef)(() => {
14943
+ const selectLogoRef = (0, import_react16.useRef)(() => {
16154
14944
  });
16155
- const openLogoSizePanelRef = (0, import_react17.useRef)(() => {
14945
+ const openLogoSizePanelRef = (0, import_react16.useRef)(() => {
16156
14946
  });
16157
- const deselectRef = (0, import_react17.useRef)(() => {
14947
+ const deselectRef = (0, import_react16.useRef)(() => {
16158
14948
  });
16159
- const closeFloatingPanelOnlyRef = (0, import_react17.useRef)(() => {
14949
+ const closeFloatingPanelOnlyRef = (0, import_react16.useRef)(() => {
16160
14950
  });
16161
- const reselectNavigationItemRef = (0, import_react17.useRef)(() => {
14951
+ const reselectNavigationItemRef = (0, import_react16.useRef)(() => {
16162
14952
  });
16163
- const commitNavigationTextEditRef = (0, import_react17.useRef)(() => {
14953
+ const commitNavigationTextEditRef = (0, import_react16.useRef)(() => {
16164
14954
  });
16165
- const handleDeleteSelectedRef = (0, import_react17.useRef)(() => false);
16166
- const runPendingDeleteUndoRef = (0, import_react17.useRef)(() => false);
16167
- const isFooterFrameSelectionRef = (0, import_react17.useRef)(false);
16168
- const refreshActiveCommandsRef = (0, import_react17.useRef)(() => {
14955
+ const handleDeleteSelectedRef = (0, import_react16.useRef)(() => false);
14956
+ const runPendingDeleteUndoRef = (0, import_react16.useRef)(() => false);
14957
+ const isFooterFrameSelectionRef = (0, import_react16.useRef)(false);
14958
+ const refreshActiveCommandsRef = (0, import_react16.useRef)(() => {
16169
14959
  });
16170
- const postToParentRef = (0, import_react17.useRef)(postToParent2);
14960
+ const postToParentRef = (0, import_react16.useRef)(postToParent2);
16171
14961
  postToParentRef.current = postToParent2;
16172
- const aiSectionApiRef = (0, import_react17.useRef)(null);
16173
- const sectionsLoadedRef = (0, import_react17.useRef)(false);
16174
- const pendingScheduleConfigRequests = (0, import_react17.useRef)([]);
16175
- const [toolbarRect, setToolbarRect] = (0, import_react17.useState)(null);
16176
- const [formPickRect, setFormPickRect] = (0, import_react17.useState)(null);
16177
- const formPickElRef = (0, import_react17.useRef)(null);
16178
- const [formViewState, setFormViewStateUi] = (0, import_react17.useState)("default");
16179
- const [formPickCount, setFormPickCount] = (0, import_react17.useState)(null);
16180
- const [formHoverRect, setFormHoverRect] = (0, import_react17.useState)(null);
16181
- const formHoverElRef = (0, import_react17.useRef)(null);
16182
- const [fieldPickRect, setFieldPickRect] = (0, import_react17.useState)(null);
16183
- const fieldPickElRef = (0, import_react17.useRef)(null);
16184
- const [fieldPickState, setFieldPickState] = (0, import_react17.useState)(null);
16185
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react17.useState)(false);
16186
- const clearFormPick = (0, import_react17.useCallback)(() => {
14962
+ const aiSectionApiRef = (0, import_react16.useRef)(null);
14963
+ const sectionsLoadedRef = (0, import_react16.useRef)(false);
14964
+ const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14965
+ const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
14966
+ const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
14967
+ const formPickElRef = (0, import_react16.useRef)(null);
14968
+ const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
14969
+ const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
14970
+ const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
14971
+ const formHoverElRef = (0, import_react16.useRef)(null);
14972
+ const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
14973
+ const fieldPickElRef = (0, import_react16.useRef)(null);
14974
+ const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
14975
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
14976
+ const clearFormPick = (0, import_react16.useCallback)(() => {
16187
14977
  const form = formPickElRef.current;
16188
14978
  const editing = fieldPickElRef.current;
16189
14979
  if (commitPlaceholderEdit(editing) && editing) {
@@ -16203,7 +14993,7 @@ function OhhwellsBridge() {
16203
14993
  formPickElRef.current = null;
16204
14994
  setFormPickRect(null);
16205
14995
  }, []);
16206
- const clearFieldPick = (0, import_react17.useCallback)(() => {
14996
+ const clearFieldPick = (0, import_react16.useCallback)(() => {
16207
14997
  const wrapper = fieldPickElRef.current;
16208
14998
  if (commitPlaceholderEdit(wrapper) && wrapper) {
16209
14999
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -16213,9 +15003,9 @@ function OhhwellsBridge() {
16213
15003
  setFieldPickRect(null);
16214
15004
  setFieldPickState(null);
16215
15005
  }, []);
16216
- const persistFieldsRef = (0, import_react17.useRef)(() => {
15006
+ const persistFieldsRef = (0, import_react16.useRef)(() => {
16217
15007
  });
16218
- const persistFields = (0, import_react17.useCallback)(
15008
+ const persistFields = (0, import_react16.useCallback)(
16219
15009
  (form) => {
16220
15010
  const key = formKeyOf(form);
16221
15011
  if (!key) return;
@@ -16226,7 +15016,7 @@ function OhhwellsBridge() {
16226
15016
  []
16227
15017
  );
16228
15018
  persistFieldsRef.current = persistFields;
16229
- const selectField = (0, import_react17.useCallback)((wrapper) => {
15019
+ const selectField = (0, import_react16.useCallback)((wrapper) => {
16230
15020
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
16231
15021
  commitPlaceholderEdit(fieldPickElRef.current);
16232
15022
  }
@@ -16239,7 +15029,7 @@ function OhhwellsBridge() {
16239
15029
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
16240
15030
  setFieldTypePickerOpen(false);
16241
15031
  }, []);
16242
- const withSelectedField = (0, import_react17.useCallback)(
15032
+ const withSelectedField = (0, import_react16.useCallback)(
16243
15033
  (run) => {
16244
15034
  const wrapper = fieldPickElRef.current;
16245
15035
  const form = formPickElRef.current;
@@ -16252,28 +15042,28 @@ function OhhwellsBridge() {
16252
15042
  },
16253
15043
  [persistFields]
16254
15044
  );
16255
- const handleFieldTypeChange = (0, import_react17.useCallback)(
15045
+ const handleFieldTypeChange = (0, import_react16.useCallback)(
16256
15046
  (type) => withSelectedField((_form, wrapper) => {
16257
15047
  applyFieldType(wrapper, type);
16258
15048
  selectField(wrapper);
16259
15049
  }),
16260
15050
  [selectField, withSelectedField]
16261
15051
  );
16262
- const handleFieldRequiredToggle = (0, import_react17.useCallback)(
15052
+ const handleFieldRequiredToggle = (0, import_react16.useCallback)(
16263
15053
  () => withSelectedField((_form, wrapper) => {
16264
15054
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
16265
15055
  selectField(wrapper);
16266
15056
  }),
16267
15057
  [selectField, withSelectedField]
16268
15058
  );
16269
- const handleFieldDuplicate = (0, import_react17.useCallback)(
15059
+ const handleFieldDuplicate = (0, import_react16.useCallback)(
16270
15060
  () => withSelectedField((form, wrapper) => {
16271
15061
  const copy = duplicateField(form, wrapper);
16272
15062
  selectField(copy);
16273
15063
  }),
16274
15064
  [selectField, withSelectedField]
16275
15065
  );
16276
- const handleFieldDelete = (0, import_react17.useCallback)(
15066
+ const handleFieldDelete = (0, import_react16.useCallback)(
16277
15067
  () => withSelectedField((_form, wrapper) => {
16278
15068
  removeField(wrapper);
16279
15069
  clearFieldPick();
@@ -16281,7 +15071,7 @@ function OhhwellsBridge() {
16281
15071
  }),
16282
15072
  [clearFieldPick, withSelectedField]
16283
15073
  );
16284
- const handleAddField = (0, import_react17.useCallback)(
15074
+ const handleAddField = (0, import_react16.useCallback)(
16285
15075
  (type) => {
16286
15076
  const form = formPickElRef.current;
16287
15077
  if (!form) return;
@@ -16297,8 +15087,8 @@ function OhhwellsBridge() {
16297
15087
  },
16298
15088
  [persistFields, selectField]
16299
15089
  );
16300
- const fieldDragRef = (0, import_react17.useRef)(null);
16301
- const buildFieldDropSlots = (0, import_react17.useCallback)((form, draggedKey) => {
15090
+ const fieldDragRef = (0, import_react16.useRef)(null);
15091
+ const buildFieldDropSlots = (0, import_react16.useCallback)((form, draggedKey) => {
16302
15092
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
16303
15093
  const slots = others.map((el) => {
16304
15094
  const rect = el.getBoundingClientRect();
@@ -16311,7 +15101,7 @@ function OhhwellsBridge() {
16311
15101
  }
16312
15102
  return slots;
16313
15103
  }, []);
16314
- const handleFieldDragStart = (0, import_react17.useCallback)(() => {
15104
+ const handleFieldDragStart = (0, import_react16.useCallback)(() => {
16315
15105
  const wrapper = fieldPickElRef.current;
16316
15106
  const form = formPickElRef.current;
16317
15107
  if (!wrapper || !form) return;
@@ -16320,18 +15110,18 @@ function OhhwellsBridge() {
16320
15110
  setFieldDragging(true);
16321
15111
  setFieldDropSlots(buildFieldDropSlots(form, key));
16322
15112
  }, [buildFieldDropSlots]);
16323
- const handleFieldDragEnd = (0, import_react17.useCallback)(() => {
15113
+ const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
16324
15114
  fieldDragRef.current = null;
16325
15115
  setFieldDropIndex(null);
16326
15116
  setFieldDropSlots([]);
16327
15117
  setFieldDragging(false);
16328
15118
  }, []);
16329
- const [fieldDropIndex, setFieldDropIndex] = (0, import_react17.useState)(null);
16330
- const [fieldDropSlots, setFieldDropSlots] = (0, import_react17.useState)([]);
16331
- const [fieldDragging, setFieldDragging] = (0, import_react17.useState)(false);
16332
- const clearFormPickRef = (0, import_react17.useRef)(clearFormPick);
15119
+ const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
15120
+ const [fieldDropSlots, setFieldDropSlots] = (0, import_react16.useState)([]);
15121
+ const [fieldDragging, setFieldDragging] = (0, import_react16.useState)(false);
15122
+ const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
16333
15123
  clearFormPickRef.current = clearFormPick;
16334
- (0, import_react17.useEffect)(() => {
15124
+ (0, import_react16.useEffect)(() => {
16335
15125
  const el = fieldPickElRef.current;
16336
15126
  if (!el || fieldPickRect === null) return;
16337
15127
  const observer = new ResizeObserver(() => {
@@ -16340,7 +15130,7 @@ function OhhwellsBridge() {
16340
15130
  observer.observe(el);
16341
15131
  return () => observer.disconnect();
16342
15132
  }, [fieldPickRect !== null, fieldPickState]);
16343
- (0, import_react17.useEffect)(() => {
15133
+ (0, import_react16.useEffect)(() => {
16344
15134
  const el = formPickElRef.current;
16345
15135
  if (!el || formPickRect === null) return;
16346
15136
  const observer = new ResizeObserver(() => {
@@ -16349,25 +15139,25 @@ function OhhwellsBridge() {
16349
15139
  observer.observe(el);
16350
15140
  return () => observer.disconnect();
16351
15141
  }, [formPickRect !== null, formViewState]);
16352
- const [toolbarVariant, setToolbarVariant] = (0, import_react17.useState)("none");
16353
- const toolbarVariantRef = (0, import_react17.useRef)("none");
15142
+ const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
15143
+ const toolbarVariantRef = (0, import_react16.useRef)("none");
16354
15144
  toolbarVariantRef.current = toolbarVariant;
16355
- const [selectedIsCta, setSelectedIsCta] = (0, import_react17.useState)(false);
16356
- const [selectedIsSocial, setSelectedIsSocial] = (0, import_react17.useState)(false);
16357
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react17.useState)(false);
16358
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react17.useState)(null);
16359
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react17.useState)(false);
16360
- const [toggleState, setToggleState] = (0, import_react17.useState)(null);
16361
- const [maxBadge, setMaxBadge] = (0, import_react17.useState)(null);
16362
- const [activeCommands, setActiveCommands] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
16363
- const [sectionGap, setSectionGap] = (0, import_react17.useState)(null);
16364
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react17.useState)(false);
16365
- const hoveredNavContainerRef = (0, import_react17.useRef)(null);
16366
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react17.useState)(null);
16367
- const hoveredItemElRef = (0, import_react17.useRef)(null);
16368
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react17.useState)(null);
16369
- const [hoveredTextRect, setHoveredTextRect] = (0, import_react17.useState)(null);
16370
- (0, import_react17.useEffect)(() => {
15145
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react16.useState)(false);
15146
+ const [selectedIsSocial, setSelectedIsSocial] = (0, import_react16.useState)(false);
15147
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react16.useState)(false);
15148
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react16.useState)(null);
15149
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react16.useState)(false);
15150
+ const [toggleState, setToggleState] = (0, import_react16.useState)(null);
15151
+ const [maxBadge, setMaxBadge] = (0, import_react16.useState)(null);
15152
+ const [activeCommands, setActiveCommands] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
15153
+ const [sectionGap, setSectionGap] = (0, import_react16.useState)(null);
15154
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react16.useState)(false);
15155
+ const hoveredNavContainerRef = (0, import_react16.useRef)(null);
15156
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
15157
+ const hoveredItemElRef = (0, import_react16.useRef)(null);
15158
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
15159
+ const [hoveredTextRect, setHoveredTextRect] = (0, import_react16.useState)(null);
15160
+ (0, import_react16.useEffect)(() => {
16371
15161
  const sync = () => {
16372
15162
  const el = document.querySelector(
16373
15163
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -16392,56 +15182,43 @@ function OhhwellsBridge() {
16392
15182
  });
16393
15183
  return () => observer.disconnect();
16394
15184
  }, []);
16395
- const siblingHintElRef = (0, import_react17.useRef)(null);
16396
- const [siblingHintRect, setSiblingHintRect] = (0, import_react17.useState)(null);
16397
- const [siblingHintRects, setSiblingHintRects] = (0, import_react17.useState)([]);
16398
- const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
16399
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
15185
+ const siblingHintElRef = (0, import_react16.useRef)(null);
15186
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
15187
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
15188
+ const [isItemDragging, setIsItemDragging] = (0, import_react16.useState)(false);
15189
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react16.useState)(false);
16400
15190
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
16401
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
16402
- const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
16403
- const footerDragRef = (0, import_react17.useRef)(null);
16404
- const [footerDropSlots, setFooterDropSlots] = (0, import_react17.useState)([]);
16405
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react17.useState)(null);
16406
- const [draggedItemRect, setDraggedItemRect] = (0, import_react17.useState)(null);
16407
- const footerPointerDragRef = (0, import_react17.useRef)(null);
16408
- const suppressNextClickRef = (0, import_react17.useRef)(false);
16409
- const suppressClickUntilRef = (0, import_react17.useRef)(0);
16410
- const [linkPopover, setLinkPopover] = (0, import_react17.useState)(null);
16411
- const linkPopoverSessionRef = (0, import_react17.useRef)(null);
16412
- const addNavAfterAnchorRef = (0, import_react17.useRef)(null);
16413
- const editContentRef = (0, import_react17.useRef)({});
16414
- const aiSectionsRef = (0, import_react17.useRef)("");
16415
- const brandKitRef = (0, import_react17.useRef)("");
16416
- const stylesRef = (0, import_react17.useRef)("");
16417
- const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
16418
- const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
16419
- const floatingPanelOpenRef = (0, import_react17.useRef)(false);
16420
- const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
16421
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
16422
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
16423
- const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
16424
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
16425
- const [sitePages, setSitePages] = (0, import_react17.useState)([]);
16426
- const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
16427
- const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
16428
- const setLinkPopoverRef = (0, import_react17.useRef)(setLinkPopover);
16429
- const linkPopoverPanelRef = (0, import_react17.useRef)(null);
16430
- const linkPopoverOpenRef = (0, import_react17.useRef)(false);
16431
- const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
15191
+ const [floatingPanel, setFloatingPanel] = (0, import_react16.useState)(null);
15192
+ const floatingPanelOpenRef = (0, import_react16.useRef)(false);
15193
+ floatingPanelOpenRef.current = floatingPanel !== null;
15194
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react16.useState)(null);
15195
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react16.useState)(null);
15196
+ const [editorViewport, setEditorViewport] = (0, import_react16.useState)("desktop");
15197
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react16.useState)(null);
15198
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react16.useState)(null);
15199
+ const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react16.useState)(null);
15200
+ const footerDragRef = (0, import_react16.useRef)(null);
15201
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react16.useState)([]);
15202
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react16.useState)(null);
15203
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react16.useState)(null);
15204
+ const footerPointerDragRef = (0, import_react16.useRef)(null);
15205
+ const suppressNextClickRef = (0, import_react16.useRef)(false);
15206
+ const suppressClickUntilRef = (0, import_react16.useRef)(0);
15207
+ const [linkPopover, setLinkPopover] = (0, import_react16.useState)(null);
15208
+ const linkPopoverSessionRef = (0, import_react16.useRef)(null);
15209
+ const addNavAfterAnchorRef = (0, import_react16.useRef)(null);
15210
+ const editContentRef = (0, import_react16.useRef)({});
15211
+ const aiSectionsRef = (0, import_react16.useRef)("");
15212
+ const pendingDeleteUndoRef = (0, import_react16.useRef)(null);
15213
+ const [sitePages, setSitePages] = (0, import_react16.useState)([]);
15214
+ const [sectionsByPath, setSectionsByPath] = (0, import_react16.useState)({});
15215
+ const sectionsPrefetchGenRef = (0, import_react16.useRef)(0);
15216
+ const setLinkPopoverRef = (0, import_react16.useRef)(setLinkPopover);
15217
+ const linkPopoverPanelRef = (0, import_react16.useRef)(null);
15218
+ const linkPopoverOpenRef = (0, import_react16.useRef)(false);
15219
+ const linkPopoverGraceUntilRef = (0, import_react16.useRef)(0);
16432
15220
  setLinkPopoverRef.current = setLinkPopover;
16433
- setFloatingPanelRef.current = setFloatingPanel;
16434
15221
  linkPopoverSessionRef.current = linkPopover;
16435
- floatingPanelOpenRef.current = Boolean(floatingPanel);
16436
- (0, import_react17.useEffect)(() => {
16437
- const syncViewport = () => {
16438
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
16439
- setEditorViewport((prev) => prev === next ? prev : next);
16440
- };
16441
- syncViewport();
16442
- window.addEventListener("resize", syncViewport);
16443
- return () => window.removeEventListener("resize", syncViewport);
16444
- }, []);
16445
15222
  const {
16446
15223
  navDragRef,
16447
15224
  navDropSlots,
@@ -16474,20 +15251,10 @@ function OhhwellsBridge() {
16474
15251
  getNavigationItemAnchor,
16475
15252
  isDragHandleDisabled
16476
15253
  });
16477
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
16478
- isEditMode,
16479
- editContentRef,
16480
- postToParentRef,
16481
- parentScrollRef,
16482
- navDragRef,
16483
- footerDragRef,
16484
- suppressNextClickRef,
16485
- suppressClickUntilRef
16486
- });
16487
15254
  const bumpLinkPopoverGrace = () => {
16488
15255
  linkPopoverGraceUntilRef.current = Date.now() + 350;
16489
15256
  };
16490
- const runSectionsPrefetch = (0, import_react17.useCallback)((pages) => {
15257
+ const runSectionsPrefetch = (0, import_react16.useCallback)((pages) => {
16491
15258
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
16492
15259
  const gen = ++sectionsPrefetchGenRef.current;
16493
15260
  const paths = pages.map((p) => p.path);
@@ -16506,9 +15273,9 @@ function OhhwellsBridge() {
16506
15273
  );
16507
15274
  });
16508
15275
  }, [isEditMode, pathname]);
16509
- const runSectionsPrefetchRef = (0, import_react17.useRef)(runSectionsPrefetch);
15276
+ const runSectionsPrefetchRef = (0, import_react16.useRef)(runSectionsPrefetch);
16510
15277
  runSectionsPrefetchRef.current = runSectionsPrefetch;
16511
- (0, import_react17.useEffect)(() => {
15278
+ (0, import_react16.useEffect)(() => {
16512
15279
  if (!linkPopover) {
16513
15280
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
16514
15281
  return;
@@ -16536,7 +15303,7 @@ function OhhwellsBridge() {
16536
15303
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
16537
15304
  };
16538
15305
  }, [linkPopover, postToParent2]);
16539
- (0, import_react17.useEffect)(() => {
15306
+ (0, import_react16.useEffect)(() => {
16540
15307
  if (!isEditMode) return;
16541
15308
  const useFixtures = shouldUseDevFixtures();
16542
15309
  if (useFixtures) {
@@ -16560,14 +15327,14 @@ function OhhwellsBridge() {
16560
15327
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
16561
15328
  return () => window.removeEventListener("message", onSitePages);
16562
15329
  }, [isEditMode, postToParent2]);
16563
- (0, import_react17.useEffect)(() => {
15330
+ (0, import_react16.useEffect)(() => {
16564
15331
  if (!isEditMode || shouldUseDevFixtures()) return;
16565
15332
  void loadAllSectionsManifest().then((manifest) => {
16566
15333
  if (Object.keys(manifest).length === 0) return;
16567
15334
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
16568
15335
  });
16569
15336
  }, [isEditMode]);
16570
- (0, import_react17.useEffect)(() => {
15337
+ (0, import_react16.useEffect)(() => {
16571
15338
  const update = () => {
16572
15339
  const el = activeElRef.current ?? selectedElRef.current;
16573
15340
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -16591,10 +15358,10 @@ function OhhwellsBridge() {
16591
15358
  vvp.removeEventListener("resize", update);
16592
15359
  };
16593
15360
  }, []);
16594
- const refreshStateRules = (0, import_react17.useCallback)(() => {
15361
+ const refreshStateRules = (0, import_react16.useCallback)(() => {
16595
15362
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
16596
15363
  }, []);
16597
- const processConfigRequest = (0, import_react17.useCallback)((insertAfterVal) => {
15364
+ const processConfigRequest = (0, import_react16.useCallback)((insertAfterVal) => {
16598
15365
  const tracker = getSectionsTracker();
16599
15366
  let entries = [];
16600
15367
  try {
@@ -16617,7 +15384,7 @@ function OhhwellsBridge() {
16617
15384
  }
16618
15385
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
16619
15386
  }, [isEditMode]);
16620
- const deactivate = (0, import_react17.useCallback)(() => {
15387
+ const deactivate = (0, import_react16.useCallback)(() => {
16621
15388
  const el = activeElRef.current;
16622
15389
  if (!el) return;
16623
15390
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16633,7 +15400,7 @@ function OhhwellsBridge() {
16633
15400
  const original = originalContentRef.current ?? "";
16634
15401
  if (html !== sanitizeHtml(original)) {
16635
15402
  postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
16636
- const h = document.body.scrollHeight;
15403
+ const h = document.documentElement.scrollHeight;
16637
15404
  if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
16638
15405
  }
16639
15406
  }
@@ -16658,12 +15425,12 @@ function OhhwellsBridge() {
16658
15425
  setToolbarShowEditLink(false);
16659
15426
  postToParent2({ type: "ow:exit-edit" });
16660
15427
  }, [postToParent2]);
16661
- const clearSelectedAttr = (0, import_react17.useCallback)(() => {
15428
+ const clearSelectedAttr = (0, import_react16.useCallback)(() => {
16662
15429
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16663
15430
  el.removeAttribute("data-ohw-selected");
16664
15431
  });
16665
15432
  }, []);
16666
- const deselect = (0, import_react17.useCallback)(() => {
15433
+ const deselect = (0, import_react16.useCallback)(() => {
16667
15434
  clearSelectedAttr();
16668
15435
  selectedElRef.current = null;
16669
15436
  selectedHrefKeyRef.current = null;
@@ -16692,20 +15459,20 @@ function OhhwellsBridge() {
16692
15459
  setToolbarVariant("none");
16693
15460
  }
16694
15461
  }, [clearSelectedAttr]);
16695
- const markSelected = (0, import_react17.useCallback)((el) => {
15462
+ const markSelected = (0, import_react16.useCallback)((el) => {
16696
15463
  clearSelectedAttr();
16697
15464
  el.removeAttribute("data-ohw-hovered");
16698
15465
  el.setAttribute("data-ohw-selected", "");
16699
15466
  }, [clearSelectedAttr]);
16700
- const isSelectedForHover = (0, import_react17.useCallback)((el) => {
15467
+ const isSelectedForHover = (0, import_react16.useCallback)((el) => {
16701
15468
  if (!el) return false;
16702
15469
  return [selectedElRef.current, activeElRef.current].some(
16703
15470
  (busy) => busy && (el === busy || busy.contains(el) || el.contains(busy))
16704
15471
  );
16705
15472
  }, []);
16706
- const isSelectedForHoverRef = (0, import_react17.useRef)(isSelectedForHover);
15473
+ const isSelectedForHoverRef = (0, import_react16.useRef)(isSelectedForHover);
16707
15474
  isSelectedForHoverRef.current = isSelectedForHover;
16708
- const resolveHrefKeyElement = (0, import_react17.useCallback)((hrefKey) => {
15475
+ const resolveHrefKeyElement = (0, import_react16.useCallback)((hrefKey) => {
16709
15476
  if (isFooterHrefKey(hrefKey)) {
16710
15477
  return document.querySelector(
16711
15478
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16720,7 +15487,7 @@ function OhhwellsBridge() {
16720
15487
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16721
15488
  );
16722
15489
  }, []);
16723
- const resyncSelectedNavigationItem = (0, import_react17.useCallback)(() => {
15490
+ const resyncSelectedNavigationItem = (0, import_react16.useCallback)(() => {
16724
15491
  const hrefKey = selectedHrefKeyRef.current;
16725
15492
  if (hrefKey) {
16726
15493
  const link = resolveHrefKeyElement(hrefKey);
@@ -16758,7 +15525,7 @@ function OhhwellsBridge() {
16758
15525
  );
16759
15526
  }
16760
15527
  }, [resolveHrefKeyElement]);
16761
- const reselectNavigationItem = (0, import_react17.useCallback)((navAnchor) => {
15528
+ const reselectNavigationItem = (0, import_react16.useCallback)((navAnchor) => {
16762
15529
  selectedElRef.current = navAnchor;
16763
15530
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16764
15531
  selectedFooterColAttrRef.current = null;
@@ -16789,7 +15556,7 @@ function OhhwellsBridge() {
16789
15556
  setToolbarShowEditLink(false);
16790
15557
  setActiveCommands(/* @__PURE__ */ new Set());
16791
15558
  }, [markSelected]);
16792
- const commitNavigationTextEdit = (0, import_react17.useCallback)((navAnchor) => {
15559
+ const commitNavigationTextEdit = (0, import_react16.useCallback)((navAnchor) => {
16793
15560
  const el = activeElRef.current;
16794
15561
  if (!el) return;
16795
15562
  const key = el.dataset.ohwKey;
@@ -16803,7 +15570,7 @@ function OhhwellsBridge() {
16803
15570
  const original = originalContentRef.current ?? "";
16804
15571
  if (html !== sanitizeHtml(original)) {
16805
15572
  postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
16806
- const h = document.body.scrollHeight;
15573
+ const h = document.documentElement.scrollHeight;
16807
15574
  if (h > 50) postToParent2({ type: "ow:height", height: h });
16808
15575
  }
16809
15576
  }
@@ -16822,7 +15589,7 @@ function OhhwellsBridge() {
16822
15589
  postToParent2({ type: "ow:exit-edit" });
16823
15590
  reselectNavigationItem(navAnchor);
16824
15591
  }, [postToParent2, reselectNavigationItem]);
16825
- const handleAddTopLevelNavItem = (0, import_react17.useCallback)(() => {
15592
+ const handleAddTopLevelNavItem = (0, import_react16.useCallback)(() => {
16826
15593
  const items = listNavbarRootItems();
16827
15594
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16828
15595
  deselectRef.current();
@@ -16834,7 +15601,7 @@ function OhhwellsBridge() {
16834
15601
  intent: "add-nav"
16835
15602
  });
16836
15603
  }, []);
16837
- const maybeWarnNavLinkDropdownConflict = (0, import_react17.useCallback)(
15604
+ const maybeWarnNavLinkDropdownConflict = (0, import_react16.useCallback)(
16838
15605
  (anchor) => {
16839
15606
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16840
15607
  if (!navDropdownsOpenOnClick()) return;
@@ -16847,7 +15614,7 @@ function OhhwellsBridge() {
16847
15614
  },
16848
15615
  [postToParent2]
16849
15616
  );
16850
- const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
15617
+ const handleNavDropdownOpenChange = (0, import_react16.useCallback)((open) => {
16851
15618
  const selected = selectedElRef.current;
16852
15619
  if (!selected || !isNavigationItem2(selected)) return;
16853
15620
  setNavGroupForceOpen(selected, open);
@@ -16859,7 +15626,7 @@ function OhhwellsBridge() {
16859
15626
  }
16860
15627
  });
16861
15628
  }, []);
16862
- const handleFooterHeadingVisibleChange = (0, import_react17.useCallback)(
15629
+ const handleFooterHeadingVisibleChange = (0, import_react16.useCallback)(
16863
15630
  (visible) => {
16864
15631
  const selected = selectedElRef.current;
16865
15632
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16883,7 +15650,7 @@ function OhhwellsBridge() {
16883
15650
  },
16884
15651
  [postToParent2]
16885
15652
  );
16886
- const enterEditOnNewItem = (0, import_react17.useCallback)((anchor) => {
15653
+ const enterEditOnNewItem = (0, import_react16.useCallback)((anchor) => {
16887
15654
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16888
15655
  if (!label) {
16889
15656
  selectRef.current(anchor);
@@ -16892,8 +15659,8 @@ function OhhwellsBridge() {
16892
15659
  setNavGroupForceOpen(anchor, true);
16893
15660
  activateRef.current(label);
16894
15661
  }, []);
16895
- const pendingSocialAddRef = (0, import_react17.useRef)(null);
16896
- const handleAddChildItem = (0, import_react17.useCallback)(() => {
15662
+ const pendingSocialAddRef = (0, import_react16.useRef)(null);
15663
+ const handleAddChildItem = (0, import_react16.useCallback)(() => {
16897
15664
  const selected = selectedElRef.current;
16898
15665
  if (!selected) return;
16899
15666
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -17002,7 +15769,7 @@ function OhhwellsBridge() {
17002
15769
  enterEditOnNewItem(result.anchor);
17003
15770
  });
17004
15771
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
17005
- const handleAddFooterColumn = (0, import_react17.useCallback)(() => {
15772
+ const handleAddFooterColumn = (0, import_react16.useCallback)(() => {
17006
15773
  if (!canAddFooterColumn()) {
17007
15774
  postToParent2({
17008
15775
  type: "ow:toast",
@@ -17023,7 +15790,7 @@ function OhhwellsBridge() {
17023
15790
  selectRef.current(result.firstLink);
17024
15791
  });
17025
15792
  }, [postToParent2]);
17026
- const clearFooterDragVisuals = (0, import_react17.useCallback)(() => {
15793
+ const clearFooterDragVisuals = (0, import_react16.useCallback)(() => {
17027
15794
  footerDragRef.current = null;
17028
15795
  setSiblingHintRects([]);
17029
15796
  setFooterDropSlots([]);
@@ -17032,7 +15799,7 @@ function OhhwellsBridge() {
17032
15799
  setIsItemDragging(false);
17033
15800
  unlockFooterDragInteraction();
17034
15801
  }, []);
17035
- const refreshFooterDragVisuals = (0, import_react17.useCallback)((session, activeSlot, clientX, clientY) => {
15802
+ const refreshFooterDragVisuals = (0, import_react16.useCallback)((session, activeSlot, clientX, clientY) => {
17036
15803
  const dragged = session.draggedEl;
17037
15804
  setDraggedItemRect(dragged.getBoundingClientRect());
17038
15805
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -17064,13 +15831,13 @@ function OhhwellsBridge() {
17064
15831
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
17065
15832
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
17066
15833
  }, []);
17067
- const refreshFooterDragVisualsRef = (0, import_react17.useRef)(refreshFooterDragVisuals);
15834
+ const refreshFooterDragVisualsRef = (0, import_react16.useRef)(refreshFooterDragVisuals);
17068
15835
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
17069
- const commitFooterDragRef = (0, import_react17.useRef)(() => {
15836
+ const commitFooterDragRef = (0, import_react16.useRef)(() => {
17070
15837
  });
17071
- const beginFooterDragRef = (0, import_react17.useRef)(() => {
15838
+ const beginFooterDragRef = (0, import_react16.useRef)(() => {
17072
15839
  });
17073
- const beginFooterDrag = (0, import_react17.useCallback)(
15840
+ const beginFooterDrag = (0, import_react16.useCallback)(
17074
15841
  (session) => {
17075
15842
  const rect = session.draggedEl.getBoundingClientRect();
17076
15843
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -17090,7 +15857,7 @@ function OhhwellsBridge() {
17090
15857
  [refreshFooterDragVisuals]
17091
15858
  );
17092
15859
  beginFooterDragRef.current = beginFooterDrag;
17093
- const commitFooterDrag = (0, import_react17.useCallback)(
15860
+ const commitFooterDrag = (0, import_react16.useCallback)(
17094
15861
  (clientX, clientY) => {
17095
15862
  const session = footerDragRef.current;
17096
15863
  if (!session) {
@@ -17219,7 +15986,7 @@ function OhhwellsBridge() {
17219
15986
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
17220
15987
  );
17221
15988
  commitFooterDragRef.current = commitFooterDrag;
17222
- const startFooterLinkDrag = (0, import_react17.useCallback)(
15989
+ const startFooterLinkDrag = (0, import_react16.useCallback)(
17223
15990
  (anchor, clientX, clientY, wasSelected) => {
17224
15991
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
17225
15992
  if (!hrefKey) return false;
@@ -17255,7 +16022,7 @@ function OhhwellsBridge() {
17255
16022
  },
17256
16023
  [beginFooterDrag]
17257
16024
  );
17258
- const startFooterColumnDrag = (0, import_react17.useCallback)(
16025
+ const startFooterColumnDrag = (0, import_react16.useCallback)(
17259
16026
  (columnEl, clientX, clientY, wasSelected) => {
17260
16027
  const columns = listFooterColumns();
17261
16028
  const idx = columns.indexOf(columnEl);
@@ -17275,7 +16042,7 @@ function OhhwellsBridge() {
17275
16042
  },
17276
16043
  [beginFooterDrag]
17277
16044
  );
17278
- const handleItemDragStart = (0, import_react17.useCallback)(
16045
+ const handleItemDragStart = (0, import_react16.useCallback)(
17279
16046
  (e) => {
17280
16047
  const selected = selectedElRef.current;
17281
16048
  if (!selected) {
@@ -17295,7 +16062,7 @@ function OhhwellsBridge() {
17295
16062
  },
17296
16063
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
17297
16064
  );
17298
- const handleItemDragEnd = (0, import_react17.useCallback)(
16065
+ const handleItemDragEnd = (0, import_react16.useCallback)(
17299
16066
  (e) => {
17300
16067
  if (footerDragRef.current) {
17301
16068
  const x = e?.clientX;
@@ -17321,7 +16088,7 @@ function OhhwellsBridge() {
17321
16088
  },
17322
16089
  [commitFooterDrag, commitNavDrag, navDragRef]
17323
16090
  );
17324
- const handleItemChromePointerDown = (0, import_react17.useCallback)((e) => {
16091
+ const handleItemChromePointerDown = (0, import_react16.useCallback)((e) => {
17325
16092
  if (e.button !== 0) return;
17326
16093
  const selected = selectedElRef.current;
17327
16094
  if (!selected) return;
@@ -17352,7 +16119,7 @@ function OhhwellsBridge() {
17352
16119
  }
17353
16120
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
17354
16121
  }, [armNavPressFromChrome]);
17355
- const handleItemChromeClick = (0, import_react17.useCallback)((clientX, clientY) => {
16122
+ const handleItemChromeClick = (0, import_react16.useCallback)((clientX, clientY) => {
17356
16123
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
17357
16124
  suppressNextClickRef.current = false;
17358
16125
  return;
@@ -17365,7 +16132,7 @@ function OhhwellsBridge() {
17365
16132
  }, []);
17366
16133
  reselectNavigationItemRef.current = reselectNavigationItem;
17367
16134
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
17368
- const select = (0, import_react17.useCallback)((anchor) => {
16135
+ const select = (0, import_react16.useCallback)((anchor) => {
17369
16136
  if (!isNavigationItem2(anchor)) return;
17370
16137
  if (activeElRef.current) deactivate();
17371
16138
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -17408,7 +16175,7 @@ function OhhwellsBridge() {
17408
16175
  setFloatingPanel(null);
17409
16176
  setLogoSizeDraft(null);
17410
16177
  }, [deactivate, markSelected]);
17411
- const selectFrame = (0, import_react17.useCallback)((el) => {
16178
+ const selectFrame = (0, import_react16.useCallback)((el) => {
17412
16179
  if (!isNavigationContainer(el)) return;
17413
16180
  if (activeElRef.current) deactivate();
17414
16181
  aiSectionApiRef.current?.selectFromElement(el);
@@ -17459,7 +16226,7 @@ function OhhwellsBridge() {
17459
16226
  setFloatingPanel(null);
17460
16227
  setLogoSizeDraft(null);
17461
16228
  }, [deactivate, markSelected, postToParent2]);
17462
- const selectLogo = (0, import_react17.useCallback)(
16229
+ const selectLogo = (0, import_react16.useCallback)(
17463
16230
  (logoEl) => {
17464
16231
  if (activeElRef.current) deactivate();
17465
16232
  selectedElRef.current = logoEl;
@@ -17488,7 +16255,7 @@ function OhhwellsBridge() {
17488
16255
  },
17489
16256
  [deactivate, markSelected]
17490
16257
  );
17491
- const openLogoSizePanel = (0, import_react17.useCallback)((logoEl) => {
16258
+ const openLogoSizePanel = (0, import_react16.useCallback)((logoEl) => {
17492
16259
  const placement = getLogoPlacement(logoEl);
17493
16260
  const draft = readLogoSizeState(editContentRef.current, placement);
17494
16261
  setLogoSizeDraft(draft);
@@ -17501,7 +16268,7 @@ function OhhwellsBridge() {
17501
16268
  placement
17502
16269
  });
17503
16270
  }, []);
17504
- const openSocialsDisplayPanel = (0, import_react17.useCallback)((row) => {
16271
+ const openSocialsDisplayPanel = (0, import_react16.useCallback)((row) => {
17505
16272
  setParentScrollSnap(parentScrollRef.current);
17506
16273
  setFloatingPanel({
17507
16274
  key: "socials-display",
@@ -17511,11 +16278,11 @@ function OhhwellsBridge() {
17511
16278
  row
17512
16279
  });
17513
16280
  }, []);
17514
- const isEditModeRef = (0, import_react17.useRef)(false);
17515
- const requestMissingSocialIconsRef = (0, import_react17.useRef)(() => {
16281
+ const isEditModeRef = (0, import_react16.useRef)(false);
16282
+ const requestMissingSocialIconsRef = (0, import_react16.useRef)(() => {
17516
16283
  });
17517
- const askedSocialIconsRef = (0, import_react17.useRef)(/* @__PURE__ */ new Set());
17518
- const requestMissingSocialIcons = (0, import_react17.useCallback)(() => {
16284
+ const askedSocialIconsRef = (0, import_react16.useRef)(/* @__PURE__ */ new Set());
16285
+ const requestMissingSocialIcons = (0, import_react16.useCallback)(() => {
17519
16286
  const items = Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).filter((row) => socialsDisplayFor(row, editContentRef.current).icon).flatMap((row) => {
17520
16287
  const missing = socialsMissingIcons(row);
17521
16288
  listSocialItems(row).forEach((item) => ensureIconSlot(item));
@@ -17527,7 +16294,7 @@ function OhhwellsBridge() {
17527
16294
  }, []);
17528
16295
  requestMissingSocialIconsRef.current = requestMissingSocialIcons;
17529
16296
  isEditModeRef.current = isEditMode;
17530
- const changeSocialsDisplay = (0, import_react17.useCallback)(
16297
+ const changeSocialsDisplay = (0, import_react16.useCallback)(
17531
16298
  (row, next) => {
17532
16299
  if (next.icon) {
17533
16300
  const missing = socialsMissingIcons(row);
@@ -17551,17 +16318,17 @@ function OhhwellsBridge() {
17551
16318
  },
17552
16319
  []
17553
16320
  );
17554
- const closeFloatingPanelOnly = (0, import_react17.useCallback)(() => {
16321
+ const closeFloatingPanelOnly = (0, import_react16.useCallback)(() => {
17555
16322
  setFloatingPanel(null);
17556
16323
  setLogoSizeDraft(null);
17557
16324
  }, []);
17558
16325
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17559
- const closeFloatingPanelAndDeselect = (0, import_react17.useCallback)(() => {
16326
+ const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
17560
16327
  setFloatingPanel(null);
17561
16328
  setLogoSizeDraft(null);
17562
16329
  deselectRef.current();
17563
16330
  }, []);
17564
- (0, import_react17.useEffect)(() => {
16331
+ (0, import_react16.useEffect)(() => {
17565
16332
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
17566
16333
  if (!session || !logoSizeDraft) {
17567
16334
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -17580,7 +16347,7 @@ function OhhwellsBridge() {
17580
16347
  max: LOGO_SIZE_MAX
17581
16348
  });
17582
16349
  }, [floatingPanel, logoSizeDraft, editorViewport]);
17583
- const persistLogoSizeDraft = (0, import_react17.useCallback)(
16350
+ const persistLogoSizeDraft = (0, import_react16.useCallback)(
17584
16351
  (placement, draft) => {
17585
16352
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
17586
16353
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -17620,7 +16387,7 @@ function OhhwellsBridge() {
17620
16387
  },
17621
16388
  [postToParent2]
17622
16389
  );
17623
- const activate = (0, import_react17.useCallback)((el, options) => {
16390
+ const activate = (0, import_react16.useCallback)((el, options) => {
17624
16391
  if (activeElRef.current === el) return;
17625
16392
  document.querySelectorAll("[data-ohw-hovered]").forEach((hovered) => {
17626
16393
  hovered.removeAttribute("data-ohw-hovered");
@@ -17718,8 +16485,8 @@ function OhhwellsBridge() {
17718
16485
  openLogoSizePanelRef.current = openLogoSizePanel;
17719
16486
  deselectRef.current = deselect;
17720
16487
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17721
- const lastSiteWideScopeRef = (0, import_react17.useRef)(null);
17722
- (0, import_react17.useEffect)(() => {
16488
+ const lastSiteWideScopeRef = (0, import_react16.useRef)(null);
16489
+ (0, import_react16.useEffect)(() => {
17723
16490
  if (!isEditMode) {
17724
16491
  if (lastSiteWideScopeRef.current !== false) {
17725
16492
  lastSiteWideScopeRef.current = false;
@@ -17745,34 +16512,22 @@ function OhhwellsBridge() {
17745
16512
  isFooterFrameSelection,
17746
16513
  postToParent2
17747
16514
  ]);
17748
- (0, import_react17.useLayoutEffect)(() => {
16515
+ (0, import_react16.useLayoutEffect)(() => {
17749
16516
  if (!subdomain || isEditMode) {
17750
16517
  setFetchState("done");
17751
16518
  return;
17752
16519
  }
17753
16520
  const applyContent = (content) => {
17754
16521
  const imageLoads = [];
17755
- if (typeof content[BRAND_KIT_KEY] === "string") {
17756
- brandKitRef.current = content[BRAND_KIT_KEY];
17757
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17758
- }
17759
16522
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17760
16523
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17761
16524
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17762
16525
  }
17763
- if (typeof content[STYLE_STORE_KEY] === "string") {
17764
- stylesRef.current = content[STYLE_STORE_KEY];
17765
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17766
- }
17767
- applyBrandChrome(content);
17768
16526
  for (const [key, val] of Object.entries(content)) {
17769
16527
  if (key === "__ohw_sections") continue;
17770
16528
  if (key === AI_SECTIONS_KEY) continue;
17771
16529
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17772
16530
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17773
- if (key === BRAND_KIT_KEY) continue;
17774
- if (key === STYLE_STORE_KEY) continue;
17775
- if (BRAND_CHROME_KEYS.has(key)) continue;
17776
16531
  if (applyVideoSettingNode(key, val)) continue;
17777
16532
  if (applyCarouselNode(key, val)) continue;
17778
16533
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17833,9 +16588,7 @@ function OhhwellsBridge() {
17833
16588
  let cancelled = false;
17834
16589
  setFetchState("loading");
17835
16590
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17836
- const initialPath = pathname;
17837
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17838
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16591
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17839
16592
  if (cancelled) return;
17840
16593
  const content = data?.content ?? {};
17841
16594
  contentCache.set(subdomain, content);
@@ -17848,7 +16601,7 @@ function OhhwellsBridge() {
17848
16601
  cancelled = true;
17849
16602
  };
17850
16603
  }, [subdomain, isEditMode]);
17851
- (0, import_react17.useEffect)(() => {
16604
+ (0, import_react16.useEffect)(() => {
17852
16605
  if (!isEditMode) return;
17853
16606
  const resolveIndex = (form, clientY) => {
17854
16607
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17889,7 +16642,7 @@ function OhhwellsBridge() {
17889
16642
  window.removeEventListener("drop", onDrop, true);
17890
16643
  };
17891
16644
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17892
- (0, import_react17.useEffect)(() => {
16645
+ (0, import_react16.useEffect)(() => {
17893
16646
  if (!isEditMode) return;
17894
16647
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17895
16648
  markFormFields(form);
@@ -17901,7 +16654,7 @@ function OhhwellsBridge() {
17901
16654
  });
17902
16655
  return () => observer.disconnect();
17903
16656
  }, [isEditMode, fetchState, pathname]);
17904
- (0, import_react17.useEffect)(() => {
16657
+ (0, import_react16.useEffect)(() => {
17905
16658
  if (!isEditMode) return;
17906
16659
  let saveTimer = null;
17907
16660
  const onInput = (e) => {
@@ -17923,14 +16676,14 @@ function OhhwellsBridge() {
17923
16676
  document.addEventListener("input", onInput, true);
17924
16677
  return () => document.removeEventListener("input", onInput, true);
17925
16678
  }, [isEditMode, persistFields]);
17926
- (0, import_react17.useEffect)(() => {
16679
+ (0, import_react16.useEffect)(() => {
17927
16680
  if (isEditMode || fetchState !== "done") return;
17928
16681
  const content = contentCache.get(subdomain) ?? {};
17929
16682
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17930
16683
  reconcileFieldsFromContent(form, content);
17931
16684
  });
17932
16685
  }, [isEditMode, fetchState, subdomain]);
17933
- (0, import_react17.useEffect)(() => {
16686
+ (0, import_react16.useEffect)(() => {
17934
16687
  if (!isEditMode) return;
17935
16688
  const swallow = (e) => {
17936
16689
  const target = e.target;
@@ -17939,12 +16692,12 @@ function OhhwellsBridge() {
17939
16692
  document.addEventListener("submit", swallow, true);
17940
16693
  return () => document.removeEventListener("submit", swallow, true);
17941
16694
  }, [isEditMode]);
17942
- (0, import_react17.useEffect)(() => {
16695
+ (0, import_react16.useEffect)(() => {
17943
16696
  if (isEditMode || fetchState !== "done") return;
17944
16697
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17945
16698
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17946
16699
  }, [isEditMode, fetchState, subdomain]);
17947
- (0, import_react17.useEffect)(() => {
16700
+ (0, import_react16.useEffect)(() => {
17948
16701
  if (!subdomain || isEditMode) return;
17949
16702
  let debounceTimer = null;
17950
16703
  let observer = null;
@@ -17955,25 +16708,10 @@ function OhhwellsBridge() {
17955
16708
  initSectionInstancesFromContent(content, window.location.pathname);
17956
16709
  observer?.disconnect();
17957
16710
  try {
17958
- applyBrandChrome(content);
17959
- if (typeof content[BRAND_KIT_KEY] === "string") {
17960
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17961
- }
17962
- if (typeof content[AI_SECTIONS_KEY] === "string") {
17963
- applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17964
- }
17965
- if (typeof content[STYLE_STORE_KEY] === "string") {
17966
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17967
- }
17968
16711
  for (const [key, val] of Object.entries(content)) {
17969
16712
  if (key === "__ohw_sections") continue;
17970
- if (key === AI_SECTIONS_KEY) continue;
17971
16713
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17972
16714
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17973
- if (key === BRAND_KIT_KEY) continue;
17974
- if (key === STYLE_STORE_KEY) continue;
17975
- if (key === STYLE_STORE_KEY) continue;
17976
- if (BRAND_CHROME_KEYS.has(key)) continue;
17977
16715
  if (applyVideoSettingNode(key, val)) continue;
17978
16716
  if (applyCarouselNode(key, val)) continue;
17979
16717
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -18019,17 +16757,6 @@ function OhhwellsBridge() {
18019
16757
  debounceTimer = setTimeout(applyFromCache, 150);
18020
16758
  };
18021
16759
  applyFromCache();
18022
- const pathCacheKey = `${subdomain}::${pathname}`;
18023
- if (!fetchedContentPaths.has(pathCacheKey)) {
18024
- fetchedContentPaths.add(pathCacheKey);
18025
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
18026
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
18027
- if (!data?.content) return;
18028
- contentCache.set(subdomain, data.content);
18029
- applyFromCache();
18030
- }).catch(() => {
18031
- });
18032
- }
18033
16760
  observer = new MutationObserver(scheduleApply);
18034
16761
  observer.observe(document.body, { childList: true, subtree: true });
18035
16762
  return () => {
@@ -18037,16 +16764,16 @@ function OhhwellsBridge() {
18037
16764
  if (debounceTimer) clearTimeout(debounceTimer);
18038
16765
  };
18039
16766
  }, [subdomain, isEditMode, pathname]);
18040
- (0, import_react17.useLayoutEffect)(() => {
16767
+ (0, import_react16.useLayoutEffect)(() => {
18041
16768
  const el = document.getElementById("ohw-loader");
18042
16769
  if (!el) return;
18043
16770
  const visible = Boolean(subdomain) && fetchState !== "done";
18044
16771
  el.style.display = visible ? "flex" : "none";
18045
16772
  }, [subdomain, fetchState]);
18046
- (0, import_react17.useEffect)(() => {
16773
+ (0, import_react16.useEffect)(() => {
18047
16774
  postToParent2({ type: "ow:navigation", path: pathname });
18048
16775
  }, [pathname, postToParent2]);
18049
- (0, import_react17.useEffect)(() => {
16776
+ (0, import_react16.useEffect)(() => {
18050
16777
  if (!isEditMode) return;
18051
16778
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
18052
16779
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -18054,7 +16781,7 @@ function OhhwellsBridge() {
18054
16781
  deselectRef.current();
18055
16782
  deactivateRef.current();
18056
16783
  }, [pathname, isEditMode]);
18057
- (0, import_react17.useEffect)(() => {
16784
+ (0, import_react16.useEffect)(() => {
18058
16785
  const contentForNav = () => {
18059
16786
  if (isEditMode) return editContentRef.current;
18060
16787
  if (!subdomain) return {};
@@ -18123,36 +16850,35 @@ function OhhwellsBridge() {
18123
16850
  observer?.disconnect();
18124
16851
  };
18125
16852
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
18126
- (0, import_react17.useEffect)(() => {
16853
+ (0, import_react16.useEffect)(() => {
18127
16854
  if (!isEditMode) return;
18128
- let lastPosted = 0;
18129
16855
  const measure = () => {
18130
16856
  const h = document.body.scrollHeight;
18131
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
18132
- lastPosted = h;
18133
- postToParent2({ type: "ow:height", height: h });
18134
- }
18135
- };
18136
- let raf = null;
18137
- const schedule = () => {
18138
- if (raf != null) return;
18139
- raf = requestAnimationFrame(() => {
18140
- raf = null;
18141
- measure();
18142
- });
16857
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
18143
16858
  };
18144
16859
  const t1 = setTimeout(measure, 50);
18145
16860
  const t2 = setTimeout(measure, 500);
18146
- const ro = new ResizeObserver(schedule);
18147
- ro.observe(document.body);
16861
+ let lastWidth = window.innerWidth;
16862
+ let resizeTimers = [];
16863
+ const clearResizeTimers = () => {
16864
+ resizeTimers.forEach(clearTimeout);
16865
+ resizeTimers = [];
16866
+ };
16867
+ const handleResize = () => {
16868
+ if (window.innerWidth === lastWidth) return;
16869
+ lastWidth = window.innerWidth;
16870
+ clearResizeTimers();
16871
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
16872
+ };
16873
+ window.addEventListener("resize", handleResize);
18148
16874
  return () => {
18149
16875
  clearTimeout(t1);
18150
16876
  clearTimeout(t2);
18151
- if (raf != null) cancelAnimationFrame(raf);
18152
- ro.disconnect();
16877
+ clearResizeTimers();
16878
+ window.removeEventListener("resize", handleResize);
18153
16879
  };
18154
16880
  }, [pathname, isEditMode, postToParent2]);
18155
- (0, import_react17.useEffect)(() => {
16881
+ (0, import_react16.useEffect)(() => {
18156
16882
  if (!subdomainFromQuery || isEditMode) return;
18157
16883
  const handleClick = (e) => {
18158
16884
  const anchor = e.target.closest("a");
@@ -18168,7 +16894,7 @@ function OhhwellsBridge() {
18168
16894
  document.addEventListener("click", handleClick, true);
18169
16895
  return () => document.removeEventListener("click", handleClick, true);
18170
16896
  }, [subdomainFromQuery, isEditMode, router]);
18171
- (0, import_react17.useEffect)(() => {
16897
+ (0, import_react16.useEffect)(() => {
18172
16898
  if (!isEditMode) {
18173
16899
  editStylesRef.current?.base.remove();
18174
16900
  editStylesRef.current?.forceHover.remove();
@@ -18390,7 +17116,6 @@ function OhhwellsBridge() {
18390
17116
  return;
18391
17117
  }
18392
17118
  const target = e.target;
18393
- if (target.closest("[data-ohw-ai-review]")) return;
18394
17119
  if (target.closest("[data-ohw-toolbar]")) return;
18395
17120
  if (target.closest("[data-ohw-state-toggle]")) return;
18396
17121
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18402,9 +17127,6 @@ function OhhwellsBridge() {
18402
17127
  )) {
18403
17128
  return;
18404
17129
  }
18405
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
18406
- clearMediaSelectionRef.current();
18407
- }
18408
17130
  {
18409
17131
  const formEl = getFormElement(target);
18410
17132
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -18559,11 +17281,8 @@ function OhhwellsBridge() {
18559
17281
  if (isMediaEditable(editable) && !buttonOnMedia) {
18560
17282
  e.preventDefault();
18561
17283
  e.stopPropagation();
18562
- if (selectedMediaElRef.current === editable) {
18563
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18564
- } else {
18565
- selectMediaElementRef.current(editable);
18566
- }
17284
+ aiSectionApiRef.current?.selectFromElement(editable);
17285
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
18567
17286
  return;
18568
17287
  }
18569
17288
  const socialItem = getSocialItem(editable);
@@ -18699,7 +17418,6 @@ function OhhwellsBridge() {
18699
17418
  };
18700
17419
  const handleDblClick = (e) => {
18701
17420
  const target = e.target;
18702
- if (target.closest("[data-ohw-ai-review]")) return;
18703
17421
  if (target.closest("[data-ohw-toolbar]")) return;
18704
17422
  if (target.closest("[data-ohw-state-toggle]")) return;
18705
17423
  if (target.closest("[data-ohw-max-badge]")) return;
@@ -18751,9 +17469,6 @@ function OhhwellsBridge() {
18751
17469
  setHoveredItemRect(null);
18752
17470
  hoveredNavContainerRef.current = null;
18753
17471
  setHoveredNavContainerRect(null);
18754
- siblingHintElRef.current = null;
18755
- setSiblingHintRect(null);
18756
- setSiblingHintRects([]);
18757
17472
  return;
18758
17473
  }
18759
17474
  {
@@ -18872,6 +17587,7 @@ function OhhwellsBridge() {
18872
17587
  hoveredNavContainerRef.current = null;
18873
17588
  setHoveredNavContainerRect(null);
18874
17589
  hoveredItemElRef.current = editable;
17590
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
18875
17591
  }
18876
17592
  }
18877
17593
  }
@@ -19168,7 +17884,7 @@ function OhhwellsBridge() {
19168
17884
  }
19169
17885
  };
19170
17886
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
19171
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17887
+ if (linkPopoverOpenRef.current) {
19172
17888
  if (hoveredImageRef.current) {
19173
17889
  hoveredImageRef.current = null;
19174
17890
  hoveredImageHasTextOverlapRef.current = false;
@@ -19502,9 +18218,7 @@ function OhhwellsBridge() {
19502
18218
  return;
19503
18219
  }
19504
18220
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
19505
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
19506
- (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
19507
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18221
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
19508
18222
  const ZONE = 20;
19509
18223
  for (let i = 0; i < sections.length; i++) {
19510
18224
  const a = sections[i];
@@ -19533,7 +18247,8 @@ function OhhwellsBridge() {
19533
18247
  };
19534
18248
  const handleMouseMove = (e) => {
19535
18249
  const { clientX, clientY } = e;
19536
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
18250
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18251
+ if (isOverEditorChrome(clientX, clientY)) {
19537
18252
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
19538
18253
  formHoverElRef.current = null;
19539
18254
  setFormHoverRect(null);
@@ -19541,12 +18256,6 @@ function OhhwellsBridge() {
19541
18256
  setHoveredItemRect(null);
19542
18257
  hoveredNavContainerRef.current = null;
19543
18258
  setHoveredNavContainerRect(null);
19544
- siblingHintElRef.current = null;
19545
- setSiblingHintRect(null);
19546
- setSiblingHintRects([]);
19547
- dismissImageHover();
19548
- clearImageHover();
19549
- setSectionGap(null);
19550
18259
  return;
19551
18260
  }
19552
18261
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -19558,11 +18267,7 @@ function OhhwellsBridge() {
19558
18267
  if (e.data?.type !== "ow:pointer-sync") return;
19559
18268
  const { clientX, clientY } = e.data;
19560
18269
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
19561
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
19562
- dismissImageHover();
19563
- clearImageHover();
19564
- return;
19565
- }
18270
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
19566
18271
  if (probeSocialsRowAt(clientX, clientY)) return;
19567
18272
  probeSectionGapAt(clientX, clientY);
19568
18273
  probeImageAt(clientX, clientY);
@@ -19837,7 +18542,7 @@ function OhhwellsBridge() {
19837
18542
  timers.set(key, setTimeout(() => {
19838
18543
  timers.delete(key);
19839
18544
  postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
19840
- const h = document.body.scrollHeight;
18545
+ const h = document.documentElement.scrollHeight;
19841
18546
  if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19842
18547
  }, 400));
19843
18548
  };
@@ -19845,19 +18550,10 @@ function OhhwellsBridge() {
19845
18550
  if (e.data?.type !== "ow:hydrate") return;
19846
18551
  const content = e.data.content;
19847
18552
  if (!content) return;
19848
- if (typeof content[BRAND_KIT_KEY] === "string") {
19849
- brandKitRef.current = content[BRAND_KIT_KEY];
19850
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19851
- }
19852
18553
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19853
18554
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19854
18555
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19855
18556
  }
19856
- if (typeof content[STYLE_STORE_KEY] === "string") {
19857
- stylesRef.current = content[STYLE_STORE_KEY];
19858
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19859
- }
19860
- applyBrandChrome(content);
19861
18557
  let sectionsJson = null;
19862
18558
  for (const [key, val] of Object.entries(content)) {
19863
18559
  if (key === "__ohw_sections") {
@@ -19867,9 +18563,6 @@ function OhhwellsBridge() {
19867
18563
  if (key === AI_SECTIONS_KEY) continue;
19868
18564
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19869
18565
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19870
- if (key === BRAND_KIT_KEY) continue;
19871
- if (key === STYLE_STORE_KEY) continue;
19872
- if (BRAND_CHROME_KEYS.has(key)) continue;
19873
18566
  if (applyVideoSettingNode(key, val)) continue;
19874
18567
  if (applyCarouselNode(key, val)) continue;
19875
18568
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19883,8 +18576,6 @@ function OhhwellsBridge() {
19883
18576
  if (video && video.src !== val) applyVideoSrc(video, val);
19884
18577
  } else if (el.dataset.ohwEditable === "link") {
19885
18578
  applyLinkHref(el, val);
19886
- } else if (el.dataset.ohwEditable === "icon") {
19887
- applyIconMarkup(el, val);
19888
18579
  } else if (isIconMarkupValue(val)) {
19889
18580
  } else {
19890
18581
  el.innerHTML = val;
@@ -19905,7 +18596,7 @@ function OhhwellsBridge() {
19905
18596
  reconcileFooterOrderFromContent(editContentRef.current);
19906
18597
  syncNavigationDragCursorAttrs();
19907
18598
  enforceLinkHrefs();
19908
- const hydratedHeight = document.body.scrollHeight;
18599
+ const hydratedHeight = document.documentElement.scrollHeight;
19909
18600
  if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
19910
18601
  postToParentRef.current({ type: "ow:hydrate-done" });
19911
18602
  };
@@ -19969,25 +18660,16 @@ function OhhwellsBridge() {
19969
18660
  nodes: collectEditableNodes(editContentRef.current)
19970
18661
  });
19971
18662
  };
19972
- const clearInteractionChrome = () => {
19973
- deactivateRef.current();
19974
- deselectRef.current();
19975
- clearMediaSelectionRef.current();
19976
- };
19977
18663
  const handleAiApplyTree = (e) => {
19978
18664
  if (e.data?.type !== "ow:ai-apply-tree") return;
19979
18665
  const payload = e.data.payload;
19980
18666
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19981
- clearInteractionChrome();
19982
18667
  const previous = aiSectionsRef.current;
19983
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19984
- ...payload,
19985
- path: payload.path ?? window.location.pathname
19986
- });
18668
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19987
18669
  const nextValue = serializeAiSectionsState(nextState);
19988
18670
  aiSectionsRef.current = nextValue;
19989
18671
  applyAiSectionsToDom(nextState);
19990
- const newHeight = document.body.scrollHeight;
18672
+ const newHeight = document.documentElement.scrollHeight;
19991
18673
  if (newHeight > 50) postToParentRef.current({ type: "ow:height", height: newHeight });
19992
18674
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: nextValue }] });
19993
18675
  const appliedEl = document.querySelector(`[data-ohw-section="${CSS.escape(payload.id)}"]`);
@@ -20004,13 +18686,12 @@ function OhhwellsBridge() {
20004
18686
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
20005
18687
  if (!exists) return;
20006
18688
  if (isPageFrameSection(exists)) return;
20007
- clearInteractionChrome();
20008
18689
  const previous = aiSectionsRef.current;
20009
18690
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
20010
18691
  const nextValue = serializeAiSectionsState(nextState);
20011
18692
  aiSectionsRef.current = nextValue;
20012
18693
  applyAiSectionsToDom(nextState);
20013
- const newHeight = document.body.scrollHeight;
18694
+ const newHeight = document.documentElement.scrollHeight;
20014
18695
  if (newHeight > 50) postToParentRef.current({ type: "ow:height", height: newHeight });
20015
18696
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: nextValue }] });
20016
18697
  postToParentRef.current({ type: "ow:ai-section-deleted", sectionId, previous, value: nextValue });
@@ -20020,106 +18701,20 @@ function OhhwellsBridge() {
20020
18701
  const handleAiSetSections = (e) => {
20021
18702
  if (e.data?.type !== "ow:ai-set-sections") return;
20022
18703
  const value = typeof e.data.value === "string" ? e.data.value : "";
20023
- clearInteractionChrome();
20024
18704
  aiSectionsRef.current = value;
20025
18705
  applyAiSectionsToDom(parseAiSectionsState(value));
20026
- applyStylesToDom(parseStyleStore(stylesRef.current));
20027
- const restoredHeight = document.body.scrollHeight;
18706
+ const restoredHeight = document.documentElement.scrollHeight;
20028
18707
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
20029
18708
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
20030
18709
  postAiSectionsChanged();
20031
18710
  };
20032
18711
  window.addEventListener("message", handleAiSetSections);
20033
- const handleMoveSection = (e) => {
20034
- if (e.data?.type !== "ow:move-section") return;
20035
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
20036
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
20037
- if (!instanceId || !direction) return;
20038
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
20039
- if (!entries) return;
20040
- const orderJson = JSON.stringify(entries);
20041
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
20042
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
20043
- window.dispatchEvent(new Event("resize"));
20044
- };
20045
- window.addEventListener("message", handleMoveSection);
20046
- const handleAiSetBrand = (e) => {
20047
- if (e.data?.type !== "ow:ai-set-brand") return;
20048
- const value = typeof e.data.value === "string" ? e.data.value : "";
20049
- const previous = brandKitRef.current;
20050
- brandKitRef.current = value;
20051
- applyBrandToDom(parseBrandKit(value));
20052
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
20053
- applyStylesToDom(parseStyleStore(stylesRef.current));
20054
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
20055
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
20056
- };
20057
- window.addEventListener("message", handleAiSetBrand);
20058
- const handleAiSetStyles = (e) => {
20059
- if (e.data?.type !== "ow:ai-set-styles") return;
20060
- const value = typeof e.data.value === "string" ? e.data.value : "";
20061
- const previous = stylesRef.current;
20062
- stylesRef.current = value;
20063
- applyStylesToDom(parseStyleStore(value));
20064
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
20065
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
20066
- };
20067
- window.addEventListener("message", handleAiSetStyles);
20068
- const handleGetBrand = (e) => {
20069
- if (e.data?.type !== "ow:get-brand") return;
20070
- const template = deriveTemplateBrand();
20071
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
20072
- postToParentRef.current({ type: "ow:brand-value", value });
20073
- };
20074
- window.addEventListener("message", handleGetBrand);
20075
18712
  const handlePanelDragging = (e) => {
20076
18713
  if (e.data?.type !== "ow:panel-dragging") return;
20077
18714
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
20078
18715
  else document.documentElement.removeAttribute("data-ohw-panel-dragging");
20079
18716
  };
20080
18717
  window.addEventListener("message", handlePanelDragging);
20081
- const handleDeleteSection = (e) => {
20082
- if (e.data?.type !== "ow:delete-section") return;
20083
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
20084
- if (!instanceId) return;
20085
- const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
20086
- const entries = deleteSectionInstance(instanceId, window.location.pathname, currentEntries);
20087
- if (!entries) return;
20088
- const orderJson = JSON.stringify(entries);
20089
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
20090
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
20091
- aiSectionApiRef.current?.clear();
20092
- window.dispatchEvent(new Event("resize"));
20093
- const deleteHeight = document.body.scrollHeight;
20094
- if (deleteHeight > 50) postToParentRef.current({ type: "ow:height", height: deleteHeight });
20095
- const actionId = newInstanceId();
20096
- pendingDeleteUndoRef.current = {
20097
- actionId,
20098
- restore: () => {
20099
- const restoredEntries = getPageSectionOrderEntries(
20100
- editContentRef.current[SECTION_ORDER_KEY],
20101
- window.location.pathname
20102
- );
20103
- const restored = restoreSectionInstance(instanceId, window.location.pathname, restoredEntries);
20104
- if (!restored) return;
20105
- const restoredJson = JSON.stringify(restored);
20106
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: restoredJson };
20107
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: restoredJson }] });
20108
- window.dispatchEvent(new Event("resize"));
20109
- const restoreHeight = document.body.scrollHeight;
20110
- if (restoreHeight > 50) postToParentRef.current({ type: "ow:height", height: restoreHeight });
20111
- }
20112
- };
20113
- postToParentRef.current({
20114
- type: "ow:toast",
20115
- title: "Section deleted",
20116
- toastType: "success",
20117
- actionLabel: "Undo",
20118
- actionId,
20119
- duration: 6e3
20120
- });
20121
- };
20122
- window.addEventListener("message", handleDeleteSection);
20123
18718
  const handleDeactivate = (e) => {
20124
18719
  if (e.data?.type !== "ow:deactivate") return;
20125
18720
  if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return;
@@ -20129,15 +18724,8 @@ function OhhwellsBridge() {
20129
18724
  closeLinkPopoverRef.current();
20130
18725
  return;
20131
18726
  }
20132
- if (floatingPanelOpenRef.current) {
20133
- setFloatingPanelRef.current(null);
20134
- deselectRef.current();
20135
- deactivateRef.current();
20136
- return;
20137
- }
20138
18727
  deselectRef.current();
20139
18728
  deactivateRef.current();
20140
- clearMediaSelectionRef.current();
20141
18729
  };
20142
18730
  window.addEventListener("message", handleDeactivate);
20143
18731
  const handleToastAction = (e) => {
@@ -20223,10 +18811,6 @@ function OhhwellsBridge() {
20223
18811
  const handleKeyDown = (e) => {
20224
18812
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
20225
18813
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
20226
- if (e.key === "Escape" && selectedMediaElRef.current) {
20227
- clearMediaSelectionRef.current();
20228
- return;
20229
- }
20230
18814
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
20231
18815
  e.preventDefault();
20232
18816
  selectAllTextInEditable(activeElRef.current);
@@ -20386,12 +18970,6 @@ function OhhwellsBridge() {
20386
18970
  if (aiSectionsRef.current) {
20387
18971
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
20388
18972
  }
20389
- if (stylesRef.current) {
20390
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
20391
- }
20392
- if (brandKitRef.current) {
20393
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
20394
- }
20395
18973
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
20396
18974
  const formKey = formKeyOf(form);
20397
18975
  if (!formKey) return;
@@ -20409,12 +18987,8 @@ function OhhwellsBridge() {
20409
18987
  if (inserted) {
20410
18988
  const tracker = getSectionsTracker();
20411
18989
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
20412
- const reportHeight = () => {
20413
- const h = document.body.scrollHeight;
20414
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20415
- };
20416
- reportHeight();
20417
- setTimeout(reportHeight, 500);
18990
+ const h = document.documentElement.scrollHeight;
18991
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20418
18992
  }
20419
18993
  };
20420
18994
  const handleSwitchSchedule = (e) => {
@@ -20455,7 +19029,7 @@ function OhhwellsBridge() {
20455
19029
  const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
20456
19030
  tracker.textContent = JSON.stringify(updated);
20457
19031
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
20458
- const h = document.body.scrollHeight;
19032
+ const h = document.documentElement.scrollHeight;
20459
19033
  if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
20460
19034
  };
20461
19035
  const handleCollectSection = (e) => {
@@ -20810,24 +19384,19 @@ function OhhwellsBridge() {
20810
19384
  window.removeEventListener("message", handleAiApplyTree);
20811
19385
  window.removeEventListener("message", handleAiDeleteSection);
20812
19386
  window.removeEventListener("message", handleAiSetSections);
20813
- window.removeEventListener("message", handleMoveSection);
20814
- window.removeEventListener("message", handleAiSetBrand);
20815
- window.removeEventListener("message", handleAiSetStyles);
20816
- window.removeEventListener("message", handleGetBrand);
20817
19387
  window.removeEventListener("message", handlePanelDragging);
20818
- window.removeEventListener("message", handleDeleteSection);
20819
19388
  window.removeEventListener("message", handleDeactivate);
19389
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
20820
19390
  window.removeEventListener("message", handleToastAction);
20821
19391
  window.removeEventListener("message", handleFormCount);
20822
19392
  window.removeEventListener("message", handleUiEscape);
20823
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
20824
19393
  autoSaveTimers.current.forEach(clearTimeout);
20825
19394
  autoSaveTimers.current.clear();
20826
19395
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
20827
19396
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
20828
19397
  };
20829
19398
  }, [isEditMode, refreshStateRules]);
20830
- (0, import_react17.useEffect)(() => {
19399
+ (0, import_react16.useEffect)(() => {
20831
19400
  if (!isEditMode) return;
20832
19401
  const THRESHOLD = 10;
20833
19402
  const resolveWasSelected = (el) => {
@@ -20983,7 +19552,7 @@ function OhhwellsBridge() {
20983
19552
  unlockFooterDragInteraction();
20984
19553
  };
20985
19554
  }, [isEditMode]);
20986
- (0, import_react17.useEffect)(() => {
19555
+ (0, import_react16.useEffect)(() => {
20987
19556
  const handler = (e) => {
20988
19557
  if (e.data?.type !== "ow:request-schedule-config") return;
20989
19558
  const insertAfterVal = e.data.insertAfter;
@@ -20999,7 +19568,7 @@ function OhhwellsBridge() {
20999
19568
  window.addEventListener("message", handler);
21000
19569
  return () => window.removeEventListener("message", handler);
21001
19570
  }, [processConfigRequest]);
21002
- (0, import_react17.useEffect)(() => {
19571
+ (0, import_react16.useEffect)(() => {
21003
19572
  if (!isEditMode) return;
21004
19573
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
21005
19574
  el.removeAttribute("data-ohw-active-state");
@@ -21023,7 +19592,7 @@ function OhhwellsBridge() {
21023
19592
  postToParent2({
21024
19593
  type: "ow:ready",
21025
19594
  version: "1",
21026
- bridgeVersion: "0.1.71-next.218",
19595
+ bridgeVersion: "0.1.72",
21027
19596
  path: pathname,
21028
19597
  nodes: collectEditableNodes(editContentRef.current),
21029
19598
  sections
@@ -21035,13 +19604,13 @@ function OhhwellsBridge() {
21035
19604
  clearTimeout(timer);
21036
19605
  };
21037
19606
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
21038
- (0, import_react17.useEffect)(() => {
19607
+ (0, import_react16.useEffect)(() => {
21039
19608
  scrollToHashSectionWhenReady();
21040
19609
  const onHashChange = () => scrollToHashSectionWhenReady();
21041
19610
  window.addEventListener("hashchange", onHashChange);
21042
19611
  return () => window.removeEventListener("hashchange", onHashChange);
21043
19612
  }, [pathname]);
21044
- const handleCommand = (0, import_react17.useCallback)((cmd) => {
19613
+ const handleCommand = (0, import_react16.useCallback)((cmd) => {
21045
19614
  const el = activeElRef.current;
21046
19615
  const selBefore = window.getSelection();
21047
19616
  let savedOffsets = null;
@@ -21077,7 +19646,7 @@ function OhhwellsBridge() {
21077
19646
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
21078
19647
  refreshActiveCommandsRef.current();
21079
19648
  }, []);
21080
- (0, import_react17.useEffect)(() => {
19649
+ (0, import_react16.useEffect)(() => {
21081
19650
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
21082
19651
  if (!session || !logoSizeDraft) return;
21083
19652
  const onPanelAction = (e) => {
@@ -21115,7 +19684,7 @@ function OhhwellsBridge() {
21115
19684
  window.addEventListener("message", onPanelAction);
21116
19685
  return () => window.removeEventListener("message", onPanelAction);
21117
19686
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
21118
- const handleStateChange = (0, import_react17.useCallback)((state) => {
19687
+ const handleStateChange = (0, import_react16.useCallback)((state) => {
21119
19688
  if (!activeStateElRef.current) return;
21120
19689
  const el = activeStateElRef.current;
21121
19690
  if (state === "Default") {
@@ -21128,7 +19697,7 @@ function OhhwellsBridge() {
21128
19697
  }
21129
19698
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
21130
19699
  }, [deactivate]);
21131
- const reselectAfterLinkPopover = (0, import_react17.useCallback)(
19700
+ const reselectAfterLinkPopover = (0, import_react16.useCallback)(
21132
19701
  (hrefKey) => {
21133
19702
  requestAnimationFrame(() => {
21134
19703
  const el = resolveHrefKeyElement(hrefKey);
@@ -21137,7 +19706,7 @@ function OhhwellsBridge() {
21137
19706
  },
21138
19707
  [resolveHrefKeyElement]
21139
19708
  );
21140
- const closeLinkPopover = (0, import_react17.useCallback)(() => {
19709
+ const closeLinkPopover = (0, import_react16.useCallback)(() => {
21141
19710
  const session = linkPopoverSessionRef.current;
21142
19711
  addNavAfterAnchorRef.current = null;
21143
19712
  setLinkPopover(null);
@@ -21145,9 +19714,9 @@ function OhhwellsBridge() {
21145
19714
  reselectAfterLinkPopover(session.key);
21146
19715
  }
21147
19716
  }, [reselectAfterLinkPopover]);
21148
- const closeLinkPopoverRef = (0, import_react17.useRef)(closeLinkPopover);
19717
+ const closeLinkPopoverRef = (0, import_react16.useRef)(closeLinkPopover);
21149
19718
  closeLinkPopoverRef.current = closeLinkPopover;
21150
- const openLinkPopoverForActive = (0, import_react17.useCallback)(() => {
19719
+ const openLinkPopoverForActive = (0, import_react16.useCallback)(() => {
21151
19720
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
21152
19721
  if (!hrefCtx) return;
21153
19722
  bumpLinkPopoverGrace();
@@ -21158,7 +19727,7 @@ function OhhwellsBridge() {
21158
19727
  });
21159
19728
  deactivate();
21160
19729
  }, [deactivate]);
21161
- const openLinkPopoverForSelected = (0, import_react17.useCallback)(() => {
19730
+ const openLinkPopoverForSelected = (0, import_react16.useCallback)(() => {
21162
19731
  const anchor = selectedElRef.current;
21163
19732
  if (!anchor) return;
21164
19733
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -21175,7 +19744,7 @@ function OhhwellsBridge() {
21175
19744
  });
21176
19745
  deselect();
21177
19746
  }, [deselect]);
21178
- const handleSelectParent = (0, import_react17.useCallback)(() => {
19747
+ const handleSelectParent = (0, import_react16.useCallback)(() => {
21179
19748
  const selected = selectedElRef.current;
21180
19749
  if (!selected) return;
21181
19750
  if (toolbarVariantRef.current === "select-frame") {
@@ -21202,7 +19771,7 @@ function OhhwellsBridge() {
21202
19771
  }
21203
19772
  deselectRef.current();
21204
19773
  }, []);
21205
- const handleDuplicateSelected = (0, import_react17.useCallback)(() => {
19774
+ const handleDuplicateSelected = (0, import_react16.useCallback)(() => {
21206
19775
  const selected = selectedElRef.current;
21207
19776
  if (!selected || !isNavigationItem2(selected)) return;
21208
19777
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -21335,7 +19904,7 @@ function OhhwellsBridge() {
21335
19904
  });
21336
19905
  }
21337
19906
  }, [postToParent2]);
21338
- const runPendingDeleteUndo = (0, import_react17.useCallback)(() => {
19907
+ const runPendingDeleteUndo = (0, import_react16.useCallback)(() => {
21339
19908
  const pending = pendingDeleteUndoRef.current;
21340
19909
  if (!pending) return false;
21341
19910
  pendingDeleteUndoRef.current = null;
@@ -21343,7 +19912,7 @@ function OhhwellsBridge() {
21343
19912
  enforceLinkHrefs();
21344
19913
  return true;
21345
19914
  }, []);
21346
- const handleDeleteSelected = (0, import_react17.useCallback)(() => {
19915
+ const handleDeleteSelected = (0, import_react16.useCallback)(() => {
21347
19916
  const selected = selectedElRef.current;
21348
19917
  if (!selected) return false;
21349
19918
  return deleteSelectedNavFooterItem({
@@ -21364,7 +19933,7 @@ function OhhwellsBridge() {
21364
19933
  }, [postToParent2]);
21365
19934
  handleDeleteSelectedRef.current = handleDeleteSelected;
21366
19935
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
21367
- const handleLinkPopoverSubmit = (0, import_react17.useCallback)(
19936
+ const handleLinkPopoverSubmit = (0, import_react16.useCallback)(
21368
19937
  (target) => {
21369
19938
  const session = linkPopoverSessionRef.current;
21370
19939
  if (!session) return;
@@ -21430,30 +19999,19 @@ function OhhwellsBridge() {
21430
19999
  const showEditLink = toolbarShowEditLink;
21431
20000
  const currentSections = sectionsByPath[pathname] ?? [];
21432
20001
  linkPopoverOpenRef.current = linkPopover !== null;
21433
- const handleMediaSelect = (0, import_react17.useCallback)((key) => {
21434
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
21435
- (m) => (m.dataset.ohwKey ?? "") === key
21436
- ) ?? null;
21437
- if (!el) return;
21438
- selectMediaElementRef.current(el);
21439
- }, []);
21440
- const handleMediaReplace = (0, import_react17.useCallback)(
20002
+ const handleMediaReplace = (0, import_react16.useCallback)(
21441
20003
  (key) => {
21442
- postToParent2({
21443
- type: "ow:image-pick",
21444
- key,
21445
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
21446
- });
20004
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
21447
20005
  },
21448
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
20006
+ [postToParent2, mediaHover?.elementType]
21449
20007
  );
21450
- const handleEditCarousel = (0, import_react17.useCallback)(
20008
+ const handleEditCarousel = (0, import_react16.useCallback)(
21451
20009
  (key) => {
21452
20010
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
21453
20011
  },
21454
20012
  [postToParent2]
21455
20013
  );
21456
- const handleMediaFadeOutComplete = (0, import_react17.useCallback)((key) => {
20014
+ const handleMediaFadeOutComplete = (0, import_react16.useCallback)((key) => {
21457
20015
  setUploadingRects((prev) => {
21458
20016
  if (!(key in prev)) return prev;
21459
20017
  const next = { ...prev };
@@ -21461,7 +20019,7 @@ function OhhwellsBridge() {
21461
20019
  return next;
21462
20020
  });
21463
20021
  }, []);
21464
- const handleVideoSettingsChange = (0, import_react17.useCallback)(
20022
+ const handleVideoSettingsChange = (0, import_react16.useCallback)(
21465
20023
  (key, settings) => {
21466
20024
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
21467
20025
  const video = getVideoEl2(el);
@@ -21483,516 +20041,430 @@ function OhhwellsBridge() {
21483
20041
  },
21484
20042
  [postToParent2]
21485
20043
  );
21486
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21487
- /* @__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, {}) }),
21488
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
21489
- bridgeRoot ? (0, import_react_dom4.createPortal)(
21490
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21491
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
21492
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
21493
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21494
- "div",
21495
- {
21496
- className: "pointer-events-none fixed z-2147483646",
21497
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
21498
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21499
- DropIndicator,
21500
- {
21501
- direction: "horizontal",
21502
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
21503
- className: "!h-full !w-full"
21504
- }
21505
- )
21506
- },
21507
- `section-drop-${slot.insertIndex}-${i}`
21508
- )),
21509
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21510
- MediaOverlay,
21511
- {
21512
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
21513
- isUploading: true,
21514
- fadingOut,
21515
- onFadeOutComplete: handleMediaFadeOutComplete,
21516
- onReplace: handleMediaReplace
21517
- },
21518
- `uploading-${key}`
21519
- )),
21520
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21521
- MediaOverlay,
21522
- {
21523
- hover: mediaHover,
21524
- isUploading: false,
21525
- onReplace: handleMediaReplace,
21526
- onSelect: handleMediaSelect,
21527
- onVideoSettingsChange: handleVideoSettingsChange
21528
- }
21529
- ),
21530
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21531
- MediaOverlay,
21532
- {
21533
- hover: selectedMedia,
21534
- selected: true,
21535
- hovered: mediaHover?.key === selectedMedia.key,
21536
- isUploading: false,
21537
- onReplace: handleMediaReplace,
21538
- onSelect: handleMediaSelect,
21539
- onVideoSettingsChange: handleVideoSettingsChange
21540
- }
21541
- ),
21542
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
21543
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
21544
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
21545
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
21546
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21547
- "div",
21548
- {
21549
- className: "pointer-events-none fixed z-2147483646",
21550
- style: {
21551
- left: slot.left,
21552
- top: slot.top,
21553
- width: slot.width,
21554
- height: slot.height
21555
- },
21556
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21557
- DropIndicator,
21558
- {
21559
- direction: slot.direction,
21560
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
21561
- className: "!h-full !w-full"
21562
- }
21563
- )
21564
- },
21565
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
21566
- )),
21567
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21568
- "div",
21569
- {
21570
- className: "pointer-events-none fixed z-2147483646",
21571
- style: {
21572
- left: slot.left,
21573
- top: slot.top,
21574
- width: slot.width,
21575
- height: slot.height
21576
- },
21577
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21578
- DropIndicator,
21579
- {
21580
- direction: slot.direction,
21581
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
21582
- className: "!h-full !w-full"
21583
- }
21584
- )
20044
+ return bridgeRoot ? (0, import_react_dom4.createPortal)(
20045
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20046
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20047
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20048
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20049
+ MediaOverlay,
20050
+ {
20051
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20052
+ isUploading: true,
20053
+ fadingOut,
20054
+ onFadeOutComplete: handleMediaFadeOutComplete,
20055
+ onReplace: handleMediaReplace
20056
+ },
20057
+ `uploading-${key}`
20058
+ )),
20059
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20060
+ MediaOverlay,
20061
+ {
20062
+ hover: mediaHover,
20063
+ isUploading: false,
20064
+ onReplace: handleMediaReplace,
20065
+ onVideoSettingsChange: handleVideoSettingsChange
20066
+ }
20067
+ ),
20068
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20069
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20070
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20071
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20072
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20073
+ "div",
20074
+ {
20075
+ className: "pointer-events-none fixed z-2147483646",
20076
+ style: {
20077
+ left: slot.left,
20078
+ top: slot.top,
20079
+ width: slot.width,
20080
+ height: slot.height
21585
20081
  },
21586
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
21587
- )),
21588
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
21589
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
21590
- hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
21591
- formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21592
- ItemInteractionLayer,
21593
- {
21594
- rect: formPickRect,
21595
- state: "active-top",
21596
- itemDragSurface: false,
21597
- toolbarAlign: "left",
21598
- chromeGap: 24,
21599
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21600
- "div",
21601
- {
21602
- "data-ohw-form-toolbar": "",
21603
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
21604
- children: [
21605
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21606
- "button",
21607
- {
21608
- type: "button",
21609
- "aria-label": "Add field",
21610
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
21611
- onClick: () => setFieldTypePickerOpen((open) => !open),
21612
- "data-ohw-add-field": "",
21613
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
21614
- }
21615
- ),
21616
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
21617
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21618
- "button",
21619
- {
21620
- type: "button",
21621
- 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",
21622
- onClick: () => {
21623
- setFieldTypePickerOpen(false);
21624
- const form = formPickElRef.current;
21625
- if (!form) return;
21626
- postToParent2({
21627
- type: "ow:form-pick",
21628
- formKey: formKeyOf(form),
21629
- hasLongText: formHasLongText(form)
21630
- });
21631
- },
21632
- children: [
21633
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
21634
- "Form settings",
21635
- formPickCount ? (
21636
- // Counter pill, per the design — not a text suffix.
21637
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21638
- "span",
21639
- {
21640
- "data-ohw-form-count": "",
21641
- 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",
21642
- children: formPickCount
21643
- }
21644
- )
21645
- ) : null
21646
- ]
21647
- }
21648
- ),
21649
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
21650
- /* @__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)(
21651
- "button",
21652
- {
21653
- type: "button",
21654
- "aria-pressed": formViewState === state,
21655
- 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"),
21656
- onClick: () => {
21657
- setFieldTypePickerOpen(false);
21658
- const form = formPickElRef.current;
21659
- const key = form ? formKeyOf(form) : null;
21660
- if (!form || !key) return;
21661
- const initial = successInitialFor(form, key, editContentRef.current);
21662
- setFormViewState(form, key, state, initial);
21663
- setFormViewStateUi(state);
21664
- setFormPickRect(form.getBoundingClientRect());
21665
- if (state === "success") {
21666
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
21667
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
21668
- } else {
21669
- deactivateRef.current();
21670
- }
21671
- },
21672
- children: state
21673
- },
21674
- state
21675
- )) })
21676
- ]
21677
- }
21678
- )
21679
- }
21680
- ),
21681
- formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21682
- ItemInteractionLayer,
21683
- {
21684
- rect: formHoverRect,
21685
- state: "hover",
21686
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
21687
- }
21688
- ),
21689
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21690
- ItemInteractionLayer,
21691
- {
21692
- rect: fieldPickRect,
21693
- state: fieldDragging ? "dragging" : "active-top",
21694
- itemDragSurface: false,
21695
- toolbarAlign: "left",
21696
- chromeGap: 10,
21697
- showHandle: true,
21698
- dragHandleLabel: "Reorder field",
21699
- onDragHandleDragStart: handleFieldDragStart,
21700
- onDragHandleDragEnd: handleFieldDragEnd,
21701
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21702
- FormFieldToolbar,
21703
- {
21704
- type: fieldPickState.type,
21705
- required: fieldPickState.required,
21706
- onTypeChange: handleFieldTypeChange,
21707
- onRequiredToggle: handleFieldRequiredToggle,
21708
- onDuplicate: handleFieldDuplicate,
21709
- onDelete: handleFieldDelete
21710
- }
21711
- )
21712
- }
21713
- ),
21714
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21715
- "div",
21716
- {
21717
- className: "pointer-events-none fixed z-[2147483644]",
21718
- style: { top: slot.top, left: slot.left, width: slot.width },
21719
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21720
- DropIndicator,
21721
- {
21722
- direction: "horizontal",
21723
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
21724
- className: "!w-full"
21725
- }
21726
- )
20082
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20083
+ DropIndicator,
20084
+ {
20085
+ direction: slot.direction,
20086
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20087
+ className: "!h-full !w-full"
20088
+ }
20089
+ )
20090
+ },
20091
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20092
+ )),
20093
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20094
+ "div",
20095
+ {
20096
+ className: "pointer-events-none fixed z-2147483646",
20097
+ style: {
20098
+ left: slot.left,
20099
+ top: slot.top,
20100
+ width: slot.width,
20101
+ height: slot.height
21727
20102
  },
21728
- `field-drop-${i}`
21729
- )) : null,
21730
- fieldTypePickerOpen && formPickRect ? (() => {
21731
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
21732
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21733
- "div",
20103
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20104
+ DropIndicator,
21734
20105
  {
21735
- className: "pointer-events-none fixed z-[2147483645]",
21736
- style: {
21737
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
21738
- left: toolbar ? toolbar.left : formPickRect.left + 24
21739
- },
21740
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
20106
+ direction: slot.direction,
20107
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20108
+ className: "!h-full !w-full"
21741
20109
  }
21742
- );
21743
- })() : null,
21744
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
21745
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21746
- FooterContainerChrome,
21747
- {
21748
- rect: toolbarRect,
21749
- onAdd: handleAddFooterColumn,
21750
- addDisabled: !canAddFooterColumn()
21751
- }
21752
- ),
21753
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21754
- ItemInteractionLayer,
21755
- {
21756
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
21757
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
21758
- elRef: glowElRef,
21759
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
21760
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
21761
- dragDisabled: reorderDragDisabled,
21762
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
21763
- onDragHandleDragStart: handleItemDragStart,
21764
- onDragHandleDragEnd: handleItemDragEnd,
21765
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
21766
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
21767
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
21768
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21769
- ItemActionToolbar,
21770
- {
21771
- onEditLink: openLinkPopoverForSelected,
21772
- onStyle: () => {
21773
- const row = selectedElRef.current;
21774
- if (!row) return;
21775
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
21776
- else openSocialsDisplayPanel(row);
21777
- },
21778
- showStyle: selectedIsSocialsRow,
21779
- styleActive: floatingPanel?.kind === "socials-display",
21780
- onAddItem: handleAddChildItem,
21781
- onSelectParent: handleSelectParent,
21782
- onDuplicate: handleDuplicateSelected,
21783
- onDelete: handleDeleteSelected,
21784
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
21785
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
21786
- return row ? !canAddSocialItem(row) : false;
21787
- })(),
21788
- editLinkDisabled: false,
21789
- moreDisabled: false,
21790
- deleteDisabled: selectedElRef.current !== null && (() => {
21791
- const social = getSocialItem(selectedElRef.current);
21792
- return social ? !canRemoveSocialItem(social) : false;
21793
- })(),
21794
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
21795
- const social = getSocialItem(selectedElRef.current);
21796
- const row = social ? findSocialsRow(social) : null;
21797
- return row ? !canAddSocialItem(row) : false;
21798
- })(),
21799
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
21800
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
21801
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
20110
+ )
20111
+ },
20112
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20113
+ )),
20114
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20115
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20116
+ hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20117
+ formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20118
+ ItemInteractionLayer,
20119
+ {
20120
+ rect: formPickRect,
20121
+ state: "active-top",
20122
+ itemDragSurface: false,
20123
+ toolbarAlign: "left",
20124
+ chromeGap: 24,
20125
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20126
+ "div",
20127
+ {
20128
+ "data-ohw-form-toolbar": "",
20129
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20130
+ children: [
20131
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20132
+ "button",
20133
+ {
20134
+ type: "button",
20135
+ "aria-label": "Add field",
20136
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20137
+ onClick: () => setFieldTypePickerOpen((open) => !open),
20138
+ "data-ohw-add-field": "",
20139
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
20140
+ }
21802
20141
  ),
21803
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
21804
- dropdownOpen: navDropdownPreviewOpen,
21805
- onDropdownOpenChange: handleNavDropdownOpenChange,
21806
- headingVisible: footerHeadingVisible,
21807
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
21808
- }
21809
- ) : void 0
21810
- }
21811
- ),
21812
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
21813
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21814
- EditGlowChrome,
20142
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20143
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20144
+ "button",
20145
+ {
20146
+ type: "button",
20147
+ 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",
20148
+ onClick: () => {
20149
+ setFieldTypePickerOpen(false);
20150
+ const form = formPickElRef.current;
20151
+ if (!form) return;
20152
+ postToParent2({
20153
+ type: "ow:form-pick",
20154
+ formKey: formKeyOf(form),
20155
+ hasLongText: formHasLongText(form)
20156
+ });
20157
+ },
20158
+ children: [
20159
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
20160
+ "Form settings",
20161
+ formPickCount ? (
20162
+ // Counter pill, per the design — not a text suffix.
20163
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20164
+ "span",
20165
+ {
20166
+ "data-ohw-form-count": "",
20167
+ 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",
20168
+ children: formPickCount
20169
+ }
20170
+ )
20171
+ ) : null
20172
+ ]
20173
+ }
20174
+ ),
20175
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20176
+ /* @__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)(
20177
+ "button",
20178
+ {
20179
+ type: "button",
20180
+ "aria-pressed": formViewState === state,
20181
+ 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"),
20182
+ onClick: () => {
20183
+ setFieldTypePickerOpen(false);
20184
+ const form = formPickElRef.current;
20185
+ const key = form ? formKeyOf(form) : null;
20186
+ if (!form || !key) return;
20187
+ const initial = successInitialFor(form, key, editContentRef.current);
20188
+ setFormViewState(form, key, state, initial);
20189
+ setFormViewStateUi(state);
20190
+ setFormPickRect(form.getBoundingClientRect());
20191
+ if (state === "success") {
20192
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20193
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20194
+ } else {
20195
+ deactivateRef.current();
20196
+ }
20197
+ },
20198
+ children: state
20199
+ },
20200
+ state
20201
+ )) })
20202
+ ]
20203
+ }
20204
+ )
20205
+ }
20206
+ ),
20207
+ formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20208
+ ItemInteractionLayer,
20209
+ {
20210
+ rect: formHoverRect,
20211
+ state: "hover",
20212
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20213
+ }
20214
+ ),
20215
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20216
+ ItemInteractionLayer,
20217
+ {
20218
+ rect: fieldPickRect,
20219
+ state: fieldDragging ? "dragging" : "active-top",
20220
+ itemDragSurface: false,
20221
+ toolbarAlign: "left",
20222
+ chromeGap: 10,
20223
+ showHandle: true,
20224
+ dragHandleLabel: "Reorder field",
20225
+ onDragHandleDragStart: handleFieldDragStart,
20226
+ onDragHandleDragEnd: handleFieldDragEnd,
20227
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20228
+ FormFieldToolbar,
21815
20229
  {
21816
- rect: toolbarRect,
21817
- elRef: glowElRef,
21818
- reorderHrefKey,
21819
- dragDisabled: reorderDragDisabled,
21820
- hideHandle: isItemDragging
20230
+ type: fieldPickState.type,
20231
+ required: fieldPickState.required,
20232
+ onTypeChange: handleFieldTypeChange,
20233
+ onRequiredToggle: handleFieldRequiredToggle,
20234
+ onDuplicate: handleFieldDuplicate,
20235
+ onDelete: handleFieldDelete
21821
20236
  }
21822
- ),
21823
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21824
- FloatingToolbar,
20237
+ )
20238
+ }
20239
+ ),
20240
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20241
+ "div",
20242
+ {
20243
+ className: "pointer-events-none fixed z-[2147483644]",
20244
+ style: { top: slot.top, left: slot.left, width: slot.width },
20245
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20246
+ DropIndicator,
21825
20247
  {
21826
- rect: toolbarRect,
21827
- parentScroll: parentScrollRef.current,
21828
- elRef: toolbarElRef,
21829
- onCommand: handleCommand,
21830
- activeCommands,
21831
- showEditLink,
21832
- onEditLink: openLinkPopoverForActive
20248
+ direction: "horizontal",
20249
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20250
+ className: "!w-full"
21833
20251
  }
21834
20252
  )
21835
- ] }),
21836
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20253
+ },
20254
+ `field-drop-${i}`
20255
+ )) : null,
20256
+ fieldTypePickerOpen && formPickRect ? (() => {
20257
+ const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20258
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21837
20259
  "div",
21838
20260
  {
21839
- "data-ohw-max-badge": "",
20261
+ className: "pointer-events-none fixed z-[2147483645]",
21840
20262
  style: {
21841
- position: "fixed",
21842
- top: maxBadge.rect.bottom + 4,
21843
- left: maxBadge.rect.right,
21844
- transform: "translateX(-100%)",
21845
- zIndex: 2147483647,
21846
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
21847
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
21848
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
21849
- borderRadius: 4,
21850
- padding: "2px 6px",
21851
- fontSize: 11,
21852
- fontWeight: 500,
21853
- pointerEvents: "none"
20263
+ top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20264
+ left: toolbar ? toolbar.left : formPickRect.left + 24
21854
20265
  },
21855
- children: [
21856
- maxBadge.current,
21857
- "/",
21858
- maxBadge.max
21859
- ]
20266
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
21860
20267
  }
21861
- ),
21862
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21863
- StateToggle,
20268
+ );
20269
+ })() : null,
20270
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20271
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20272
+ FooterContainerChrome,
20273
+ {
20274
+ rect: toolbarRect,
20275
+ onAdd: handleAddFooterColumn,
20276
+ addDisabled: !canAddFooterColumn()
20277
+ }
20278
+ ),
20279
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20280
+ ItemInteractionLayer,
20281
+ {
20282
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20283
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20284
+ elRef: glowElRef,
20285
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20286
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20287
+ dragDisabled: reorderDragDisabled,
20288
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20289
+ onDragHandleDragStart: handleItemDragStart,
20290
+ onDragHandleDragEnd: handleItemDragEnd,
20291
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20292
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20293
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
20294
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20295
+ ItemActionToolbar,
20296
+ {
20297
+ onEditLink: openLinkPopoverForSelected,
20298
+ onStyle: () => {
20299
+ const row = selectedElRef.current;
20300
+ if (!row) return;
20301
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20302
+ else openSocialsDisplayPanel(row);
20303
+ },
20304
+ showStyle: selectedIsSocialsRow,
20305
+ styleActive: floatingPanel?.kind === "socials-display",
20306
+ onAddItem: handleAddChildItem,
20307
+ onSelectParent: handleSelectParent,
20308
+ onDuplicate: handleDuplicateSelected,
20309
+ onDelete: handleDeleteSelected,
20310
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20311
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20312
+ return row ? !canAddSocialItem(row) : false;
20313
+ })(),
20314
+ editLinkDisabled: false,
20315
+ moreDisabled: false,
20316
+ deleteDisabled: selectedElRef.current !== null && (() => {
20317
+ const social = getSocialItem(selectedElRef.current);
20318
+ return social ? !canRemoveSocialItem(social) : false;
20319
+ })(),
20320
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
20321
+ const social = getSocialItem(selectedElRef.current);
20322
+ const row = social ? findSocialsRow(social) : null;
20323
+ return row ? !canAddSocialItem(row) : false;
20324
+ })(),
20325
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20326
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20327
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
20328
+ ),
20329
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20330
+ dropdownOpen: navDropdownPreviewOpen,
20331
+ onDropdownOpenChange: handleNavDropdownOpenChange,
20332
+ headingVisible: footerHeadingVisible,
20333
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
20334
+ }
20335
+ ) : void 0
20336
+ }
20337
+ ),
20338
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20339
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20340
+ EditGlowChrome,
21864
20341
  {
21865
- rect: toggleState.rect,
21866
- activeState: toggleState.activeState,
21867
- states: toggleState.states,
21868
- onStateChange: handleStateChange
20342
+ rect: toolbarRect,
20343
+ elRef: glowElRef,
20344
+ reorderHrefKey,
20345
+ dragDisabled: reorderDragDisabled,
20346
+ hideHandle: isItemDragging
21869
20347
  }
21870
20348
  ),
21871
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
21872
- "div",
20349
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20350
+ FloatingToolbar,
21873
20351
  {
21874
- "data-ohw-section-insert-line": "",
21875
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
21876
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
21877
- children: [
21878
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
21879
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21880
- Badge,
21881
- {
21882
- 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",
21883
- onClick: () => {
21884
- window.parent.postMessage(
21885
- {
21886
- type: "ow:add-section",
21887
- insertAfter: sectionGap.insertAfter,
21888
- insertBefore: sectionGap.insertBefore
21889
- },
21890
- "*"
21891
- );
21892
- },
21893
- children: "Add Section"
21894
- }
21895
- ),
21896
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
21897
- ]
20352
+ rect: toolbarRect,
20353
+ parentScroll: parentScrollRef.current,
20354
+ elRef: toolbarElRef,
20355
+ onCommand: handleCommand,
20356
+ activeCommands,
20357
+ showEditLink,
20358
+ onEditLink: openLinkPopoverForActive
21898
20359
  }
21899
- ),
21900
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21901
- LinkPopover,
21902
- {
21903
- panelRef: linkPopoverPanelRef,
21904
- portalContainer: dialogPortalContainer,
21905
- open: true,
21906
- mode: linkPopover.mode ?? "edit",
21907
- pages: sitePages,
21908
- sections: currentSections,
21909
- sectionsByPath,
21910
- initialTarget: linkPopover.target,
21911
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21912
- onClose: closeLinkPopover,
21913
- onSubmit: handleLinkPopoverSubmit
20360
+ )
20361
+ ] }),
20362
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20363
+ "div",
20364
+ {
20365
+ "data-ohw-max-badge": "",
20366
+ style: {
20367
+ position: "fixed",
20368
+ top: maxBadge.rect.bottom + 4,
20369
+ left: maxBadge.rect.right,
20370
+ transform: "translateX(-100%)",
20371
+ zIndex: 2147483647,
20372
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20373
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20374
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20375
+ borderRadius: 4,
20376
+ padding: "2px 6px",
20377
+ fontSize: 11,
20378
+ fontWeight: 500,
20379
+ pointerEvents: "none"
21914
20380
  },
21915
- linkPopover.key
21916
- ) : null,
21917
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21918
- FloatingPanel,
21919
- {
21920
- open: true,
21921
- title: floatingPanel.title,
21922
- context: floatingPanel.context,
21923
- position: floatingPanelPos,
21924
- onPositionChange: setFloatingPanelPos,
21925
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21926
- onClose: closeFloatingPanelOnly,
21927
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21928
- SocialsDisplayPanel,
20381
+ children: [
20382
+ maxBadge.current,
20383
+ "/",
20384
+ maxBadge.max
20385
+ ]
20386
+ }
20387
+ ),
20388
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20389
+ StateToggle,
20390
+ {
20391
+ rect: toggleState.rect,
20392
+ activeState: toggleState.activeState,
20393
+ states: toggleState.states,
20394
+ onStateChange: handleStateChange
20395
+ }
20396
+ ),
20397
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20398
+ "div",
20399
+ {
20400
+ "data-ohw-section-insert-line": "",
20401
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20402
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
20403
+ children: [
20404
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20405
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20406
+ Badge,
21929
20407
  {
21930
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21931
- onChange: (next) => {
21932
- changeSocialsDisplay(floatingPanel.row, next);
21933
- setFloatingPanel({ ...floatingPanel });
21934
- }
20408
+ 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",
20409
+ onClick: () => {
20410
+ window.parent.postMessage(
20411
+ {
20412
+ type: "ow:add-section",
20413
+ insertAfter: sectionGap.insertAfter,
20414
+ insertBefore: sectionGap.insertBefore
20415
+ },
20416
+ "*"
20417
+ );
20418
+ },
20419
+ children: "Add Section"
21935
20420
  }
21936
- )
21937
- }
21938
- ) : null
21939
- ] }),
21940
- bridgeRoot
21941
- ) : null
21942
- ] });
21943
- }
21944
-
21945
- // src/ui/EmptySection.tsx
21946
- var import_link = __toESM(require("next/link"), 1);
21947
- var import_jsx_runtime34 = require("react/jsx-runtime");
21948
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21949
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
21950
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21951
- "p",
21952
- {
21953
- style: {
21954
- fontFamily: "var(--brand-font-body)",
21955
- fontSize: "0.75rem",
21956
- fontWeight: 500,
21957
- letterSpacing: "0.15em",
21958
- textTransform: "uppercase",
21959
- color: "var(--brand-accent)",
21960
- marginBottom: "1.5rem"
21961
- },
21962
- 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" }) })
21963
- }
21964
- ),
21965
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21966
- "h1",
21967
- {
21968
- style: {
21969
- fontFamily: "var(--brand-font-heading)",
21970
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21971
- lineHeight: 1.1,
21972
- letterSpacing: "-0.025em",
21973
- color: "var(--brand-text)",
21974
- marginBottom: "1rem"
21975
- },
21976
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21977
- children: title
21978
- }
21979
- ),
21980
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21981
- "p",
21982
- {
21983
- style: {
21984
- fontFamily: "var(--brand-font-body)",
21985
- fontSize: "1rem",
21986
- lineHeight: 1.7,
21987
- fontWeight: 300,
21988
- color: "var(--brand-text-muted)",
21989
- maxWidth: "340px"
20421
+ ),
20422
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20423
+ ]
20424
+ }
20425
+ ),
20426
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20427
+ LinkPopover,
20428
+ {
20429
+ panelRef: linkPopoverPanelRef,
20430
+ portalContainer: dialogPortalContainer,
20431
+ open: true,
20432
+ mode: linkPopover.mode ?? "edit",
20433
+ pages: sitePages,
20434
+ sections: currentSections,
20435
+ sectionsByPath,
20436
+ initialTarget: linkPopover.target,
20437
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
20438
+ onClose: closeLinkPopover,
20439
+ onSubmit: handleLinkPopoverSubmit
21990
20440
  },
21991
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21992
- children: "This page doesn't have any content yet."
21993
- }
21994
- )
21995
- ] });
20441
+ linkPopover.key
20442
+ ) : null,
20443
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20444
+ FloatingPanel,
20445
+ {
20446
+ open: true,
20447
+ title: floatingPanel.title,
20448
+ context: floatingPanel.context,
20449
+ position: floatingPanelPos,
20450
+ onPositionChange: setFloatingPanelPos,
20451
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
20452
+ onClose: closeFloatingPanelOnly,
20453
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20454
+ SocialsDisplayPanel,
20455
+ {
20456
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
20457
+ onChange: (next) => {
20458
+ changeSocialsDisplay(floatingPanel.row, next);
20459
+ setFloatingPanel({ ...floatingPanel });
20460
+ }
20461
+ }
20462
+ )
20463
+ }
20464
+ ) : null
20465
+ ] }),
20466
+ bridgeRoot
20467
+ ) : null;
21996
20468
  }
21997
20469
  // Annotate the CommonJS export names for ESM import in node:
21998
20470
  0 && (module.exports = {
@@ -22011,7 +20483,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
22011
20483
  DropdownMenuItem,
22012
20484
  DropdownMenuSeparator,
22013
20485
  DropdownMenuTrigger,
22014
- EmptySection,
22015
20486
  ItemActionToolbar,
22016
20487
  ItemInteractionLayer,
22017
20488
  LinkEditorPanel,