@ohhwells/bridge 0.1.67-next.195 → 0.1.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React11, { useCallback as useCallback8, useEffect as useEffect13, useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState12 } from "react";
4
+ import React11, { useCallback as useCallback7, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
5
5
  import { createRoot as createRoot2 } from "react-dom/client";
6
6
  import { flushSync as flushSync2 } from "react-dom";
7
7
 
@@ -83,12 +83,7 @@ function parseAiSectionsState(raw) {
83
83
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
84
84
  }));
85
85
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
86
- return {
87
- v: 1,
88
- sections,
89
- ...removed.length ? { removed } : {},
90
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
91
- };
86
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
92
87
  } catch {
93
88
  return EMPTY_AI_SECTIONS;
94
89
  }
@@ -101,7 +96,6 @@ function applyTreeToState(state, payload) {
101
96
  const entry = {
102
97
  id: payload.id,
103
98
  label: payload.label ?? "Generated section",
104
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
105
99
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
106
100
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
107
101
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -124,317 +118,6 @@ function deleteSectionFromState(state, sectionId) {
124
118
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
125
119
  }
126
120
 
127
- // src/lib/brand-chrome.ts
128
- var BRAND_NAME_KEY = "__ohw_brand_name";
129
- var BRAND_TITLE_KEY = "__ohw_site_title";
130
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
131
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
132
- BRAND_NAME_KEY,
133
- BRAND_TITLE_KEY,
134
- BRAND_FAVICON_LETTER_KEY
135
- ]);
136
- function upsertMeta(selector, attr, token, value) {
137
- let el = document.head.querySelector(selector);
138
- if (!el) {
139
- el = document.createElement("meta");
140
- el.setAttribute(attr, token);
141
- document.head.appendChild(el);
142
- }
143
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
144
- }
145
- function escapeXml(value) {
146
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
147
- }
148
- function applyLetterFavicon(letter) {
149
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
150
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
151
- let link = document.head.querySelector('link[rel="icon"]');
152
- if (!link) {
153
- link = document.createElement("link");
154
- link.rel = "icon";
155
- document.head.appendChild(link);
156
- }
157
- link.type = "image/svg+xml";
158
- if (link.href !== href) link.href = href;
159
- }
160
- function applyBrandChrome(content) {
161
- const name = content[BRAND_NAME_KEY];
162
- if (typeof name === "string" && name.length > 0) {
163
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
164
- if (el.textContent !== name) el.textContent = name;
165
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
166
- });
167
- }
168
- const title = content[BRAND_TITLE_KEY];
169
- if (typeof title === "string" && title.length > 0) {
170
- if (document.title !== title) document.title = title;
171
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
172
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
173
- }
174
- const letter = content[BRAND_FAVICON_LETTER_KEY];
175
- if (typeof letter === "string" && letter.length > 0) {
176
- applyLetterFavicon(letter);
177
- }
178
- }
179
-
180
- // src/lib/brand-kit.ts
181
- var BRAND_KIT_KEY = "__ohw_brand";
182
- var BRAND_VAR_PREFIX = "--ohw-brand-";
183
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
184
- (role) => `${BRAND_VAR_PREFIX}${role}`
185
- );
186
- var FONT_VARS = {
187
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
188
- body: ["--font-body", "--brand-font-body"]
189
- };
190
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
191
- function brandColorVars(kit) {
192
- const { dark, primary, accent, light } = kit.palette;
193
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
194
- return {
195
- [`${BRAND_VAR_PREFIX}primary`]: primary,
196
- [`${BRAND_VAR_PREFIX}accent`]: accent,
197
- [`${BRAND_VAR_PREFIX}light`]: light,
198
- [`${BRAND_VAR_PREFIX}dark`]: dark,
199
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
200
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
201
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
202
- };
203
- }
204
- function parseBrandKit(raw) {
205
- if (!raw) return null;
206
- try {
207
- const parsed = JSON.parse(raw);
208
- const p = parsed?.palette;
209
- const f = parsed?.fonts;
210
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
211
- return null;
212
- }
213
- return {
214
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
215
- fonts: { heading: f.heading, body: f.body }
216
- };
217
- } catch {
218
- return null;
219
- }
220
- }
221
- function familyOf(stack) {
222
- const first = stack.split(",")[0]?.trim() ?? "";
223
- return first.replace(/^['"]|['"]$/g, "");
224
- }
225
- function loadBrandFonts(families) {
226
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
227
- if (unique.length === 0) return;
228
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
229
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
230
- let link = document.getElementById(BRAND_FONT_LINK_ID);
231
- if (!link) {
232
- link = document.createElement("link");
233
- link.id = BRAND_FONT_LINK_ID;
234
- link.rel = "stylesheet";
235
- document.head.appendChild(link);
236
- }
237
- if (link.href !== href) link.href = href;
238
- }
239
- function applyBrandToDom(kit) {
240
- const root = document.documentElement;
241
- if (!kit) {
242
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
243
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
244
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
245
- return;
246
- }
247
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
248
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
249
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
250
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
251
- }
252
-
253
- // src/lib/section-styles.ts
254
- var STYLE_STORE_KEY = "__ohw_styles";
255
- var STYLE_SHEET_ID = "ohw-section-styles";
256
- function parseStyleStore(raw) {
257
- if (!raw) return null;
258
- try {
259
- const parsed = JSON.parse(raw);
260
- if (parsed?.v !== 1) return null;
261
- return {
262
- v: 1,
263
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
264
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
265
- };
266
- } catch {
267
- return null;
268
- }
269
- }
270
- var BG_VALUES = {
271
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
272
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
273
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
274
- };
275
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
276
- function styleSheetCss() {
277
- const rules = [];
278
- for (const [tone, value] of Object.entries(BG_VALUES)) {
279
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
280
- }
281
- rules.push(
282
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
283
- );
284
- rules.push(
285
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
286
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
287
- );
288
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
289
- rules.push(
290
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
291
- );
292
- }
293
- rules.push(
294
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
295
- );
296
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
297
- rules.push(
298
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
299
- );
300
- }
301
- const pad = { tight: 40, balanced: 64, airy: 96 };
302
- for (const [spacing, px] of Object.entries(pad)) {
303
- rules.push(
304
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
305
- );
306
- }
307
- return rules.join("\n");
308
- }
309
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
310
- function loadStyleFonts(families) {
311
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
312
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
313
- if (unique.length === 0) {
314
- existing?.remove();
315
- return;
316
- }
317
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
318
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
319
- let link = existing;
320
- if (!link) {
321
- link = document.createElement("link");
322
- link.id = STYLE_FONT_LINK_ID;
323
- link.rel = "stylesheet";
324
- document.head.appendChild(link);
325
- }
326
- if (link.href !== href) link.href = href;
327
- }
328
- var SECTION_ATTRS = {
329
- sectionBackground: "data-ohw-style-bg",
330
- textDistribution: "data-ohw-style-distribution",
331
- headlineScale: "data-ohw-style-headline",
332
- imageAspect: "data-ohw-style-aspect",
333
- spacing: "data-ohw-style-spacing"
334
- };
335
- var NODE_WROTE_ATTR = "data-ohw-style-node";
336
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
337
- function saveInline(el, prop) {
338
- const attr = `data-ohw-style-prev-${prop}`;
339
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
340
- }
341
- function restoreInline(el, prop) {
342
- const attr = `data-ohw-style-prev-${prop}`;
343
- if (!el.hasAttribute(attr)) return;
344
- const prev = el.getAttribute(attr) ?? "";
345
- if (prev) el.style.setProperty(prop, prev);
346
- else el.style.removeProperty(prop);
347
- el.removeAttribute(attr);
348
- }
349
- function ensureStyleSheet() {
350
- let el = document.getElementById(STYLE_SHEET_ID);
351
- if (!el) {
352
- el = document.createElement("style");
353
- el.id = STYLE_SHEET_ID;
354
- document.head.appendChild(el);
355
- }
356
- const css = styleSheetCss();
357
- if (el.textContent !== css) el.textContent = css;
358
- }
359
- function clearSectionAttrs(root) {
360
- for (const attr of Object.values(SECTION_ATTRS)) {
361
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
362
- }
363
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
364
- restoreInline(el, "background");
365
- el.removeAttribute("data-ohw-style-bgcolor");
366
- }
367
- }
368
- function clearNodeProps(root) {
369
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
370
- const h = el;
371
- for (const prop of NODE_PROPS) restoreInline(h, prop);
372
- h.removeAttribute(NODE_WROTE_ATTR);
373
- }
374
- }
375
- function buttonSurfaceOf(el) {
376
- return el.closest("a, button") ?? el;
377
- }
378
- function applyStylesToDom(store) {
379
- ensureStyleSheet();
380
- clearSectionAttrs(document);
381
- clearNodeProps(document);
382
- loadStyleFonts(
383
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
384
- );
385
- if (!store) return;
386
- for (const [sectionId, override] of Object.entries(store.sections)) {
387
- const sections = document.querySelectorAll(
388
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
389
- );
390
- for (const section of Array.from(sections)) {
391
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
392
- const value = override[prop];
393
- if (value === void 0) continue;
394
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
395
- section.setAttribute(attr, String(value).replace(":", "-"));
396
- }
397
- if (override.sectionBackgroundColor !== void 0) {
398
- saveInline(section, "background");
399
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
400
- section.setAttribute("data-ohw-style-bgcolor", "");
401
- }
402
- }
403
- }
404
- for (const [key, override] of Object.entries(store.nodes)) {
405
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
406
- for (const el of Array.from(nodes)) {
407
- if (override.color !== void 0) {
408
- saveInline(el, "color");
409
- el.style.setProperty("color", override.color, "important");
410
- el.setAttribute(NODE_WROTE_ATTR, "");
411
- }
412
- if (override.fontFamily !== void 0) {
413
- saveInline(el, "font-family");
414
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
415
- el.setAttribute(NODE_WROTE_ATTR, "");
416
- }
417
- if (override.fontSize !== void 0) {
418
- saveInline(el, "font-size");
419
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
420
- el.setAttribute(NODE_WROTE_ATTR, "");
421
- }
422
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
423
- const surface = buttonSurfaceOf(el);
424
- if (override.buttonBackground !== void 0) {
425
- saveInline(surface, "background");
426
- surface.style.setProperty("background", override.buttonBackground, "important");
427
- }
428
- if (override.buttonText !== void 0) {
429
- saveInline(surface, "color");
430
- surface.style.setProperty("color", override.buttonText, "important");
431
- }
432
- surface.setAttribute(NODE_WROTE_ATTR, "");
433
- }
434
- }
435
- }
436
- }
437
-
438
121
  // src/ui/ai-tree/aiSectionsManager.tsx
439
122
  import { flushSync } from "react-dom";
440
123
  import { createRoot } from "react-dom/client";
@@ -449,8 +132,7 @@ function lucideByName(name) {
449
132
  }
450
133
  var typeStyle = (spec, font) => ({
451
134
  fontFamily: font,
452
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
453
- fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
135
+ fontSize: spec.size,
454
136
  lineHeight: spec.line,
455
137
  fontWeight: spec.weight
456
138
  });
@@ -465,36 +147,6 @@ var FEATURE_LINE_CSS = [
465
147
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
466
148
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
467
149
  ].join("");
468
- function hexLuminance(color) {
469
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
470
- if (!m) return null;
471
- const [r2, g, b] = [0, 2, 4].map((i) => {
472
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
473
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
474
- });
475
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
476
- }
477
- function hexContrast(a, b) {
478
- const la = hexLuminance(a);
479
- const lb = hexLuminance(b);
480
- if (la === null || lb === null) return null;
481
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
482
- return (hi + 0.05) / (lo + 0.05);
483
- }
484
- function accentBandContext(brand) {
485
- const p = brand.palette;
486
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
487
- if (lightWins) {
488
- return {
489
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
490
- buttonLabel: p.primary
491
- };
492
- }
493
- return {
494
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
495
- buttonLabel: p.light
496
- };
497
- }
498
150
  function textAttrs(ctx, path) {
499
151
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
500
152
  }
@@ -507,8 +159,6 @@ var AI_RESPONSIVE_CSS = [
507
159
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
508
160
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
509
161
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
510
- " [data-ai-responsive] { overflow-x: hidden; }",
511
- " [data-ai-responsive] img { max-width: 100%; }",
512
162
  "}"
513
163
  ].join("\n");
514
164
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -586,7 +236,7 @@ function ButtonEl({
586
236
  }) {
587
237
  const secondary = slots.variant === "secondary";
588
238
  const href = str(slots.href);
589
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
239
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
590
240
  return /* @__PURE__ */ jsx(
591
241
  "a",
592
242
  {
@@ -602,7 +252,7 @@ function ButtonEl({
602
252
  textDecoration: "none",
603
253
  cursor: "pointer",
604
254
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
605
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
255
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
606
256
  },
607
257
  children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
608
258
  }
@@ -1504,14 +1154,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1504
1154
  return null;
1505
1155
  }
1506
1156
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1507
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1508
- const blockBrand = band?.brand ?? resolvedBrand;
1509
1157
  const ctx = {
1510
- brand: blockBrand,
1158
+ brand: resolvedBrand,
1511
1159
  resolveMedia: resolveMedia ?? (() => null),
1512
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1513
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1514
- ...band ? { buttonLabel: band.buttonLabel } : {}
1160
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1161
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1515
1162
  };
1516
1163
  const settings = tree.settings ?? {};
1517
1164
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1519,20 +1166,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1519
1166
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1520
1167
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1521
1168
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1522
- const toneBackground = (() => {
1523
- const { dark, primary, light } = resolvedBrand.palette;
1524
- switch (settings.sectionBackground) {
1525
- case "surface":
1526
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1527
- case "accent":
1528
- return primary;
1529
- case "accent-soft":
1530
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1531
- default:
1532
- return void 0;
1533
- }
1534
- })();
1535
- const distributed = !isOverlay && settings.textDistribution;
1536
1169
  return /* @__PURE__ */ jsxs(
1537
1170
  "section",
1538
1171
  {
@@ -1542,11 +1175,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1542
1175
  style: {
1543
1176
  position: "relative",
1544
1177
  padding: `${pad}px 0`,
1545
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1178
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1546
1179
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1547
1180
  backgroundSize: "cover",
1548
- backgroundPosition: "center",
1549
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1181
+ backgroundPosition: "center"
1550
1182
  },
1551
1183
  children: [
1552
1184
  /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
@@ -1570,24 +1202,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1570
1202
  display: "grid",
1571
1203
  gridTemplateColumns: "repeat(12, 1fr)",
1572
1204
  gap: AI_TREE_TOKENS.spacing6,
1573
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1205
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1574
1206
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1575
1207
  },
1576
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
1577
- "div",
1578
- {
1579
- "data-ai-cell": "",
1580
- style: {
1581
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1582
- minWidth: 0,
1583
- // space-between: each column becomes a flex column whose content spreads over
1584
- // the full row height instead of clumping at the top.
1585
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1586
- },
1587
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1588
- },
1589
- b
1590
- ))
1208
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1591
1209
  },
1592
1210
  r2
1593
1211
  ))
@@ -1603,36 +1221,17 @@ import { jsx as jsx2 } from "react/jsx-runtime";
1603
1221
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1604
1222
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1605
1223
  var REMOVED_ATTR = "data-ohw-ai-removed";
1606
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1607
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1608
- function readRootVar(name) {
1609
- if (typeof document === "undefined") return "";
1610
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1611
- }
1612
- function deriveBrandOverride() {
1613
- const dark = readRootVar("--ohw-brand-dark");
1614
- const primary = readRootVar("--ohw-brand-primary");
1615
- const light = readRootVar("--ohw-brand-light");
1616
- if (!dark || !primary || !light) return null;
1617
- const accent = readRootVar("--ohw-brand-accent");
1618
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1619
- const body = readRootVar("--font-body");
1620
- return {
1621
- palette: { dark, primary, accent: accent || dark, light },
1622
- fonts: {
1623
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1624
- body: body || AI_DEFAULT_BRAND.fonts.body
1625
- }
1626
- };
1627
- }
1628
1224
  function deriveTemplateBrand() {
1629
- const dark = readRootVar("--color-dark");
1630
- const primary = readRootVar("--color-primary");
1631
- const light = readRootVar("--color-light");
1225
+ if (typeof document === "undefined") return null;
1226
+ const cs = getComputedStyle(document.documentElement);
1227
+ const read = (name) => cs.getPropertyValue(name).trim();
1228
+ const dark = read("--color-dark");
1229
+ const primary = read("--color-primary");
1230
+ const light = read("--color-light");
1632
1231
  if (!dark || !primary || !light) return null;
1633
- const accent = readRootVar("--color-accent");
1634
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1635
- const body = readRootVar("--font-body");
1232
+ const accent = read("--color-accent");
1233
+ const heading = read("--font-heading") || read("--font-display");
1234
+ const body = read("--font-body");
1636
1235
  return {
1637
1236
  palette: { dark, primary, accent: accent || dark, light },
1638
1237
  fonts: {
@@ -1704,24 +1303,6 @@ function syncRemovedSections(state) {
1704
1303
  }
1705
1304
  }
1706
1305
  }
1707
- function syncTemplateHidden(state, pageHasSections) {
1708
- const hide = state.hideTemplate === true && pageHasSections;
1709
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1710
- if (!hide) {
1711
- el.style.removeProperty("display");
1712
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1713
- }
1714
- }
1715
- if (!hide) return;
1716
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1717
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1718
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1719
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1720
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1721
- el.style.display = "none";
1722
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1723
- }
1724
- }
1725
1306
  function syncReplacedOriginals(state) {
1726
1307
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1727
1308
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1742,12 +1323,8 @@ function syncReplacedOriginals(state) {
1742
1323
  }
1743
1324
  function applyAiSectionsToDom(state, options) {
1744
1325
  if (typeof document === "undefined") return;
1745
- const brandOverride = deriveBrandOverride();
1746
1326
  const templateBrand = deriveTemplateBrand();
1747
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1748
- const pagePath = window.location.pathname;
1749
- const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
1750
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1327
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1751
1328
  for (const [id, section] of mounted) {
1752
1329
  if (!activeIds.has(id)) {
1753
1330
  section.root.unmount();
@@ -1755,8 +1332,8 @@ function applyAiSectionsToDom(state, options) {
1755
1332
  mounted.delete(id);
1756
1333
  }
1757
1334
  }
1758
- for (const entry of pageSections) {
1759
- const serialized = JSON.stringify(entry) + brandKey;
1335
+ for (const entry of state.sections) {
1336
+ const serialized = JSON.stringify(entry);
1760
1337
  const existing = mounted.get(entry.id);
1761
1338
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1762
1339
  continue;
@@ -1770,7 +1347,6 @@ function applyAiSectionsToDom(state, options) {
1770
1347
  mounted.delete(entry.id);
1771
1348
  }
1772
1349
  container.setAttribute("data-ohw-section", entry.id);
1773
- container.setAttribute("data-ohw-instance", entry.id);
1774
1350
  container.setAttribute("data-ohw-section-label", entry.label);
1775
1351
  placeContainer(container, entry);
1776
1352
  const root = mounted.get(entry.id)?.root ?? createRoot(container);
@@ -1781,7 +1357,7 @@ function applyAiSectionsToDom(state, options) {
1781
1357
  AiTreeRenderer,
1782
1358
  {
1783
1359
  tree: entry.tree,
1784
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1360
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1785
1361
  resolveMedia,
1786
1362
  editKeyPrefix: `ai.${entry.id}`
1787
1363
  }
@@ -1792,7 +1368,6 @@ function applyAiSectionsToDom(state, options) {
1792
1368
  }
1793
1369
  syncReplacedOriginals(state);
1794
1370
  syncRemovedSections(state);
1795
- syncTemplateHidden(state, pageSections.length > 0);
1796
1371
  }
1797
1372
 
1798
1373
  // src/useLinkHrefGuardian.ts
@@ -2399,7 +1974,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2399
1974
  const autoId = useId();
2400
1975
  const insertAfter = insertAfterProp ?? autoId;
2401
1976
  const [schedule, setSchedule] = useState2(null);
2402
- const [loading, setLoading] = useState2(initialScheduleId !== null);
1977
+ const [loading, setLoading] = useState2(true);
2403
1978
  const [inEditor, setInEditor] = useState2(false);
2404
1979
  const [isHovered, setIsHovered] = useState2(false);
2405
1980
  const [modalState, setModalState] = useState2(null);
@@ -2573,10 +2148,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2573
2148
  "*"
2574
2149
  );
2575
2150
  };
2151
+ if (!inEditor && !loading && !schedule) return null;
2576
2152
  const sectionId = `scheduling-${insertAfter}`;
2577
- if (!inEditor && !loading && !schedule) {
2578
- return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2579
- }
2580
2153
  return /* @__PURE__ */ jsxs3(
2581
2154
  "section",
2582
2155
  {
@@ -7107,7 +6680,6 @@ function applyFieldType(wrapper, type) {
7107
6680
  if (inputType) input.type = inputType;
7108
6681
  shedSize(input);
7109
6682
  applyDefaults(input);
7110
- requireIfEmail(wrapper, type);
7111
6683
  return;
7112
6684
  }
7113
6685
  const next = document.createElement(tag);
@@ -7120,11 +6692,6 @@ function applyFieldType(wrapper, type) {
7120
6692
  if (type === "long-text") next.setAttribute("rows", "4");
7121
6693
  input.replaceWith(next);
7122
6694
  applyDefaults(next);
7123
- requireIfEmail(wrapper, type);
7124
- }
7125
- function requireIfEmail(wrapper, type) {
7126
- if (type !== "email") return;
7127
- setFieldRequired(wrapper, true);
7128
6695
  }
7129
6696
  var REQUIRED_MARK_ATTR = "data-ohw-field-required";
7130
6697
  function fieldLabelText(label) {
@@ -7207,7 +6774,6 @@ function insertField(form, type) {
7207
6774
  const label = ensureFieldLabel(wrapper, key);
7208
6775
  label.textContent = defaults.label;
7209
6776
  label.setAttribute("data-ohw-key", `${key}-label`);
7210
- requireIfEmail(wrapper, type);
7211
6777
  return wrapper;
7212
6778
  }
7213
6779
  function duplicateField(form, wrapper) {
@@ -7349,7 +6915,7 @@ function FormFieldToolbar({
7349
6915
  "aria-pressed": required,
7350
6916
  onClick: onRequiredToggle,
7351
6917
  className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
7352
- "data-ohw-field-required-toggle": "",
6918
+ "data-ohw-field-required": "",
7353
6919
  children: [
7354
6920
  /* @__PURE__ */ jsx13(Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
7355
6921
  "Required"
@@ -7484,17 +7050,13 @@ function MediaOverlay({
7484
7050
  hover,
7485
7051
  isUploading,
7486
7052
  fadingOut = false,
7487
- selected = false,
7488
- hovered = false,
7489
7053
  onFadeOutComplete,
7490
7054
  onReplace,
7491
- onSelect,
7492
7055
  onVideoSettingsChange
7493
7056
  }) {
7494
7057
  const { rect } = hover;
7495
7058
  const skeletonRef = React7.useRef(null);
7496
7059
  const isVideo = hover.elementType === "video";
7497
- const showChrome = !selected || hovered;
7498
7060
  const autoplay = hover.videoAutoplay ?? true;
7499
7061
  const muted = hover.videoMuted ?? true;
7500
7062
  const box = {
@@ -7529,7 +7091,7 @@ function MediaOverlay({
7529
7091
  }
7530
7092
  );
7531
7093
  }
7532
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ jsxs7(
7094
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
7533
7095
  "div",
7534
7096
  {
7535
7097
  "data-ohw-bridge": "",
@@ -7599,13 +7161,11 @@ function MediaOverlay({
7599
7161
  // in-document, pointer-events does it natively. The button below opts back in, so
7600
7162
  // Replace still works.
7601
7163
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7602
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7603
- // than hovered. Hover keeps the existing tinted preview.
7604
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7605
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7164
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7165
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7606
7166
  },
7607
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7608
- children: showChrome && /* @__PURE__ */ jsxs7(
7167
+ onClick: () => onReplace(hover.key),
7168
+ children: /* @__PURE__ */ jsxs7(
7609
7169
  Button,
7610
7170
  {
7611
7171
  "data-ohw-media-overlay": "",
@@ -7694,9 +7254,6 @@ import { Check, X } from "lucide-react";
7694
7254
 
7695
7255
  // src/lib/sections.ts
7696
7256
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7697
- function isChromeSection(el) {
7698
- return el.matches("header, nav, footer, aside");
7699
- }
7700
7257
  function titleCaseSectionId(id) {
7701
7258
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7702
7259
  }
@@ -7707,8 +7264,6 @@ function parseSectionsFromRoot(root) {
7707
7264
  const id = el.getAttribute("data-ohw-section") ?? "";
7708
7265
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7709
7266
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7710
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7711
- continue;
7712
7267
  seen.add(id);
7713
7268
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7714
7269
  sections.push({ id, label });
@@ -7726,12 +7281,8 @@ function parseSectionsFromHtml(html) {
7726
7281
 
7727
7282
  // src/ui/ai-section/AiSectionOverlay.tsx
7728
7283
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
7729
- function findSectionElement(instanceId) {
7730
- const escaped = CSS.escape(instanceId);
7731
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7732
- }
7733
- function readRect(instanceId) {
7734
- const el = findSectionElement(instanceId);
7284
+ function readRect(sectionId) {
7285
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7735
7286
  if (!el) return null;
7736
7287
  const r2 = el.getBoundingClientRect();
7737
7288
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7754,7 +7305,7 @@ function useLiveSectionRect(sectionId) {
7754
7305
  const opts = { capture: true, passive: true };
7755
7306
  window.addEventListener("scroll", update, opts);
7756
7307
  window.addEventListener("resize", update);
7757
- const el = findSectionElement(sectionId);
7308
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7758
7309
  const ro = el ? new ResizeObserver(update) : null;
7759
7310
  if (el && ro) ro.observe(el);
7760
7311
  const interval = setInterval(update, 500);
@@ -7767,14 +7318,6 @@ function useLiveSectionRect(sectionId) {
7767
7318
  }, [sectionId]);
7768
7319
  return rect;
7769
7320
  }
7770
- function computeSectionBoundaryFlags(instanceId) {
7771
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7772
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7773
- );
7774
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7775
- if (index === -1) return { isFirst: true, isLast: true };
7776
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7777
- }
7778
7321
  var PRIMARY2 = "#0885FE";
7779
7322
  function edgeAwareRadius(rect) {
7780
7323
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7848,7 +7391,6 @@ function AiSectionOverlay({
7848
7391
  }) {
7849
7392
  const [selectedId, setSelectedId] = useState4(null);
7850
7393
  const [reviewId, setReviewId] = useState4(null);
7851
- const [reviewButtonsHidden, setReviewButtonsHidden] = useState4(false);
7852
7394
  const reviewIdRef = useRef4(null);
7853
7395
  reviewIdRef.current = reviewId;
7854
7396
  const selectedIdRef = useRef4(null);
@@ -7857,7 +7399,7 @@ function AiSectionOverlay({
7857
7399
  (el) => {
7858
7400
  postToParent2({
7859
7401
  type: "ow:section-selected",
7860
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7402
+ sectionId: el?.dataset.ohwSection ?? null,
7861
7403
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7862
7404
  });
7863
7405
  },
@@ -7866,7 +7408,7 @@ function AiSectionOverlay({
7866
7408
  const selectFromElement = useCallback2(
7867
7409
  (el, options) => {
7868
7410
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7869
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7411
+ const id = sectionEl?.dataset.ohwSection ?? null;
7870
7412
  if (id === selectedIdRef.current) return;
7871
7413
  setSelectedId(id);
7872
7414
  if (options?.report !== false) report(sectionEl);
@@ -7907,10 +7449,9 @@ function AiSectionOverlay({
7907
7449
  }
7908
7450
  const found = readRect(sectionId) != null;
7909
7451
  setReviewId(found ? sectionId : null);
7910
- setReviewButtonsHidden(e.data.hideButtons === true);
7911
7452
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7912
7453
  if (found) {
7913
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7454
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7914
7455
  }
7915
7456
  }
7916
7457
  };
@@ -7929,7 +7470,7 @@ function AiSectionOverlay({
7929
7470
  return;
7930
7471
  }
7931
7472
  const sec = t.closest("[data-ohw-section]");
7932
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7473
+ setHoveredId(sec?.dataset.ohwSection ?? null);
7933
7474
  };
7934
7475
  const onLeave = () => setHoveredId(null);
7935
7476
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -7961,30 +7502,9 @@ function AiSectionOverlay({
7961
7502
  },
7962
7503
  [postToParent2]
7963
7504
  );
7964
- const activeSelectionId = reviewId ? null : selectedId;
7965
- const selectionRect = useLiveSectionRect(activeSelectionId);
7505
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
7966
7506
  const reviewRect = useLiveSectionRect(reviewId);
7967
7507
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
7968
- useEffect4(() => {
7969
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
7970
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
7971
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
7972
- return;
7973
- }
7974
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
7975
- postToParent2({
7976
- type: "ow:section-rect",
7977
- instanceId: activeSelectionId,
7978
- rect: {
7979
- top: selectionRect.top + window.scrollY,
7980
- left: selectionRect.left + window.scrollX,
7981
- width: selectionRect.width,
7982
- height: selectionRect.height
7983
- },
7984
- isFirst,
7985
- isLast
7986
- });
7987
- }, [activeSelectionId, selectionRect, postToParent2]);
7988
7508
  return /* @__PURE__ */ jsxs9(Fragment5, { children: [
7989
7509
  hoverRect && /* @__PURE__ */ jsx17(
7990
7510
  "div",
@@ -8035,16 +7555,13 @@ function AiSectionOverlay({
8035
7555
  border: `2px solid ${PRIMARY2}`,
8036
7556
  borderRadius: edgeAwareRadius(reviewRect),
8037
7557
  zIndex: 2147483200,
8038
- // The veil itself: swallows clicks so the section stays locked until decided. This
8039
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8040
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8041
- // Accept/Discard resolves to the media beneath and opens the file picker.
7558
+ // The veil itself: swallows clicks so the section stays locked until decided.
8042
7559
  background: "rgba(8, 133, 254, 0.04)",
8043
7560
  pointerEvents: "auto",
8044
7561
  cursor: "default"
8045
7562
  },
8046
7563
  onClick: (e) => e.stopPropagation(),
8047
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
7564
+ children: /* @__PURE__ */ jsxs9(
8048
7565
  "div",
8049
7566
  {
8050
7567
  style: {
@@ -8069,58 +7586,6 @@ function AiSectionOverlay({
8069
7586
 
8070
7587
  // src/lib/section-instances.ts
8071
7588
  var SECTION_ORDER_KEY = "__ohw_section_order";
8072
- function topLevelSections() {
8073
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8074
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8075
- );
8076
- }
8077
- function instanceIdOf(el) {
8078
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8079
- }
8080
- function planSectionMove(instanceId, targetIndex, currentPath) {
8081
- const sections = topLevelSections();
8082
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8083
- if (index === -1) return null;
8084
- const dragged = sections[index];
8085
- const others = sections.filter((_, i) => i !== index);
8086
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8087
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8088
- return reordered.map((el, order) => ({
8089
- instanceId: instanceIdOf(el),
8090
- type: el.getAttribute("data-ohw-section") ?? "",
8091
- order,
8092
- pagePath: currentPath
8093
- }));
8094
- }
8095
- function moveSectionInstance(instanceId, direction, currentPath) {
8096
- const sections = topLevelSections();
8097
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8098
- if (index === -1) return null;
8099
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8100
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8101
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8102
- if (!entries) return null;
8103
- applyPersistedOrder(entries);
8104
- return entries;
8105
- }
8106
- function applyPersistedOrder(entries) {
8107
- if (entries.length === 0) return;
8108
- const sections = topLevelSections();
8109
- if (sections.length === 0) return;
8110
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8111
- const ordered = [...sections].sort((a, b) => {
8112
- const aOrder = orderIndex.get(instanceIdOf(a));
8113
- const bOrder = orderIndex.get(instanceIdOf(b));
8114
- if (aOrder === void 0 && bOrder === void 0) return 0;
8115
- if (aOrder === void 0) return 1;
8116
- if (bOrder === void 0) return -1;
8117
- return aOrder - bOrder;
8118
- });
8119
- const parent = sections[0].parentElement;
8120
- if (!parent) return;
8121
- const anchor = sections[sections.length - 1].nextSibling;
8122
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8123
- }
8124
7589
  function getPageSectionOrderEntries(raw, currentPath) {
8125
7590
  if (!raw) return [];
8126
7591
  try {
@@ -8158,7 +7623,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8158
7623
  rekeySectionSubtree(clone, entry.instanceId);
8159
7624
  original.insertAdjacentElement("afterend", clone);
8160
7625
  }
8161
- applyPersistedOrder(entries);
8162
7626
  }
8163
7627
 
8164
7628
  // src/OhhwellsBridge.tsx
@@ -12003,12 +11467,17 @@ function deleteFooterColumn(column) {
12003
11467
  }
12004
11468
 
12005
11469
  // src/lib/logo-identity.ts
12006
- var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
12007
- var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
11470
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text", "nav-logo", "logo"];
11471
+ var LOGO_IMAGE_KEYS = [
11472
+ "nav-logo-image",
11473
+ "footer-logo",
11474
+ "footer-logo-image",
11475
+ "logo-image",
11476
+ "footer-logo-img"
11477
+ ];
12008
11478
  var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
12009
11479
  var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
12010
11480
  var LOGO_ALT_KEY = "logo-alt";
12011
- var LOGO_IMAGE_URL_KEY = "nav-logo-image";
12012
11481
  var PLACEHOLDER_BUSINESS_NAME = "Business name";
12013
11482
  function resolveLogoDisplayText(text) {
12014
11483
  const trimmed = (text ?? "").trim();
@@ -12028,6 +11497,21 @@ function ensureLogoHrefKey(root) {
12028
11497
  if (root.hasAttribute("data-ohw-href-key")) return;
12029
11498
  root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
12030
11499
  }
11500
+ function logoTextElement(root) {
11501
+ const SELECTOR = '[data-ohw-editable="plain"], [data-ohw-editable="text"]';
11502
+ if (root.matches(SELECTOR)) return root;
11503
+ const marked = root.querySelector(SELECTOR);
11504
+ if (marked) return marked;
11505
+ const hasOwnText = Array.from(root.childNodes).some(
11506
+ (node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
11507
+ );
11508
+ return hasOwnText ? root : null;
11509
+ }
11510
+ function logoRootImage(root) {
11511
+ const img = root.querySelector("img");
11512
+ const src = img?.getAttribute("src")?.trim() ?? "";
11513
+ return img && src && img.style.display !== "none" ? img : null;
11514
+ }
12031
11515
  function applyLogoIdentity(text, isPlaceholder) {
12032
11516
  const display = resolveLogoDisplayText(text);
12033
11517
  const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
@@ -12045,6 +11529,9 @@ function applyLogoIdentity(text, isPlaceholder) {
12045
11529
  document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
12046
11530
  if (placeholder) el.setAttribute("data-ohw-placeholder", "");
12047
11531
  else el.removeAttribute("data-ohw-placeholder");
11532
+ if (logoRootImage(el)) return;
11533
+ const textEl = logoTextElement(el);
11534
+ if (textEl && textEl.textContent !== display) textEl.textContent = display;
12048
11535
  });
12049
11536
  return display;
12050
11537
  }
@@ -12055,7 +11542,7 @@ function applyLogoImage(url, alt) {
12055
11542
  const imageKey = imageKeyForRoot(root);
12056
11543
  const textKey = textKeyForRoot(root);
12057
11544
  let img = root.querySelector(`img[data-ohw-key="${imageKey}"]`) ?? (root.querySelector(`[data-ohw-key="${imageKey}"]`) instanceof HTMLImageElement ? root.querySelector(`[data-ohw-key="${imageKey}"]`) : null) ?? root.querySelector("img");
12058
- let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
11545
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]') ?? logoTextElement(root);
12059
11546
  if (url) {
12060
11547
  if (!img) {
12061
11548
  img = document.createElement("img");
@@ -12077,7 +11564,11 @@ function applyLogoImage(url, alt) {
12077
11564
  img.src = url;
12078
11565
  img.alt = displayAlt;
12079
11566
  img.style.display = "block";
12080
- if (textEl) textEl.style.display = "none";
11567
+ if (textEl === root) {
11568
+ Array.from(root.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).forEach((node) => node.remove());
11569
+ } else if (textEl) {
11570
+ textEl.style.display = "none";
11571
+ }
12081
11572
  root.removeAttribute("data-ohw-placeholder");
12082
11573
  return;
12083
11574
  }
@@ -12126,6 +11617,13 @@ function readLogoIdentityFromDom() {
12126
11617
  }
12127
11618
  let text = PLACEHOLDER_BUSINESS_NAME;
12128
11619
  let isPlaceholder = true;
11620
+ const rootWithText = Array.from(
11621
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
11622
+ ).find((root) => logoTextElement(root)?.textContent?.trim());
11623
+ if (rootWithText) {
11624
+ text = logoTextElement(rootWithText).textContent.trim();
11625
+ isPlaceholder = rootWithText.hasAttribute("data-ohw-placeholder") || text === PLACEHOLDER_BUSINESS_NAME;
11626
+ }
12129
11627
  for (const key of LOGO_TEXT_KEYS) {
12130
11628
  const el = document.querySelector(`[data-ohw-key="${key}"]`);
12131
11629
  if (el?.textContent?.trim()) {
@@ -12156,7 +11654,7 @@ function applyLogoFromContent(content) {
12156
11654
  if (!hasLogoIdentity) return false;
12157
11655
  const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
12158
11656
  const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
12159
- const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11657
+ const rawLogoImage = LOGO_IMAGE_KEYS.map((key) => content[key]).find((value) => typeof value === "string" && value.trim()) ?? null;
12160
11658
  const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
12161
11659
  const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
12162
11660
  const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
@@ -12291,7 +11789,6 @@ function readLogoSizeState(content, placement) {
12291
11789
  function getLogoElement(el) {
12292
11790
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12293
11791
  if (marked) return marked;
12294
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12295
11792
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12296
11793
  if (!root) return null;
12297
11794
  const anchor = el.closest("a");
@@ -13162,449 +12659,122 @@ function useNavItemDrag({
13162
12659
  };
13163
12660
  }
13164
12661
 
13165
- // src/useSectionDrag.ts
13166
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef9, useState as useState10 } from "react";
12662
+ // src/ui/footer-container-chrome.tsx
12663
+ import { Plus as Plus2 } from "lucide-react";
12664
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
12665
+ function FooterContainerChrome({
12666
+ rect,
12667
+ onAdd,
12668
+ addDisabled = false
12669
+ }) {
12670
+ const chromeGap = 6;
12671
+ const buttonMargin = 7;
12672
+ return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
12673
+ "div",
12674
+ {
12675
+ "data-ohw-footer-container-chrome": "",
12676
+ "data-ohw-bridge": "",
12677
+ className: "pointer-events-none fixed z-[2147483647]",
12678
+ style: {
12679
+ top: rect.top - chromeGap,
12680
+ left: rect.left - chromeGap,
12681
+ width: rect.width + chromeGap * 2,
12682
+ height: rect.height + chromeGap * 2
12683
+ },
12684
+ children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
12685
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
12686
+ "button",
12687
+ {
12688
+ type: "button",
12689
+ "data-ohw-footer-add-button": "",
12690
+ disabled: addDisabled,
12691
+ className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80 disabled:pointer-events-none disabled:opacity-40",
12692
+ style: { top: chromeGap - buttonMargin },
12693
+ "aria-label": "Add item",
12694
+ onMouseDown: (e) => {
12695
+ e.preventDefault();
12696
+ e.stopPropagation();
12697
+ },
12698
+ onClick: (e) => {
12699
+ e.preventDefault();
12700
+ e.stopPropagation();
12701
+ if (addDisabled) return;
12702
+ onAdd();
12703
+ },
12704
+ children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12705
+ }
12706
+ ) }),
12707
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12708
+ ] })
12709
+ }
12710
+ ) });
12711
+ }
13167
12712
 
13168
- // src/lib/section-dnd.ts
13169
- function isFooterSection(el) {
13170
- return el.dataset.ohwSection === "footer";
12713
+ // src/lib/carousel.ts
12714
+ import { useEffect as useEffect11, useState as useState10 } from "react";
12715
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12716
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12717
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12718
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12719
+ function listCarouselKeys() {
12720
+ const keys = /* @__PURE__ */ new Set();
12721
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12722
+ const key = el.getAttribute("data-ohw-key");
12723
+ if (key) keys.add(key);
12724
+ });
12725
+ return [...keys];
13171
12726
  }
13172
- function buildSectionDropSlots(draggedInstanceId) {
13173
- const sections = topLevelSections().filter(
13174
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12727
+ function containersForKey(key) {
12728
+ return Array.from(
12729
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13175
12730
  );
13176
- const slots = [];
13177
- if (sections.length === 0) return slots;
13178
- const left = 0;
13179
- const width = document.documentElement.clientWidth;
13180
- for (let i = 0; i <= sections.length; i++) {
13181
- let y;
13182
- if (i === 0) {
13183
- y = sections[0].getBoundingClientRect().top;
13184
- } else if (i === sections.length) {
13185
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13186
- } else {
13187
- const prev = sections[i - 1].getBoundingClientRect();
13188
- const next = sections[i].getBoundingClientRect();
13189
- y = (prev.bottom + next.top) / 2;
13190
- }
13191
- slots.push({ insertIndex: i, y, left, width });
12731
+ }
12732
+ function isCarouselKey(key) {
12733
+ return containersForKey(key).length > 0;
12734
+ }
12735
+ function parseSlides(raw) {
12736
+ if (!raw) return [];
12737
+ try {
12738
+ const parsed = JSON.parse(raw);
12739
+ if (!Array.isArray(parsed)) return [];
12740
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12741
+ } catch {
12742
+ return [];
13192
12743
  }
13193
- return slots;
13194
12744
  }
13195
- function hitTestSectionDropSlot(y, slots) {
13196
- let best = null;
13197
- for (const slot of slots) {
13198
- const dist = Math.abs(y - slot.y);
13199
- if (!best || dist < best.dist) best = { slot, dist };
12745
+ function readCarouselValue(key) {
12746
+ const container = containersForKey(key)[0];
12747
+ if (!container) return [];
12748
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
12749
+ if (fromAttr.length > 0) return fromAttr;
12750
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
12751
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
12752
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
12753
+ });
12754
+ }
12755
+ function slideIndex(el) {
12756
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
12757
+ const n = raw ? parseInt(raw, 10) : NaN;
12758
+ return Number.isFinite(n) ? n : 0;
12759
+ }
12760
+ function applyCarouselValue(key, slides) {
12761
+ const value = JSON.stringify(slides);
12762
+ for (const container of containersForKey(key)) {
12763
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
12764
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
12765
+ container.dispatchEvent(
12766
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
12767
+ );
13200
12768
  }
13201
- return best?.slot ?? null;
13202
12769
  }
13203
-
13204
- // src/useSectionDrag.ts
13205
- var PRESS_THRESHOLD = 10;
13206
- var EDGE_ZONE = 60;
13207
- var MAX_AUTO_SCROLL_SPEED = 18;
13208
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13209
- "[data-ohw-toolbar]",
13210
- "[data-ohw-edit-chrome]",
13211
- "[data-ohw-item-interaction]",
13212
- "[data-ohw-drag-handle-container]",
13213
- '[data-slot="drag-handle"]',
13214
- "[data-ohw-item-toolbar-anchor]",
13215
- "[data-ohw-item-drag-surface]",
13216
- "[data-ohw-more-menu]",
13217
- '[data-slot="dropdown-menu-content"]',
13218
- '[data-slot="dropdown-menu-item"]',
13219
- "[data-ohw-state-toggle]",
13220
- "[data-ohw-max-badge]",
13221
- "[data-ohw-floating-panel]",
13222
- "[data-ohw-section-picker]",
13223
- "[data-ohw-link-popover-root]",
13224
- "[data-ohw-link-modal-root]",
13225
- "[data-ohw-link-page-dropdown]",
13226
- '[data-slot="popover-content"]',
13227
- '[data-slot="dialog-content"]',
13228
- '[data-slot="dialog-overlay"]',
13229
- "[data-ohw-ai-review]",
13230
- "[data-ohw-editable]",
13231
- "[data-ohw-editable-state]",
13232
- "[contenteditable]",
13233
- "[data-ohw-href-key]",
13234
- "[data-ohw-footer-col]",
13235
- "[data-ohw-social-label]",
13236
- "a",
13237
- "button",
13238
- '[role="button"]',
13239
- '[data-ohw-role="navbar-button"]',
13240
- '[data-ohw-role="button"]',
13241
- "[data-ohw-carousel]",
13242
- "[data-ohw-carousel-value]",
13243
- "[data-ohw-carousel-slide]",
13244
- "[data-ohw-carousel-overlay]",
13245
- "[data-ohw-media-chrome]",
13246
- "[data-ohw-media-overlay]",
13247
- "[data-ohw-media-skeleton]"
13248
- ].join(", ");
13249
- function visibleClip(ps) {
13250
- if (!ps) return null;
13251
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13252
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13253
- return { top, bottom: Math.max(top, bottom) };
13254
- }
13255
- function useSectionDrag({
13256
- isEditMode,
13257
- editContentRef,
13258
- postToParentRef,
13259
- parentScrollRef,
13260
- navDragRef,
13261
- footerDragRef,
13262
- suppressNextClickRef,
13263
- suppressClickUntilRef
13264
- }) {
13265
- const sectionDragRef = useRef9(null);
13266
- const [sectionDropSlots, setSectionDropSlots] = useState10([]);
13267
- const [activeSectionDropIndex, setActiveSectionDropIndex] = useState10(null);
13268
- const [isSectionDragging, setIsSectionDragging] = useState10(false);
13269
- const sectionPointerDragRef = useRef9(null);
13270
- const autoScrollRafRef = useRef9(null);
13271
- const autoScrollDeltaRef = useRef9(0);
13272
- const stopAutoScroll = useCallback7(() => {
13273
- if (autoScrollRafRef.current != null) {
13274
- cancelAnimationFrame(autoScrollRafRef.current);
13275
- autoScrollRafRef.current = null;
13276
- }
13277
- autoScrollDeltaRef.current = 0;
13278
- }, []);
13279
- const tickAutoScroll = useCallback7(() => {
13280
- if (!sectionDragRef.current) {
13281
- stopAutoScroll();
13282
- return;
13283
- }
13284
- if (autoScrollDeltaRef.current !== 0) {
13285
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13286
- }
13287
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13288
- }, [postToParentRef, stopAutoScroll]);
13289
- const updateAutoScroll = useCallback7(
13290
- (clientY) => {
13291
- const clip = visibleClip(parentScrollRef.current);
13292
- let delta = 0;
13293
- if (clip) {
13294
- const distTop = clientY - clip.top;
13295
- const distBottom = clip.bottom - clientY;
13296
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13297
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13298
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13299
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13300
- }
13301
- }
13302
- autoScrollDeltaRef.current = delta;
13303
- if (delta !== 0 && autoScrollRafRef.current == null) {
13304
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13305
- } else if (delta === 0) {
13306
- stopAutoScroll();
13307
- }
13308
- },
13309
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13310
- );
13311
- const clearSectionDragVisuals = useCallback7(() => {
13312
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13313
- sectionDragRef.current = null;
13314
- setSectionDropSlots([]);
13315
- setActiveSectionDropIndex(null);
13316
- setIsSectionDragging(false);
13317
- stopAutoScroll();
13318
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13319
- unlockItemDragInteraction();
13320
- }, [stopAutoScroll]);
13321
- const refreshSectionDragVisuals = useCallback7(
13322
- (session, clientX, clientY) => {
13323
- session.lastClientX = clientX;
13324
- session.lastClientY = clientY;
13325
- const slots = buildSectionDropSlots(session.instanceId);
13326
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13327
- session.activeSlot = activeSlot;
13328
- setSectionDropSlots(slots);
13329
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13330
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13331
- updateAutoScroll(clientY);
13332
- },
13333
- [updateAutoScroll]
13334
- );
13335
- const beginSectionDrag = useCallback7(
13336
- (session) => {
13337
- sectionDragRef.current = session;
13338
- setIsSectionDragging(true);
13339
- lockItemDuringDrag();
13340
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13341
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13342
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13343
- },
13344
- [refreshSectionDragVisuals]
13345
- );
13346
- const commitSectionDrag = useCallback7(() => {
13347
- const session = sectionDragRef.current;
13348
- if (!session) {
13349
- clearSectionDragVisuals();
13350
- return;
13351
- }
13352
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13353
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13354
- if (!entries) {
13355
- clearSectionDragVisuals();
13356
- return;
13357
- }
13358
- const orderJson = JSON.stringify(entries);
13359
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13360
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13361
- applyPersistedOrder(entries);
13362
- clearSectionDragVisuals();
13363
- requestAnimationFrame(() => {
13364
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13365
- applyPersistedOrder(entries);
13366
- }
13367
- requestAnimationFrame(() => {
13368
- window.dispatchEvent(new Event("resize"));
13369
- });
13370
- });
13371
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13372
- const startSectionPressDrag = useCallback7(
13373
- (el, clientX, clientY, pointerId) => {
13374
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13375
- const instanceId = instanceIdOf(el);
13376
- if (!instanceId) return false;
13377
- sectionPointerDragRef.current = {
13378
- el,
13379
- instanceId,
13380
- startX: clientX,
13381
- startY: clientY,
13382
- pointerId,
13383
- started: false
13384
- };
13385
- return true;
13386
- },
13387
- [footerDragRef, navDragRef]
13388
- );
13389
- useEffect11(() => {
13390
- if (!isEditMode) return;
13391
- const onPointerDown = (e) => {
13392
- if (e.button !== 0) return;
13393
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13394
- if (sectionPointerDragRef.current) return;
13395
- const target = e.target;
13396
- if (!(target instanceof HTMLElement)) return;
13397
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13398
- const sectionEl = target.closest("[data-ohw-section]");
13399
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13400
- if (!topLevelSections().includes(sectionEl)) return;
13401
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13402
- };
13403
- const onPointerMove = (e) => {
13404
- const pending = sectionPointerDragRef.current;
13405
- if (!pending) return;
13406
- if (pending.started) {
13407
- e.preventDefault();
13408
- clearTextSelection();
13409
- const session = sectionDragRef.current;
13410
- if (!session) return;
13411
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13412
- return;
13413
- }
13414
- const dx = e.clientX - pending.startX;
13415
- const dy = e.clientY - pending.startY;
13416
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13417
- e.preventDefault();
13418
- pending.started = true;
13419
- armItemPressDrag();
13420
- clearTextSelection();
13421
- try {
13422
- document.body.setPointerCapture(pending.pointerId);
13423
- } catch {
13424
- }
13425
- beginSectionDrag({
13426
- instanceId: pending.instanceId,
13427
- draggedEl: pending.el,
13428
- lastClientX: e.clientX,
13429
- lastClientY: e.clientY,
13430
- activeSlot: null
13431
- });
13432
- };
13433
- const endPointerDrag = (e) => {
13434
- const pending = sectionPointerDragRef.current;
13435
- sectionPointerDragRef.current = null;
13436
- try {
13437
- if (document.body.hasPointerCapture(e.pointerId)) {
13438
- document.body.releasePointerCapture(e.pointerId);
13439
- }
13440
- } catch {
13441
- }
13442
- if (!pending) return;
13443
- if (!pending.started) {
13444
- unlockItemDragInteraction();
13445
- return;
13446
- }
13447
- suppressNextClickRef.current = true;
13448
- suppressClickUntilRef.current = Date.now() + 500;
13449
- commitSectionDrag();
13450
- };
13451
- const onKeyDown = (e) => {
13452
- if (e.key !== "Escape") return;
13453
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13454
- sectionPointerDragRef.current = null;
13455
- clearSectionDragVisuals();
13456
- };
13457
- document.addEventListener("pointerdown", onPointerDown, true);
13458
- document.addEventListener("pointermove", onPointerMove, true);
13459
- document.addEventListener("pointerup", endPointerDrag, true);
13460
- document.addEventListener("pointercancel", endPointerDrag, true);
13461
- document.addEventListener("keydown", onKeyDown, true);
13462
- return () => {
13463
- document.removeEventListener("pointerdown", onPointerDown, true);
13464
- document.removeEventListener("pointermove", onPointerMove, true);
13465
- document.removeEventListener("pointerup", endPointerDrag, true);
13466
- document.removeEventListener("pointercancel", endPointerDrag, true);
13467
- document.removeEventListener("keydown", onKeyDown, true);
13468
- unlockItemDragInteraction();
13469
- stopAutoScroll();
13470
- };
13471
- }, [
13472
- beginSectionDrag,
13473
- clearSectionDragVisuals,
13474
- commitSectionDrag,
13475
- footerDragRef,
13476
- isEditMode,
13477
- navDragRef,
13478
- refreshSectionDragVisuals,
13479
- startSectionPressDrag,
13480
- stopAutoScroll,
13481
- suppressClickUntilRef,
13482
- suppressNextClickRef
13483
- ]);
13484
- return {
13485
- sectionDragRef,
13486
- sectionDropSlots,
13487
- activeSectionDropIndex,
13488
- isSectionDragging
13489
- };
13490
- }
13491
-
13492
- // src/ui/footer-container-chrome.tsx
13493
- import { Plus as Plus2 } from "lucide-react";
13494
- import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
13495
- function FooterContainerChrome({
13496
- rect,
13497
- onAdd,
13498
- addDisabled = false
13499
- }) {
13500
- const chromeGap = 6;
13501
- const buttonMargin = 7;
13502
- return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
13503
- "div",
13504
- {
13505
- "data-ohw-footer-container-chrome": "",
13506
- "data-ohw-bridge": "",
13507
- className: "pointer-events-none fixed z-[2147483647]",
13508
- style: {
13509
- top: rect.top - chromeGap,
13510
- left: rect.left - chromeGap,
13511
- width: rect.width + chromeGap * 2,
13512
- height: rect.height + chromeGap * 2
13513
- },
13514
- children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
13515
- /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
13516
- "button",
13517
- {
13518
- type: "button",
13519
- "data-ohw-footer-add-button": "",
13520
- disabled: addDisabled,
13521
- className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80 disabled:pointer-events-none disabled:opacity-40",
13522
- style: { top: chromeGap - buttonMargin },
13523
- "aria-label": "Add item",
13524
- onMouseDown: (e) => {
13525
- e.preventDefault();
13526
- e.stopPropagation();
13527
- },
13528
- onClick: (e) => {
13529
- e.preventDefault();
13530
- e.stopPropagation();
13531
- if (addDisabled) return;
13532
- onAdd();
13533
- },
13534
- children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13535
- }
13536
- ) }),
13537
- /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13538
- ] })
13539
- }
13540
- ) });
13541
- }
13542
-
13543
- // src/lib/carousel.ts
13544
- import { useEffect as useEffect12, useState as useState11 } from "react";
13545
- var CAROUSEL_ATTR = "data-ohw-carousel";
13546
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13547
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13548
- var CAROUSEL_EVENT = "ohw:carousel-change";
13549
- function listCarouselKeys() {
13550
- const keys = /* @__PURE__ */ new Set();
13551
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13552
- const key = el.getAttribute("data-ohw-key");
13553
- if (key) keys.add(key);
13554
- });
13555
- return [...keys];
13556
- }
13557
- function containersForKey(key) {
13558
- return Array.from(
13559
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13560
- );
13561
- }
13562
- function isCarouselKey(key) {
13563
- return containersForKey(key).length > 0;
13564
- }
13565
- function parseSlides(raw) {
13566
- if (!raw) return [];
13567
- try {
13568
- const parsed = JSON.parse(raw);
13569
- if (!Array.isArray(parsed)) return [];
13570
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13571
- } catch {
13572
- return [];
13573
- }
13574
- }
13575
- function readCarouselValue(key) {
13576
- const container = containersForKey(key)[0];
13577
- if (!container) return [];
13578
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
13579
- if (fromAttr.length > 0) return fromAttr;
13580
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
13581
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
13582
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
13583
- });
13584
- }
13585
- function slideIndex(el) {
13586
- const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
13587
- const n = raw ? parseInt(raw, 10) : NaN;
13588
- return Number.isFinite(n) ? n : 0;
13589
- }
13590
- function applyCarouselValue(key, slides) {
13591
- const value = JSON.stringify(slides);
13592
- for (const container of containersForKey(key)) {
13593
- if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
13594
- container.setAttribute(CAROUSEL_VALUE_ATTR, value);
13595
- container.dispatchEvent(
13596
- new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
13597
- );
13598
- }
13599
- }
13600
- function applyCarouselNode(key, val) {
13601
- if (!isCarouselKey(key)) return false;
13602
- applyCarouselValue(key, parseSlides(val));
13603
- return true;
12770
+ function applyCarouselNode(key, val) {
12771
+ if (!isCarouselKey(key)) return false;
12772
+ applyCarouselValue(key, parseSlides(val));
12773
+ return true;
13604
12774
  }
13605
12775
  function useOhwCarousel(key, initial) {
13606
- const [images, setImages] = useState11(initial);
13607
- useEffect12(() => {
12776
+ const [images, setImages] = useState10(initial);
12777
+ useEffect11(() => {
13608
12778
  const el = document.querySelector(
13609
12779
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13610
12780
  );
@@ -13682,7 +12852,7 @@ function collectEditableNodes(extraContent, root = document) {
13682
12852
  nodes.push({ key, type: "link", text: href });
13683
12853
  }
13684
12854
  if (extraContent) {
13685
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12855
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13686
12856
  const text = extraContent[key];
13687
12857
  if (typeof text === "string" && text.length > 0) {
13688
12858
  nodes.push({ key, type: "meta", text });
@@ -13719,18 +12889,6 @@ function collectEditableNodes(extraContent, root = document) {
13719
12889
  }
13720
12890
  if (extraContent && !isScoped) {
13721
12891
  applyNavFooterDeleteOverrides(byKey, extraContent);
13722
- for (const key of LOGO_IMAGE_KEYS) {
13723
- if (!(key in extraContent)) continue;
13724
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13725
- }
13726
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13727
- if (!(key in extraContent)) continue;
13728
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13729
- }
13730
- for (const key of LOGO_SIZE_KEYS) {
13731
- if (!(key in extraContent)) continue;
13732
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13733
- }
13734
12892
  }
13735
12893
  return Array.from(byKey.values());
13736
12894
  }
@@ -14199,10 +13357,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14199
13357
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14200
13358
  };
14201
13359
  }
14202
- function resolveEntryAnchor(entry) {
14203
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14204
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14205
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13360
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13361
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13362
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13363
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13364
+ return { effectiveInsertAfter, insertBefore };
13365
+ }
13366
+ function getSchedulingMountPoint(insertAfter) {
13367
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13368
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13369
+ if (!anchorEl && anchor === "scheduling") {
13370
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13371
+ anchorEl = widgets.at(-1) ?? null;
13372
+ }
13373
+ if (!anchorEl) return null;
13374
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14206
13375
  }
14207
13376
  function schedulingMountDepth(insertAfter) {
14208
13377
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14219,7 +13388,8 @@ function getPageSchedulingEntries(raw) {
14219
13388
  }
14220
13389
  }
14221
13390
  function isSchedulingWidgetMissing(entry) {
14222
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13391
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13392
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14223
13393
  }
14224
13394
  function hasMissingSchedulingWidgets(entries) {
14225
13395
  return entries.some(isSchedulingWidgetMissing);
@@ -14249,17 +13419,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14249
13419
  } catch {
14250
13420
  }
14251
13421
  }
14252
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14253
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14254
- const sectionId = schedulingSectionId(widgetId);
13422
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13423
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13424
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14255
13425
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14256
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14257
- if (!anchorEl) return false;
14258
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13426
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13427
+ if (!mountPoint) return false;
14259
13428
  const container = document.createElement("div");
14260
13429
  container.dataset.ohwSectionContainer = "scheduling";
14261
- if (beforeId) {
14262
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13430
+ if (insertBefore) {
13431
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14263
13432
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14264
13433
  if (!beforePoint) return false;
14265
13434
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14270,25 +13439,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14270
13439
  }
14271
13440
  tail.insertAdjacentElement("afterend", container);
14272
13441
  }
14273
- try {
14274
- const root = createRoot2(container);
14275
- flushSync2(() => {
14276
- root.render(
14277
- /* @__PURE__ */ jsx33(
14278
- SchedulingWidget,
14279
- {
14280
- notifyOnConnect,
14281
- initialScheduleId: scheduleId,
14282
- insertAfter: widgetId
14283
- }
14284
- )
14285
- );
14286
- });
14287
- } catch (err) {
14288
- console.error("[ow:scheduling] render threw", err);
14289
- container.remove();
14290
- return false;
14291
- }
13442
+ const root = createRoot2(container);
13443
+ flushSync2(() => {
13444
+ root.render(
13445
+ /* @__PURE__ */ jsx33(
13446
+ SchedulingWidget,
13447
+ {
13448
+ notifyOnConnect,
13449
+ initialScheduleId: scheduleId,
13450
+ insertAfter: effectiveInsertAfter
13451
+ }
13452
+ )
13453
+ );
13454
+ });
14292
13455
  const tracker = getSectionsTracker();
14293
13456
  let sections = [];
14294
13457
  try {
@@ -14296,12 +13459,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14296
13459
  } catch {
14297
13460
  }
14298
13461
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14299
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13462
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14300
13463
  sections.push({
14301
13464
  type: "scheduling",
14302
- insertAfter: widgetId,
14303
- anchorId,
14304
- beforeId: beforeId ?? null,
13465
+ insertAfter: effectiveInsertAfter,
14305
13466
  pagePath: window.location.pathname,
14306
13467
  ...scheduleId ? { scheduleId } : {}
14307
13468
  });
@@ -14315,8 +13476,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14315
13476
  for (let i = pending.length - 1; i >= 0; i--) {
14316
13477
  const entry = pending[i];
14317
13478
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14318
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14319
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13479
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14320
13480
  pending.splice(i, 1);
14321
13481
  }
14322
13482
  }
@@ -14464,13 +13624,6 @@ function isInsideLinkEditor(target) {
14464
13624
  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"]')
14465
13625
  );
14466
13626
  }
14467
- function isInsideFloatingPanel(target) {
14468
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14469
- }
14470
- function isPointOverFloatingPanel(clientX, clientY) {
14471
- const el = document.elementFromPoint(clientX, clientY);
14472
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14473
- }
14474
13627
  function getHrefKeyFromElement(el) {
14475
13628
  if (!el) return null;
14476
13629
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14621,6 +13774,13 @@ function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
14621
13774
  if (isPointOverNavItem(column, clientX, clientY)) return null;
14622
13775
  return column;
14623
13776
  }
13777
+ function isPointOverLogo(x, y) {
13778
+ for (const root of document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')) {
13779
+ const r2 = root.getBoundingClientRect();
13780
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
13781
+ }
13782
+ return false;
13783
+ }
14624
13784
  function isPointOverNavigation(x, y) {
14625
13785
  const roots = /* @__PURE__ */ new Set();
14626
13786
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
@@ -14709,7 +13869,7 @@ function getNavigationSelectionParent(el) {
14709
13869
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14710
13870
  return getFooterLinksContainer();
14711
13871
  }
14712
- 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)) {
13872
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14713
13873
  return getNavigationRoot(el);
14714
13874
  }
14715
13875
  return null;
@@ -15302,45 +14462,6 @@ function StateToggle({
15302
14462
  );
15303
14463
  }
15304
14464
  var contentCache = /* @__PURE__ */ new Map();
15305
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15306
- var OHW_LOADER_STYLE = {
15307
- position: "fixed",
15308
- inset: 0,
15309
- background: "#fff",
15310
- zIndex: 2147483646,
15311
- display: "flex",
15312
- alignItems: "center",
15313
- justifyContent: "center"
15314
- };
15315
- function OhwLoaderSpinner() {
15316
- return /* @__PURE__ */ jsxs20("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15317
- /* @__PURE__ */ jsx33("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15318
- /* @__PURE__ */ jsx33(
15319
- "circle",
15320
- {
15321
- cx: "14",
15322
- cy: "14",
15323
- r: "11",
15324
- stroke: "#1C1917",
15325
- strokeWidth: "3",
15326
- strokeDasharray: "17 52",
15327
- strokeLinecap: "round",
15328
- children: /* @__PURE__ */ jsx33(
15329
- "animateTransform",
15330
- {
15331
- attributeName: "transform",
15332
- type: "rotate",
15333
- from: "0 14 14",
15334
- to: "360 14 14",
15335
- dur: "0.7s",
15336
- repeatCount: "indefinite"
15337
- }
15338
- )
15339
- }
15340
- )
15341
- ] });
15342
- }
15343
- 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){}})();`;
15344
14465
  function resolveSubdomain(subdomainFromQuery) {
15345
14466
  if (subdomainFromQuery) return subdomainFromQuery;
15346
14467
  if (typeof window !== "undefined") {
@@ -15363,8 +14484,8 @@ function OhhwellsBridge() {
15363
14484
  const router = useRouter3();
15364
14485
  const searchParams = useSearchParams();
15365
14486
  const isEditMode = isEditSessionActive();
15366
- const [bridgeRoot, setBridgeRoot] = useState12(null);
15367
- useEffect13(() => {
14487
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
14488
+ useEffect12(() => {
15368
14489
  const figtreeFontId = "ohw-figtree-font";
15369
14490
  if (!document.getElementById(figtreeFontId)) {
15370
14491
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15393,146 +14514,82 @@ function OhhwellsBridge() {
15393
14514
  const subdomain = resolveSubdomain(subdomainFromQuery);
15394
14515
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15395
14516
  useSavedLinkNavigation(isEditMode);
15396
- const postToParent2 = useCallback8((data) => {
14517
+ const postToParent2 = useCallback7((data) => {
15397
14518
  if (typeof window !== "undefined" && window.parent !== window) {
15398
14519
  window.parent.postMessage(data, "*");
15399
14520
  }
15400
14521
  }, []);
15401
- const [fetchState, setFetchState] = useState12("idle");
15402
- const autoSaveTimers = useRef10(/* @__PURE__ */ new Map());
15403
- const activeElRef = useRef10(null);
15404
- const pointerHeldRef = useRef10(false);
15405
- const selectedElRef = useRef10(null);
15406
- const selectedHrefKeyRef = useRef10(null);
15407
- const selectedFooterColAttrRef = useRef10(null);
15408
- const originalContentRef = useRef10(null);
15409
- const activeStateElRef = useRef10(null);
15410
- const parentScrollRef = useRef10(null);
15411
- const visibleViewportRef = useRef10(null);
15412
- const [dialogPortalContainer, setDialogPortalContainer] = useState12(null);
15413
- const attachVisibleViewport = useCallback8((node) => {
14522
+ const [fetchState, setFetchState] = useState11("idle");
14523
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
14524
+ const activeElRef = useRef9(null);
14525
+ const pointerHeldRef = useRef9(false);
14526
+ const selectedElRef = useRef9(null);
14527
+ const selectedHrefKeyRef = useRef9(null);
14528
+ const selectedFooterColAttrRef = useRef9(null);
14529
+ const originalContentRef = useRef9(null);
14530
+ const activeStateElRef = useRef9(null);
14531
+ const parentScrollRef = useRef9(null);
14532
+ const visibleViewportRef = useRef9(null);
14533
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
14534
+ const attachVisibleViewport = useCallback7((node) => {
15414
14535
  visibleViewportRef.current = node;
15415
14536
  setDialogPortalContainer(node);
15416
14537
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15417
14538
  }, []);
15418
- const toolbarElRef = useRef10(null);
15419
- const glowElRef = useRef10(null);
15420
- const hoveredImageRef = useRef10(null);
15421
- const hoveredImageHasTextOverlapRef = useRef10(false);
15422
- const dragOverElRef = useRef10(null);
15423
- const [mediaHover, setMediaHover] = useState12(null);
15424
- const [selectedMedia, setSelectedMedia] = useState12(null);
15425
- const selectedMediaElRef = useRef10(null);
15426
- const clearMediaSelection = useCallback8(() => {
15427
- const prev = selectedMediaElRef.current;
15428
- selectedMediaElRef.current = null;
15429
- setSelectedMedia(null);
15430
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15431
- if (sectionEl) {
15432
- postToParentRef.current({
15433
- type: "ow:section-selected",
15434
- sectionId: sectionEl.dataset.ohwSection ?? null,
15435
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15436
- key: null
15437
- });
15438
- }
15439
- }, []);
15440
- const clearMediaSelectionRef = useRef10(clearMediaSelection);
15441
- clearMediaSelectionRef.current = clearMediaSelection;
15442
- const selectMediaElement = useCallback8((el) => {
15443
- const r2 = el.getBoundingClientRect();
15444
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15445
- selectedMediaElRef.current = el;
15446
- setSelectedMedia({
15447
- key: el.dataset.ohwKey ?? "",
15448
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15449
- elementType: el.dataset.ohwEditable ?? "image",
15450
- hasTextOverlap: false,
15451
- isDragOver: false,
15452
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15453
- });
15454
- const sectionEl = el.closest("[data-ohw-section]");
15455
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15456
- postToParentRef.current({
15457
- type: "ow:section-selected",
15458
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15459
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15460
- key: el.dataset.ohwKey ?? null,
15461
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15462
- // bridge knows what the node IS, so it names it.
15463
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : "Image"
15464
- });
15465
- }, []);
15466
- const selectMediaElementRef = useRef10(selectMediaElement);
15467
- selectMediaElementRef.current = selectMediaElement;
15468
- useEffect13(() => {
15469
- if (!selectedMedia) return;
15470
- const update = () => {
15471
- const el = selectedMediaElRef.current;
15472
- if (!el || !el.isConnected) {
15473
- clearMediaSelection();
15474
- return;
15475
- }
15476
- const r2 = el.getBoundingClientRect();
15477
- setSelectedMedia(
15478
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15479
- );
15480
- };
15481
- window.addEventListener("scroll", update, true);
15482
- window.addEventListener("resize", update);
15483
- return () => {
15484
- window.removeEventListener("scroll", update, true);
15485
- window.removeEventListener("resize", update);
15486
- };
15487
- }, [selectedMedia !== null]);
15488
- const [carouselHover, setCarouselHover] = useState12(null);
15489
- const [uploadingRects, setUploadingRects] = useState12({});
15490
- const hoveredGapRef = useRef10(null);
15491
- const imageUnhoverTimerRef = useRef10(null);
15492
- const imageShowTimerRef = useRef10(null);
15493
- const editStylesRef = useRef10(null);
15494
- const activateRef = useRef10(() => {
14539
+ const toolbarElRef = useRef9(null);
14540
+ const glowElRef = useRef9(null);
14541
+ const hoveredImageRef = useRef9(null);
14542
+ const hoveredImageHasTextOverlapRef = useRef9(false);
14543
+ const dragOverElRef = useRef9(null);
14544
+ const [mediaHover, setMediaHover] = useState11(null);
14545
+ const [carouselHover, setCarouselHover] = useState11(null);
14546
+ const [uploadingRects, setUploadingRects] = useState11({});
14547
+ const hoveredGapRef = useRef9(null);
14548
+ const imageUnhoverTimerRef = useRef9(null);
14549
+ const imageShowTimerRef = useRef9(null);
14550
+ const editStylesRef = useRef9(null);
14551
+ const activateRef = useRef9(() => {
15495
14552
  });
15496
- const deactivateRef = useRef10(() => {
14553
+ const deactivateRef = useRef9(() => {
15497
14554
  });
15498
- const selectRef = useRef10(() => {
14555
+ const selectRef = useRef9(() => {
15499
14556
  });
15500
- const selectFrameRef = useRef10(() => {
14557
+ const selectFrameRef = useRef9(() => {
15501
14558
  });
15502
- const selectLogoRef = useRef10(() => {
14559
+ const selectLogoRef = useRef9(() => {
15503
14560
  });
15504
- const openLogoSizePanelRef = useRef10(() => {
14561
+ const openLogoSizePanelRef = useRef9(() => {
15505
14562
  });
15506
- const deselectRef = useRef10(() => {
14563
+ const deselectRef = useRef9(() => {
15507
14564
  });
15508
- const closeFloatingPanelOnlyRef = useRef10(() => {
14565
+ const closeFloatingPanelOnlyRef = useRef9(() => {
15509
14566
  });
15510
- const reselectNavigationItemRef = useRef10(() => {
14567
+ const reselectNavigationItemRef = useRef9(() => {
15511
14568
  });
15512
- const commitNavigationTextEditRef = useRef10(() => {
14569
+ const commitNavigationTextEditRef = useRef9(() => {
15513
14570
  });
15514
- const handleDeleteSelectedRef = useRef10(() => false);
15515
- const runPendingDeleteUndoRef = useRef10(() => false);
15516
- const isFooterFrameSelectionRef = useRef10(false);
15517
- const refreshActiveCommandsRef = useRef10(() => {
14571
+ const handleDeleteSelectedRef = useRef9(() => false);
14572
+ const runPendingDeleteUndoRef = useRef9(() => false);
14573
+ const isFooterFrameSelectionRef = useRef9(false);
14574
+ const refreshActiveCommandsRef = useRef9(() => {
15518
14575
  });
15519
- const postToParentRef = useRef10(postToParent2);
14576
+ const postToParentRef = useRef9(postToParent2);
15520
14577
  postToParentRef.current = postToParent2;
15521
- const aiSectionApiRef = useRef10(null);
15522
- const sectionsLoadedRef = useRef10(false);
15523
- const pendingScheduleConfigRequests = useRef10([]);
15524
- const [toolbarRect, setToolbarRect] = useState12(null);
15525
- const [formPickRect, setFormPickRect] = useState12(null);
15526
- const formPickElRef = useRef10(null);
15527
- const [formViewState, setFormViewStateUi] = useState12("default");
15528
- const [formPickCount, setFormPickCount] = useState12(null);
15529
- const [formHoverRect, setFormHoverRect] = useState12(null);
15530
- const formHoverElRef = useRef10(null);
15531
- const [fieldPickRect, setFieldPickRect] = useState12(null);
15532
- const fieldPickElRef = useRef10(null);
15533
- const [fieldPickState, setFieldPickState] = useState12(null);
15534
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState12(false);
15535
- const clearFormPick = useCallback8(() => {
14578
+ const aiSectionApiRef = useRef9(null);
14579
+ const sectionsLoadedRef = useRef9(false);
14580
+ const pendingScheduleConfigRequests = useRef9([]);
14581
+ const [toolbarRect, setToolbarRect] = useState11(null);
14582
+ const [formPickRect, setFormPickRect] = useState11(null);
14583
+ const formPickElRef = useRef9(null);
14584
+ const [formViewState, setFormViewStateUi] = useState11("default");
14585
+ const [formPickCount, setFormPickCount] = useState11(null);
14586
+ const [formHoverRect, setFormHoverRect] = useState11(null);
14587
+ const formHoverElRef = useRef9(null);
14588
+ const [fieldPickRect, setFieldPickRect] = useState11(null);
14589
+ const fieldPickElRef = useRef9(null);
14590
+ const [fieldPickState, setFieldPickState] = useState11(null);
14591
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState11(false);
14592
+ const clearFormPick = useCallback7(() => {
15536
14593
  const form = formPickElRef.current;
15537
14594
  const editing = fieldPickElRef.current;
15538
14595
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15552,7 +14609,7 @@ function OhhwellsBridge() {
15552
14609
  formPickElRef.current = null;
15553
14610
  setFormPickRect(null);
15554
14611
  }, []);
15555
- const clearFieldPick = useCallback8(() => {
14612
+ const clearFieldPick = useCallback7(() => {
15556
14613
  const wrapper = fieldPickElRef.current;
15557
14614
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15558
14615
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15562,9 +14619,9 @@ function OhhwellsBridge() {
15562
14619
  setFieldPickRect(null);
15563
14620
  setFieldPickState(null);
15564
14621
  }, []);
15565
- const persistFieldsRef = useRef10(() => {
14622
+ const persistFieldsRef = useRef9(() => {
15566
14623
  });
15567
- const persistFields = useCallback8(
14624
+ const persistFields = useCallback7(
15568
14625
  (form) => {
15569
14626
  const key = formKeyOf(form);
15570
14627
  if (!key) return;
@@ -15575,7 +14632,7 @@ function OhhwellsBridge() {
15575
14632
  []
15576
14633
  );
15577
14634
  persistFieldsRef.current = persistFields;
15578
- const selectField = useCallback8((wrapper) => {
14635
+ const selectField = useCallback7((wrapper) => {
15579
14636
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15580
14637
  commitPlaceholderEdit(fieldPickElRef.current);
15581
14638
  }
@@ -15588,7 +14645,7 @@ function OhhwellsBridge() {
15588
14645
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15589
14646
  setFieldTypePickerOpen(false);
15590
14647
  }, []);
15591
- const withSelectedField = useCallback8(
14648
+ const withSelectedField = useCallback7(
15592
14649
  (run) => {
15593
14650
  const wrapper = fieldPickElRef.current;
15594
14651
  const form = formPickElRef.current;
@@ -15601,28 +14658,28 @@ function OhhwellsBridge() {
15601
14658
  },
15602
14659
  [persistFields]
15603
14660
  );
15604
- const handleFieldTypeChange = useCallback8(
14661
+ const handleFieldTypeChange = useCallback7(
15605
14662
  (type) => withSelectedField((_form, wrapper) => {
15606
14663
  applyFieldType(wrapper, type);
15607
14664
  selectField(wrapper);
15608
14665
  }),
15609
14666
  [selectField, withSelectedField]
15610
14667
  );
15611
- const handleFieldRequiredToggle = useCallback8(
14668
+ const handleFieldRequiredToggle = useCallback7(
15612
14669
  () => withSelectedField((_form, wrapper) => {
15613
14670
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15614
14671
  selectField(wrapper);
15615
14672
  }),
15616
14673
  [selectField, withSelectedField]
15617
14674
  );
15618
- const handleFieldDuplicate = useCallback8(
14675
+ const handleFieldDuplicate = useCallback7(
15619
14676
  () => withSelectedField((form, wrapper) => {
15620
14677
  const copy = duplicateField(form, wrapper);
15621
14678
  selectField(copy);
15622
14679
  }),
15623
14680
  [selectField, withSelectedField]
15624
14681
  );
15625
- const handleFieldDelete = useCallback8(
14682
+ const handleFieldDelete = useCallback7(
15626
14683
  () => withSelectedField((_form, wrapper) => {
15627
14684
  removeField(wrapper);
15628
14685
  clearFieldPick();
@@ -15630,7 +14687,7 @@ function OhhwellsBridge() {
15630
14687
  }),
15631
14688
  [clearFieldPick, withSelectedField]
15632
14689
  );
15633
- const handleAddField = useCallback8(
14690
+ const handleAddField = useCallback7(
15634
14691
  (type) => {
15635
14692
  const form = formPickElRef.current;
15636
14693
  if (!form) return;
@@ -15646,8 +14703,8 @@ function OhhwellsBridge() {
15646
14703
  },
15647
14704
  [persistFields, selectField]
15648
14705
  );
15649
- const fieldDragRef = useRef10(null);
15650
- const buildFieldDropSlots = useCallback8((form, draggedKey) => {
14706
+ const fieldDragRef = useRef9(null);
14707
+ const buildFieldDropSlots = useCallback7((form, draggedKey) => {
15651
14708
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15652
14709
  const slots = others.map((el) => {
15653
14710
  const rect = el.getBoundingClientRect();
@@ -15660,7 +14717,7 @@ function OhhwellsBridge() {
15660
14717
  }
15661
14718
  return slots;
15662
14719
  }, []);
15663
- const handleFieldDragStart = useCallback8(() => {
14720
+ const handleFieldDragStart = useCallback7(() => {
15664
14721
  const wrapper = fieldPickElRef.current;
15665
14722
  const form = formPickElRef.current;
15666
14723
  if (!wrapper || !form) return;
@@ -15669,18 +14726,18 @@ function OhhwellsBridge() {
15669
14726
  setFieldDragging(true);
15670
14727
  setFieldDropSlots(buildFieldDropSlots(form, key));
15671
14728
  }, [buildFieldDropSlots]);
15672
- const handleFieldDragEnd = useCallback8(() => {
14729
+ const handleFieldDragEnd = useCallback7(() => {
15673
14730
  fieldDragRef.current = null;
15674
14731
  setFieldDropIndex(null);
15675
14732
  setFieldDropSlots([]);
15676
14733
  setFieldDragging(false);
15677
14734
  }, []);
15678
- const [fieldDropIndex, setFieldDropIndex] = useState12(null);
15679
- const [fieldDropSlots, setFieldDropSlots] = useState12([]);
15680
- const [fieldDragging, setFieldDragging] = useState12(false);
15681
- const clearFormPickRef = useRef10(clearFormPick);
14735
+ const [fieldDropIndex, setFieldDropIndex] = useState11(null);
14736
+ const [fieldDropSlots, setFieldDropSlots] = useState11([]);
14737
+ const [fieldDragging, setFieldDragging] = useState11(false);
14738
+ const clearFormPickRef = useRef9(clearFormPick);
15682
14739
  clearFormPickRef.current = clearFormPick;
15683
- useEffect13(() => {
14740
+ useEffect12(() => {
15684
14741
  const el = fieldPickElRef.current;
15685
14742
  if (!el || fieldPickRect === null) return;
15686
14743
  const observer = new ResizeObserver(() => {
@@ -15689,7 +14746,7 @@ function OhhwellsBridge() {
15689
14746
  observer.observe(el);
15690
14747
  return () => observer.disconnect();
15691
14748
  }, [fieldPickRect !== null, fieldPickState]);
15692
- useEffect13(() => {
14749
+ useEffect12(() => {
15693
14750
  const el = formPickElRef.current;
15694
14751
  if (!el || formPickRect === null) return;
15695
14752
  const observer = new ResizeObserver(() => {
@@ -15698,25 +14755,25 @@ function OhhwellsBridge() {
15698
14755
  observer.observe(el);
15699
14756
  return () => observer.disconnect();
15700
14757
  }, [formPickRect !== null, formViewState]);
15701
- const [toolbarVariant, setToolbarVariant] = useState12("none");
15702
- const toolbarVariantRef = useRef10("none");
14758
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
14759
+ const toolbarVariantRef = useRef9("none");
15703
14760
  toolbarVariantRef.current = toolbarVariant;
15704
- const [selectedIsCta, setSelectedIsCta] = useState12(false);
15705
- const [selectedIsSocial, setSelectedIsSocial] = useState12(false);
15706
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState12(false);
15707
- const [reorderHrefKey, setReorderHrefKey] = useState12(null);
15708
- const [reorderDragDisabled, setReorderDragDisabled] = useState12(false);
15709
- const [toggleState, setToggleState] = useState12(null);
15710
- const [maxBadge, setMaxBadge] = useState12(null);
15711
- const [activeCommands, setActiveCommands] = useState12(/* @__PURE__ */ new Set());
15712
- const [sectionGap, setSectionGap] = useState12(null);
15713
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState12(false);
15714
- const hoveredNavContainerRef = useRef10(null);
15715
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState12(null);
15716
- const hoveredItemElRef = useRef10(null);
15717
- const [hoveredItemRect, setHoveredItemRect] = useState12(null);
15718
- const [hoveredTextRect, setHoveredTextRect] = useState12(null);
15719
- useEffect13(() => {
14761
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
14762
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
14763
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
14764
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
14765
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
14766
+ const [toggleState, setToggleState] = useState11(null);
14767
+ const [maxBadge, setMaxBadge] = useState11(null);
14768
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
14769
+ const [sectionGap, setSectionGap] = useState11(null);
14770
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
14771
+ const hoveredNavContainerRef = useRef9(null);
14772
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
14773
+ const hoveredItemElRef = useRef9(null);
14774
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
14775
+ const [hoveredTextRect, setHoveredTextRect] = useState11(null);
14776
+ useEffect12(() => {
15720
14777
  const sync = () => {
15721
14778
  const el = document.querySelector(
15722
14779
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15737,56 +14794,43 @@ function OhhwellsBridge() {
15737
14794
  });
15738
14795
  return () => observer.disconnect();
15739
14796
  }, []);
15740
- const siblingHintElRef = useRef10(null);
15741
- const [siblingHintRect, setSiblingHintRect] = useState12(null);
15742
- const [siblingHintRects, setSiblingHintRects] = useState12([]);
15743
- const [isItemDragging, setIsItemDragging] = useState12(false);
15744
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState12(false);
14797
+ const siblingHintElRef = useRef9(null);
14798
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
14799
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
14800
+ const [isItemDragging, setIsItemDragging] = useState11(false);
14801
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
15745
14802
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15746
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState12(null);
15747
- const [footerHeadingVisible, setFooterHeadingVisible] = useState12(null);
15748
- const footerDragRef = useRef10(null);
15749
- const [footerDropSlots, setFooterDropSlots] = useState12([]);
15750
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState12(null);
15751
- const [draggedItemRect, setDraggedItemRect] = useState12(null);
15752
- const footerPointerDragRef = useRef10(null);
15753
- const suppressNextClickRef = useRef10(false);
15754
- const suppressClickUntilRef = useRef10(0);
15755
- const [linkPopover, setLinkPopover] = useState12(null);
15756
- const linkPopoverSessionRef = useRef10(null);
15757
- const addNavAfterAnchorRef = useRef10(null);
15758
- const editContentRef = useRef10({});
15759
- const aiSectionsRef = useRef10("");
15760
- const brandKitRef = useRef10("");
15761
- const stylesRef = useRef10("");
15762
- const pendingDeleteUndoRef = useRef10(null);
15763
- const [floatingPanel, setFloatingPanel] = useState12(null);
15764
- const floatingPanelOpenRef = useRef10(false);
15765
- const setFloatingPanelRef = useRef10(setFloatingPanel);
15766
- const [floatingPanelPos, setFloatingPanelPos] = useState12(null);
15767
- const [logoSizeDraft, setLogoSizeDraft] = useState12(null);
15768
- const [editorViewport, setEditorViewport] = useState12("desktop");
15769
- const [parentScrollSnap, setParentScrollSnap] = useState12(null);
15770
- const [sitePages, setSitePages] = useState12([]);
15771
- const [sectionsByPath, setSectionsByPath] = useState12({});
15772
- const sectionsPrefetchGenRef = useRef10(0);
15773
- const setLinkPopoverRef = useRef10(setLinkPopover);
15774
- const linkPopoverPanelRef = useRef10(null);
15775
- const linkPopoverOpenRef = useRef10(false);
15776
- const linkPopoverGraceUntilRef = useRef10(0);
14803
+ const [floatingPanel, setFloatingPanel] = useState11(null);
14804
+ const floatingPanelOpenRef = useRef9(false);
14805
+ floatingPanelOpenRef.current = floatingPanel !== null;
14806
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
14807
+ const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
14808
+ const [editorViewport, setEditorViewport] = useState11("desktop");
14809
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
14810
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
14811
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
14812
+ const footerDragRef = useRef9(null);
14813
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
14814
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
14815
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
14816
+ const footerPointerDragRef = useRef9(null);
14817
+ const suppressNextClickRef = useRef9(false);
14818
+ const suppressClickUntilRef = useRef9(0);
14819
+ const [linkPopover, setLinkPopover] = useState11(null);
14820
+ const linkPopoverSessionRef = useRef9(null);
14821
+ const addNavAfterAnchorRef = useRef9(null);
14822
+ const editContentRef = useRef9({});
14823
+ const aiSectionsRef = useRef9("");
14824
+ const pendingDeleteUndoRef = useRef9(null);
14825
+ const [sitePages, setSitePages] = useState11([]);
14826
+ const [sectionsByPath, setSectionsByPath] = useState11({});
14827
+ const sectionsPrefetchGenRef = useRef9(0);
14828
+ const setLinkPopoverRef = useRef9(setLinkPopover);
14829
+ const linkPopoverPanelRef = useRef9(null);
14830
+ const linkPopoverOpenRef = useRef9(false);
14831
+ const linkPopoverGraceUntilRef = useRef9(0);
15777
14832
  setLinkPopoverRef.current = setLinkPopover;
15778
- setFloatingPanelRef.current = setFloatingPanel;
15779
14833
  linkPopoverSessionRef.current = linkPopover;
15780
- floatingPanelOpenRef.current = Boolean(floatingPanel);
15781
- useEffect13(() => {
15782
- const syncViewport = () => {
15783
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
15784
- setEditorViewport((prev) => prev === next ? prev : next);
15785
- };
15786
- syncViewport();
15787
- window.addEventListener("resize", syncViewport);
15788
- return () => window.removeEventListener("resize", syncViewport);
15789
- }, []);
15790
14834
  const {
15791
14835
  navDragRef,
15792
14836
  navDropSlots,
@@ -15819,20 +14863,10 @@ function OhhwellsBridge() {
15819
14863
  getNavigationItemAnchor,
15820
14864
  isDragHandleDisabled
15821
14865
  });
15822
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15823
- isEditMode,
15824
- editContentRef,
15825
- postToParentRef,
15826
- parentScrollRef,
15827
- navDragRef,
15828
- footerDragRef,
15829
- suppressNextClickRef,
15830
- suppressClickUntilRef
15831
- });
15832
14866
  const bumpLinkPopoverGrace = () => {
15833
14867
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15834
14868
  };
15835
- const runSectionsPrefetch = useCallback8((pages) => {
14869
+ const runSectionsPrefetch = useCallback7((pages) => {
15836
14870
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15837
14871
  const gen = ++sectionsPrefetchGenRef.current;
15838
14872
  const paths = pages.map((p) => p.path);
@@ -15851,9 +14885,9 @@ function OhhwellsBridge() {
15851
14885
  );
15852
14886
  });
15853
14887
  }, [isEditMode, pathname]);
15854
- const runSectionsPrefetchRef = useRef10(runSectionsPrefetch);
14888
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
15855
14889
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15856
- useEffect13(() => {
14890
+ useEffect12(() => {
15857
14891
  if (!linkPopover) {
15858
14892
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15859
14893
  return;
@@ -15881,7 +14915,7 @@ function OhhwellsBridge() {
15881
14915
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15882
14916
  };
15883
14917
  }, [linkPopover, postToParent2]);
15884
- useEffect13(() => {
14918
+ useEffect12(() => {
15885
14919
  if (!isEditMode) return;
15886
14920
  const useFixtures = shouldUseDevFixtures();
15887
14921
  if (useFixtures) {
@@ -15905,14 +14939,14 @@ function OhhwellsBridge() {
15905
14939
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
15906
14940
  return () => window.removeEventListener("message", onSitePages);
15907
14941
  }, [isEditMode, postToParent2]);
15908
- useEffect13(() => {
14942
+ useEffect12(() => {
15909
14943
  if (!isEditMode || shouldUseDevFixtures()) return;
15910
14944
  void loadAllSectionsManifest().then((manifest) => {
15911
14945
  if (Object.keys(manifest).length === 0) return;
15912
14946
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
15913
14947
  });
15914
14948
  }, [isEditMode]);
15915
- useEffect13(() => {
14949
+ useEffect12(() => {
15916
14950
  const update = () => {
15917
14951
  const el = activeElRef.current ?? selectedElRef.current;
15918
14952
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -15936,10 +14970,10 @@ function OhhwellsBridge() {
15936
14970
  vvp.removeEventListener("resize", update);
15937
14971
  };
15938
14972
  }, []);
15939
- const refreshStateRules = useCallback8(() => {
14973
+ const refreshStateRules = useCallback7(() => {
15940
14974
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
15941
14975
  }, []);
15942
- const processConfigRequest = useCallback8((insertAfterVal) => {
14976
+ const processConfigRequest = useCallback7((insertAfterVal) => {
15943
14977
  const tracker = getSectionsTracker();
15944
14978
  let entries = [];
15945
14979
  try {
@@ -15962,7 +14996,7 @@ function OhhwellsBridge() {
15962
14996
  }
15963
14997
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
15964
14998
  }, [isEditMode]);
15965
- const deactivate = useCallback8(() => {
14999
+ const deactivate = useCallback7(() => {
15966
15000
  const el = activeElRef.current;
15967
15001
  if (!el) return;
15968
15002
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16003,12 +15037,12 @@ function OhhwellsBridge() {
16003
15037
  setToolbarShowEditLink(false);
16004
15038
  postToParent2({ type: "ow:exit-edit" });
16005
15039
  }, [postToParent2]);
16006
- const clearSelectedAttr = useCallback8(() => {
15040
+ const clearSelectedAttr = useCallback7(() => {
16007
15041
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16008
15042
  el.removeAttribute("data-ohw-selected");
16009
15043
  });
16010
15044
  }, []);
16011
- const deselect = useCallback8(() => {
15045
+ const deselect = useCallback7(() => {
16012
15046
  clearSelectedAttr();
16013
15047
  selectedElRef.current = null;
16014
15048
  selectedHrefKeyRef.current = null;
@@ -16037,11 +15071,11 @@ function OhhwellsBridge() {
16037
15071
  setToolbarVariant("none");
16038
15072
  }
16039
15073
  }, [clearSelectedAttr]);
16040
- const markSelected = useCallback8((el) => {
15074
+ const markSelected = useCallback7((el) => {
16041
15075
  clearSelectedAttr();
16042
15076
  el.setAttribute("data-ohw-selected", "");
16043
15077
  }, [clearSelectedAttr]);
16044
- const resolveHrefKeyElement = useCallback8((hrefKey) => {
15078
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
16045
15079
  if (isFooterHrefKey(hrefKey)) {
16046
15080
  return document.querySelector(
16047
15081
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16056,7 +15090,7 @@ function OhhwellsBridge() {
16056
15090
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16057
15091
  );
16058
15092
  }, []);
16059
- const resyncSelectedNavigationItem = useCallback8(() => {
15093
+ const resyncSelectedNavigationItem = useCallback7(() => {
16060
15094
  const hrefKey = selectedHrefKeyRef.current;
16061
15095
  if (hrefKey) {
16062
15096
  const link = resolveHrefKeyElement(hrefKey);
@@ -16094,7 +15128,7 @@ function OhhwellsBridge() {
16094
15128
  );
16095
15129
  }
16096
15130
  }, [resolveHrefKeyElement]);
16097
- const reselectNavigationItem = useCallback8((navAnchor) => {
15131
+ const reselectNavigationItem = useCallback7((navAnchor) => {
16098
15132
  selectedElRef.current = navAnchor;
16099
15133
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16100
15134
  selectedFooterColAttrRef.current = null;
@@ -16125,7 +15159,7 @@ function OhhwellsBridge() {
16125
15159
  setToolbarShowEditLink(false);
16126
15160
  setActiveCommands(/* @__PURE__ */ new Set());
16127
15161
  }, [markSelected]);
16128
- const commitNavigationTextEdit = useCallback8((navAnchor) => {
15162
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
16129
15163
  const el = activeElRef.current;
16130
15164
  if (!el) return;
16131
15165
  const key = el.dataset.ohwKey;
@@ -16158,7 +15192,7 @@ function OhhwellsBridge() {
16158
15192
  postToParent2({ type: "ow:exit-edit" });
16159
15193
  reselectNavigationItem(navAnchor);
16160
15194
  }, [postToParent2, reselectNavigationItem]);
16161
- const handleAddTopLevelNavItem = useCallback8(() => {
15195
+ const handleAddTopLevelNavItem = useCallback7(() => {
16162
15196
  const items = listNavbarRootItems();
16163
15197
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16164
15198
  deselectRef.current();
@@ -16170,7 +15204,7 @@ function OhhwellsBridge() {
16170
15204
  intent: "add-nav"
16171
15205
  });
16172
15206
  }, []);
16173
- const maybeWarnNavLinkDropdownConflict = useCallback8(
15207
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
16174
15208
  (anchor) => {
16175
15209
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16176
15210
  if (!navDropdownsOpenOnClick()) return;
@@ -16183,7 +15217,7 @@ function OhhwellsBridge() {
16183
15217
  },
16184
15218
  [postToParent2]
16185
15219
  );
16186
- const handleNavDropdownOpenChange = useCallback8((open) => {
15220
+ const handleNavDropdownOpenChange = useCallback7((open) => {
16187
15221
  const selected = selectedElRef.current;
16188
15222
  if (!selected || !isNavigationItem2(selected)) return;
16189
15223
  setNavGroupForceOpen(selected, open);
@@ -16195,7 +15229,7 @@ function OhhwellsBridge() {
16195
15229
  }
16196
15230
  });
16197
15231
  }, []);
16198
- const handleFooterHeadingVisibleChange = useCallback8(
15232
+ const handleFooterHeadingVisibleChange = useCallback7(
16199
15233
  (visible) => {
16200
15234
  const selected = selectedElRef.current;
16201
15235
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16219,7 +15253,7 @@ function OhhwellsBridge() {
16219
15253
  },
16220
15254
  [postToParent2]
16221
15255
  );
16222
- const enterEditOnNewItem = useCallback8((anchor) => {
15256
+ const enterEditOnNewItem = useCallback7((anchor) => {
16223
15257
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16224
15258
  if (!label) {
16225
15259
  selectRef.current(anchor);
@@ -16228,7 +15262,7 @@ function OhhwellsBridge() {
16228
15262
  setNavGroupForceOpen(anchor, true);
16229
15263
  activateRef.current(label);
16230
15264
  }, []);
16231
- const handleAddChildItem = useCallback8(() => {
15265
+ const handleAddChildItem = useCallback7(() => {
16232
15266
  const selected = selectedElRef.current;
16233
15267
  if (!selected) return;
16234
15268
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16340,7 +15374,7 @@ function OhhwellsBridge() {
16340
15374
  enterEditOnNewItem(result.anchor);
16341
15375
  });
16342
15376
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16343
- const handleAddFooterColumn = useCallback8(() => {
15377
+ const handleAddFooterColumn = useCallback7(() => {
16344
15378
  if (!canAddFooterColumn()) {
16345
15379
  postToParent2({
16346
15380
  type: "ow:toast",
@@ -16361,7 +15395,7 @@ function OhhwellsBridge() {
16361
15395
  selectRef.current(result.firstLink);
16362
15396
  });
16363
15397
  }, [postToParent2]);
16364
- const clearFooterDragVisuals = useCallback8(() => {
15398
+ const clearFooterDragVisuals = useCallback7(() => {
16365
15399
  footerDragRef.current = null;
16366
15400
  setSiblingHintRects([]);
16367
15401
  setFooterDropSlots([]);
@@ -16370,7 +15404,7 @@ function OhhwellsBridge() {
16370
15404
  setIsItemDragging(false);
16371
15405
  unlockFooterDragInteraction();
16372
15406
  }, []);
16373
- const refreshFooterDragVisuals = useCallback8((session, activeSlot, clientX, clientY) => {
15407
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
16374
15408
  const dragged = session.draggedEl;
16375
15409
  setDraggedItemRect(dragged.getBoundingClientRect());
16376
15410
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16402,13 +15436,13 @@ function OhhwellsBridge() {
16402
15436
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16403
15437
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16404
15438
  }, []);
16405
- const refreshFooterDragVisualsRef = useRef10(refreshFooterDragVisuals);
15439
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
16406
15440
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16407
- const commitFooterDragRef = useRef10(() => {
15441
+ const commitFooterDragRef = useRef9(() => {
16408
15442
  });
16409
- const beginFooterDragRef = useRef10(() => {
15443
+ const beginFooterDragRef = useRef9(() => {
16410
15444
  });
16411
- const beginFooterDrag = useCallback8(
15445
+ const beginFooterDrag = useCallback7(
16412
15446
  (session) => {
16413
15447
  const rect = session.draggedEl.getBoundingClientRect();
16414
15448
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16428,7 +15462,7 @@ function OhhwellsBridge() {
16428
15462
  [refreshFooterDragVisuals]
16429
15463
  );
16430
15464
  beginFooterDragRef.current = beginFooterDrag;
16431
- const commitFooterDrag = useCallback8(
15465
+ const commitFooterDrag = useCallback7(
16432
15466
  (clientX, clientY) => {
16433
15467
  const session = footerDragRef.current;
16434
15468
  if (!session) {
@@ -16556,7 +15590,7 @@ function OhhwellsBridge() {
16556
15590
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16557
15591
  );
16558
15592
  commitFooterDragRef.current = commitFooterDrag;
16559
- const startFooterLinkDrag = useCallback8(
15593
+ const startFooterLinkDrag = useCallback7(
16560
15594
  (anchor, clientX, clientY, wasSelected) => {
16561
15595
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16562
15596
  if (!hrefKey) return false;
@@ -16592,7 +15626,7 @@ function OhhwellsBridge() {
16592
15626
  },
16593
15627
  [beginFooterDrag]
16594
15628
  );
16595
- const startFooterColumnDrag = useCallback8(
15629
+ const startFooterColumnDrag = useCallback7(
16596
15630
  (columnEl, clientX, clientY, wasSelected) => {
16597
15631
  const columns = listFooterColumns();
16598
15632
  const idx = columns.indexOf(columnEl);
@@ -16612,7 +15646,7 @@ function OhhwellsBridge() {
16612
15646
  },
16613
15647
  [beginFooterDrag]
16614
15648
  );
16615
- const handleItemDragStart = useCallback8(
15649
+ const handleItemDragStart = useCallback7(
16616
15650
  (e) => {
16617
15651
  const selected = selectedElRef.current;
16618
15652
  if (!selected) {
@@ -16632,7 +15666,7 @@ function OhhwellsBridge() {
16632
15666
  },
16633
15667
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16634
15668
  );
16635
- const handleItemDragEnd = useCallback8(
15669
+ const handleItemDragEnd = useCallback7(
16636
15670
  (e) => {
16637
15671
  if (footerDragRef.current) {
16638
15672
  const x = e?.clientX;
@@ -16658,7 +15692,7 @@ function OhhwellsBridge() {
16658
15692
  },
16659
15693
  [commitFooterDrag, commitNavDrag, navDragRef]
16660
15694
  );
16661
- const handleItemChromePointerDown = useCallback8((e) => {
15695
+ const handleItemChromePointerDown = useCallback7((e) => {
16662
15696
  if (e.button !== 0) return;
16663
15697
  const selected = selectedElRef.current;
16664
15698
  if (!selected) return;
@@ -16689,7 +15723,7 @@ function OhhwellsBridge() {
16689
15723
  }
16690
15724
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16691
15725
  }, [armNavPressFromChrome]);
16692
- const handleItemChromeClick = useCallback8((clientX, clientY) => {
15726
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
16693
15727
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16694
15728
  suppressNextClickRef.current = false;
16695
15729
  return;
@@ -16702,7 +15736,7 @@ function OhhwellsBridge() {
16702
15736
  }, []);
16703
15737
  reselectNavigationItemRef.current = reselectNavigationItem;
16704
15738
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16705
- const select = useCallback8((anchor) => {
15739
+ const select = useCallback7((anchor) => {
16706
15740
  if (!isNavigationItem2(anchor)) return;
16707
15741
  if (activeElRef.current) deactivate();
16708
15742
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16745,7 +15779,7 @@ function OhhwellsBridge() {
16745
15779
  setFloatingPanel(null);
16746
15780
  setLogoSizeDraft(null);
16747
15781
  }, [deactivate, markSelected]);
16748
- const selectFrame = useCallback8((el) => {
15782
+ const selectFrame = useCallback7((el) => {
16749
15783
  if (!isNavigationContainer(el)) return;
16750
15784
  if (activeElRef.current) deactivate();
16751
15785
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16796,7 +15830,7 @@ function OhhwellsBridge() {
16796
15830
  setFloatingPanel(null);
16797
15831
  setLogoSizeDraft(null);
16798
15832
  }, [deactivate, markSelected, postToParent2]);
16799
- const selectLogo = useCallback8(
15833
+ const selectLogo = useCallback7(
16800
15834
  (logoEl) => {
16801
15835
  if (activeElRef.current) deactivate();
16802
15836
  selectedElRef.current = logoEl;
@@ -16825,7 +15859,7 @@ function OhhwellsBridge() {
16825
15859
  },
16826
15860
  [deactivate, markSelected]
16827
15861
  );
16828
- const openLogoSizePanel = useCallback8((logoEl) => {
15862
+ const openLogoSizePanel = useCallback7((logoEl) => {
16829
15863
  const placement = getLogoPlacement(logoEl);
16830
15864
  const draft = readLogoSizeState(editContentRef.current, placement);
16831
15865
  setLogoSizeDraft(draft);
@@ -16838,7 +15872,7 @@ function OhhwellsBridge() {
16838
15872
  placement
16839
15873
  });
16840
15874
  }, []);
16841
- const openSocialsDisplayPanel = useCallback8((row) => {
15875
+ const openSocialsDisplayPanel = useCallback7((row) => {
16842
15876
  setParentScrollSnap(parentScrollRef.current);
16843
15877
  setFloatingPanel({
16844
15878
  key: "socials-display",
@@ -16848,7 +15882,7 @@ function OhhwellsBridge() {
16848
15882
  row
16849
15883
  });
16850
15884
  }, []);
16851
- const changeSocialsDisplay = useCallback8(
15885
+ const changeSocialsDisplay = useCallback7(
16852
15886
  (row, next) => {
16853
15887
  if (next.icon) {
16854
15888
  const missing = socialsMissingIcons(row);
@@ -16871,17 +15905,17 @@ function OhhwellsBridge() {
16871
15905
  },
16872
15906
  []
16873
15907
  );
16874
- const closeFloatingPanelOnly = useCallback8(() => {
15908
+ const closeFloatingPanelOnly = useCallback7(() => {
16875
15909
  setFloatingPanel(null);
16876
15910
  setLogoSizeDraft(null);
16877
15911
  }, []);
16878
15912
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16879
- const closeFloatingPanelAndDeselect = useCallback8(() => {
15913
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
16880
15914
  setFloatingPanel(null);
16881
15915
  setLogoSizeDraft(null);
16882
15916
  deselectRef.current();
16883
15917
  }, []);
16884
- useEffect13(() => {
15918
+ useEffect12(() => {
16885
15919
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
16886
15920
  if (!session || !logoSizeDraft) {
16887
15921
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -16900,7 +15934,7 @@ function OhhwellsBridge() {
16900
15934
  max: LOGO_SIZE_MAX
16901
15935
  });
16902
15936
  }, [floatingPanel, logoSizeDraft, editorViewport]);
16903
- const persistLogoSizeDraft = useCallback8(
15937
+ const persistLogoSizeDraft = useCallback7(
16904
15938
  (placement, draft) => {
16905
15939
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
16906
15940
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -16940,7 +15974,7 @@ function OhhwellsBridge() {
16940
15974
  },
16941
15975
  [postToParent2]
16942
15976
  );
16943
- const activate = useCallback8((el, options) => {
15977
+ const activate = useCallback7((el, options) => {
16944
15978
  if (activeElRef.current === el) return;
16945
15979
  if (isIconEditable(el)) return;
16946
15980
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17024,8 +16058,8 @@ function OhhwellsBridge() {
17024
16058
  openLogoSizePanelRef.current = openLogoSizePanel;
17025
16059
  deselectRef.current = deselect;
17026
16060
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17027
- const lastSiteWideScopeRef = useRef10(null);
17028
- useEffect13(() => {
16061
+ const lastSiteWideScopeRef = useRef9(null);
16062
+ useEffect12(() => {
17029
16063
  if (!isEditMode) {
17030
16064
  if (lastSiteWideScopeRef.current !== false) {
17031
16065
  lastSiteWideScopeRef.current = false;
@@ -17058,27 +16092,15 @@ function OhhwellsBridge() {
17058
16092
  }
17059
16093
  const applyContent = (content) => {
17060
16094
  const imageLoads = [];
17061
- if (typeof content[BRAND_KIT_KEY] === "string") {
17062
- brandKitRef.current = content[BRAND_KIT_KEY];
17063
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17064
- }
17065
16095
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17066
16096
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17067
16097
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17068
16098
  }
17069
- if (typeof content[STYLE_STORE_KEY] === "string") {
17070
- stylesRef.current = content[STYLE_STORE_KEY];
17071
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17072
- }
17073
- applyBrandChrome(content);
17074
16099
  for (const [key, val] of Object.entries(content)) {
17075
16100
  if (key === "__ohw_sections") continue;
17076
16101
  if (key === AI_SECTIONS_KEY) continue;
17077
16102
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17078
16103
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17079
- if (key === BRAND_KIT_KEY) continue;
17080
- if (key === STYLE_STORE_KEY) continue;
17081
- if (BRAND_CHROME_KEYS.has(key)) continue;
17082
16104
  if (applyVideoSettingNode(key, val)) continue;
17083
16105
  if (applyCarouselNode(key, val)) continue;
17084
16106
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17136,9 +16158,7 @@ function OhhwellsBridge() {
17136
16158
  let cancelled = false;
17137
16159
  setFetchState("loading");
17138
16160
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17139
- const initialPath = pathname;
17140
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17141
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16161
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17142
16162
  if (cancelled) return;
17143
16163
  const content = data?.content ?? {};
17144
16164
  contentCache.set(subdomain, content);
@@ -17151,7 +16171,7 @@ function OhhwellsBridge() {
17151
16171
  cancelled = true;
17152
16172
  };
17153
16173
  }, [subdomain, isEditMode]);
17154
- useEffect13(() => {
16174
+ useEffect12(() => {
17155
16175
  if (!isEditMode) return;
17156
16176
  const resolveIndex = (form, clientY) => {
17157
16177
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17192,7 +16212,7 @@ function OhhwellsBridge() {
17192
16212
  window.removeEventListener("drop", onDrop, true);
17193
16213
  };
17194
16214
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17195
- useEffect13(() => {
16215
+ useEffect12(() => {
17196
16216
  if (!isEditMode) return;
17197
16217
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17198
16218
  markFormFields(form);
@@ -17204,7 +16224,7 @@ function OhhwellsBridge() {
17204
16224
  });
17205
16225
  return () => observer.disconnect();
17206
16226
  }, [isEditMode, fetchState, pathname]);
17207
- useEffect13(() => {
16227
+ useEffect12(() => {
17208
16228
  if (!isEditMode) return;
17209
16229
  let saveTimer = null;
17210
16230
  const onInput = (e) => {
@@ -17226,14 +16246,14 @@ function OhhwellsBridge() {
17226
16246
  document.addEventListener("input", onInput, true);
17227
16247
  return () => document.removeEventListener("input", onInput, true);
17228
16248
  }, [isEditMode, persistFields]);
17229
- useEffect13(() => {
16249
+ useEffect12(() => {
17230
16250
  if (isEditMode || fetchState !== "done") return;
17231
16251
  const content = contentCache.get(subdomain) ?? {};
17232
16252
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17233
16253
  reconcileFieldsFromContent(form, content);
17234
16254
  });
17235
16255
  }, [isEditMode, fetchState, subdomain]);
17236
- useEffect13(() => {
16256
+ useEffect12(() => {
17237
16257
  if (!isEditMode) return;
17238
16258
  const swallow = (e) => {
17239
16259
  const target = e.target;
@@ -17242,12 +16262,12 @@ function OhhwellsBridge() {
17242
16262
  document.addEventListener("submit", swallow, true);
17243
16263
  return () => document.removeEventListener("submit", swallow, true);
17244
16264
  }, [isEditMode]);
17245
- useEffect13(() => {
16265
+ useEffect12(() => {
17246
16266
  if (isEditMode || fetchState !== "done") return;
17247
16267
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17248
16268
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17249
16269
  }, [isEditMode, fetchState, subdomain]);
17250
- useEffect13(() => {
16270
+ useEffect12(() => {
17251
16271
  if (!subdomain || isEditMode) return;
17252
16272
  let debounceTimer = null;
17253
16273
  let observer = null;
@@ -17258,21 +16278,10 @@ function OhhwellsBridge() {
17258
16278
  initSectionInstancesFromContent(content, window.location.pathname);
17259
16279
  observer?.disconnect();
17260
16280
  try {
17261
- applyBrandChrome(content);
17262
- if (typeof content[BRAND_KIT_KEY] === "string") {
17263
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17264
- }
17265
- if (typeof content[STYLE_STORE_KEY] === "string") {
17266
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17267
- }
17268
16281
  for (const [key, val] of Object.entries(content)) {
17269
16282
  if (key === "__ohw_sections") continue;
17270
16283
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17271
16284
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17272
- if (key === BRAND_KIT_KEY) continue;
17273
- if (key === STYLE_STORE_KEY) continue;
17274
- if (key === STYLE_STORE_KEY) continue;
17275
- if (BRAND_CHROME_KEYS.has(key)) continue;
17276
16285
  if (applyVideoSettingNode(key, val)) continue;
17277
16286
  if (applyCarouselNode(key, val)) continue;
17278
16287
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17315,17 +16324,6 @@ function OhhwellsBridge() {
17315
16324
  debounceTimer = setTimeout(applyFromCache, 150);
17316
16325
  };
17317
16326
  applyFromCache();
17318
- const pathCacheKey = `${subdomain}::${pathname}`;
17319
- if (!fetchedContentPaths.has(pathCacheKey)) {
17320
- fetchedContentPaths.add(pathCacheKey);
17321
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17322
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17323
- if (!data?.content) return;
17324
- contentCache.set(subdomain, data.content);
17325
- applyFromCache();
17326
- }).catch(() => {
17327
- });
17328
- }
17329
16327
  observer = new MutationObserver(scheduleApply);
17330
16328
  observer.observe(document.body, { childList: true, subtree: true });
17331
16329
  return () => {
@@ -17339,10 +16337,10 @@ function OhhwellsBridge() {
17339
16337
  const visible = Boolean(subdomain) && fetchState !== "done";
17340
16338
  el.style.display = visible ? "flex" : "none";
17341
16339
  }, [subdomain, fetchState]);
17342
- useEffect13(() => {
16340
+ useEffect12(() => {
17343
16341
  postToParent2({ type: "ow:navigation", path: pathname });
17344
16342
  }, [pathname, postToParent2]);
17345
- useEffect13(() => {
16343
+ useEffect12(() => {
17346
16344
  if (!isEditMode) return;
17347
16345
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17348
16346
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17350,7 +16348,7 @@ function OhhwellsBridge() {
17350
16348
  deselectRef.current();
17351
16349
  deactivateRef.current();
17352
16350
  }, [pathname, isEditMode]);
17353
- useEffect13(() => {
16351
+ useEffect12(() => {
17354
16352
  const contentForNav = () => {
17355
16353
  if (isEditMode) return editContentRef.current;
17356
16354
  if (!subdomain) return {};
@@ -17417,36 +16415,31 @@ function OhhwellsBridge() {
17417
16415
  observer?.disconnect();
17418
16416
  };
17419
16417
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17420
- useEffect13(() => {
16418
+ useEffect12(() => {
17421
16419
  if (!isEditMode) return;
17422
- let lastPosted = 0;
17423
16420
  const measure = () => {
17424
16421
  const h = document.body.scrollHeight;
17425
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17426
- lastPosted = h;
17427
- postToParent2({ type: "ow:height", height: h });
17428
- }
17429
- };
17430
- let raf = null;
17431
- const schedule = () => {
17432
- if (raf != null) return;
17433
- raf = requestAnimationFrame(() => {
17434
- raf = null;
17435
- measure();
17436
- });
16422
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17437
16423
  };
17438
16424
  const t1 = setTimeout(measure, 50);
17439
16425
  const t2 = setTimeout(measure, 500);
17440
- const ro = new ResizeObserver(schedule);
17441
- ro.observe(document.body);
16426
+ let lastWidth = window.innerWidth;
16427
+ let resizeTimer = null;
16428
+ const handleResize = () => {
16429
+ if (window.innerWidth === lastWidth) return;
16430
+ lastWidth = window.innerWidth;
16431
+ if (resizeTimer) clearTimeout(resizeTimer);
16432
+ resizeTimer = setTimeout(measure, 150);
16433
+ };
16434
+ window.addEventListener("resize", handleResize);
17442
16435
  return () => {
17443
16436
  clearTimeout(t1);
17444
16437
  clearTimeout(t2);
17445
- if (raf != null) cancelAnimationFrame(raf);
17446
- ro.disconnect();
16438
+ if (resizeTimer) clearTimeout(resizeTimer);
16439
+ window.removeEventListener("resize", handleResize);
17447
16440
  };
17448
16441
  }, [pathname, isEditMode, postToParent2]);
17449
- useEffect13(() => {
16442
+ useEffect12(() => {
17450
16443
  if (!subdomainFromQuery || isEditMode) return;
17451
16444
  const handleClick = (e) => {
17452
16445
  const anchor = e.target.closest("a");
@@ -17462,7 +16455,7 @@ function OhhwellsBridge() {
17462
16455
  document.addEventListener("click", handleClick, true);
17463
16456
  return () => document.removeEventListener("click", handleClick, true);
17464
16457
  }, [subdomainFromQuery, isEditMode, router]);
17465
- useEffect13(() => {
16458
+ useEffect12(() => {
17466
16459
  if (!isEditMode) {
17467
16460
  editStylesRef.current?.base.remove();
17468
16461
  editStylesRef.current?.forceHover.remove();
@@ -17624,21 +16617,16 @@ function OhhwellsBridge() {
17624
16617
  return;
17625
16618
  }
17626
16619
  const target = e.target;
17627
- if (target.closest("[data-ohw-ai-review]")) return;
17628
16620
  if (target.closest("[data-ohw-toolbar]")) return;
17629
16621
  if (target.closest("[data-ohw-state-toggle]")) return;
17630
16622
  if (target.closest("[data-ohw-max-badge]")) return;
17631
16623
  if (isInsideLinkEditor(target)) return;
17632
- if (isInsideFloatingPanel(target)) return;
17633
16624
  if (target.closest("[data-ohw-form-toolbar]")) return;
17634
16625
  if (target.closest(
17635
16626
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17636
16627
  )) {
17637
16628
  return;
17638
16629
  }
17639
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
17640
- clearMediaSelectionRef.current();
17641
- }
17642
16630
  {
17643
16631
  const formEl = getFormElement(target);
17644
16632
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -17786,11 +16774,8 @@ function OhhwellsBridge() {
17786
16774
  if (isMediaEditable(editable) && !buttonOnMedia) {
17787
16775
  e.preventDefault();
17788
16776
  e.stopPropagation();
17789
- if (selectedMediaElRef.current === editable) {
17790
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17791
- } else {
17792
- selectMediaElementRef.current(editable);
17793
- }
16777
+ aiSectionApiRef.current?.selectFromElement(editable);
16778
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17794
16779
  return;
17795
16780
  }
17796
16781
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
@@ -17909,12 +16894,10 @@ function OhhwellsBridge() {
17909
16894
  };
17910
16895
  const handleDblClick = (e) => {
17911
16896
  const target = e.target;
17912
- if (target.closest("[data-ohw-ai-review]")) return;
17913
16897
  if (target.closest("[data-ohw-toolbar]")) return;
17914
16898
  if (target.closest("[data-ohw-state-toggle]")) return;
17915
16899
  if (target.closest("[data-ohw-max-badge]")) return;
17916
16900
  if (isInsideLinkEditor(target)) return;
17917
- if (isInsideFloatingPanel(target)) return;
17918
16901
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
17919
16902
  return;
17920
16903
  }
@@ -17955,14 +16938,11 @@ function OhhwellsBridge() {
17955
16938
  setSiblingHintRects([]);
17956
16939
  return;
17957
16940
  }
17958
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16941
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
17959
16942
  hoveredItemElRef.current = null;
17960
16943
  setHoveredItemRect(null);
17961
16944
  hoveredNavContainerRef.current = null;
17962
16945
  setHoveredNavContainerRect(null);
17963
- siblingHintElRef.current = null;
17964
- setSiblingHintRect(null);
17965
- setSiblingHintRects([]);
17966
16946
  return;
17967
16947
  }
17968
16948
  {
@@ -18071,6 +17051,7 @@ function OhhwellsBridge() {
18071
17051
  hoveredNavContainerRef.current = null;
18072
17052
  setHoveredNavContainerRect(null);
18073
17053
  hoveredItemElRef.current = editable;
17054
+ setHoveredItemRect(editable.getBoundingClientRect());
18074
17055
  }
18075
17056
  }
18076
17057
  }
@@ -18367,7 +17348,7 @@ function OhhwellsBridge() {
18367
17348
  }
18368
17349
  };
18369
17350
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18370
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17351
+ if (linkPopoverOpenRef.current) {
18371
17352
  if (hoveredImageRef.current) {
18372
17353
  hoveredImageRef.current = null;
18373
17354
  hoveredImageHasTextOverlapRef.current = false;
@@ -18383,6 +17364,11 @@ function OhhwellsBridge() {
18383
17364
  probeNavigationHoverAt(x, y);
18384
17365
  return;
18385
17366
  }
17367
+ if (isPointOverLogo(x, y)) {
17368
+ dismissImageHover();
17369
+ probeNavigationHoverAt(x, y);
17370
+ return;
17371
+ }
18386
17372
  const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
18387
17373
  '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
18388
17374
  );
@@ -18621,7 +17607,7 @@ function OhhwellsBridge() {
18621
17607
  }
18622
17608
  };
18623
17609
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18624
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17610
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18625
17611
  if (activeStateElRef.current) {
18626
17612
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18627
17613
  activeStateElRef.current = null;
@@ -18696,7 +17682,8 @@ function OhhwellsBridge() {
18696
17682
  };
18697
17683
  const handleMouseMove = (e) => {
18698
17684
  const { clientX, clientY } = e;
18699
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17685
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17686
+ if (isOverEditorChrome(clientX, clientY)) {
18700
17687
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18701
17688
  formHoverElRef.current = null;
18702
17689
  setFormHoverRect(null);
@@ -18704,12 +17691,6 @@ function OhhwellsBridge() {
18704
17691
  setHoveredItemRect(null);
18705
17692
  hoveredNavContainerRef.current = null;
18706
17693
  setHoveredNavContainerRect(null);
18707
- siblingHintElRef.current = null;
18708
- setSiblingHintRect(null);
18709
- setSiblingHintRects([]);
18710
- dismissImageHover();
18711
- clearImageHover();
18712
- setSectionGap(null);
18713
17694
  return;
18714
17695
  }
18715
17696
  probeSectionGapAt(clientX, clientY);
@@ -18720,11 +17701,7 @@ function OhhwellsBridge() {
18720
17701
  if (e.data?.type !== "ow:pointer-sync") return;
18721
17702
  const { clientX, clientY } = e.data;
18722
17703
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18723
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18724
- dismissImageHover();
18725
- clearImageHover();
18726
- return;
18727
- }
17704
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18728
17705
  probeSectionGapAt(clientX, clientY);
18729
17706
  probeImageAt(clientX, clientY);
18730
17707
  probeHoverCardsAt(clientX, clientY);
@@ -18970,19 +17947,10 @@ function OhhwellsBridge() {
18970
17947
  if (e.data?.type !== "ow:hydrate") return;
18971
17948
  const content = e.data.content;
18972
17949
  if (!content) return;
18973
- if (typeof content[BRAND_KIT_KEY] === "string") {
18974
- brandKitRef.current = content[BRAND_KIT_KEY];
18975
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
18976
- }
18977
17950
  if (typeof content[AI_SECTIONS_KEY] === "string") {
18978
17951
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
18979
17952
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
18980
17953
  }
18981
- if (typeof content[STYLE_STORE_KEY] === "string") {
18982
- stylesRef.current = content[STYLE_STORE_KEY];
18983
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
18984
- }
18985
- applyBrandChrome(content);
18986
17954
  let sectionsJson = null;
18987
17955
  for (const [key, val] of Object.entries(content)) {
18988
17956
  if (key === "__ohw_sections") {
@@ -18992,9 +17960,6 @@ function OhhwellsBridge() {
18992
17960
  if (key === AI_SECTIONS_KEY) continue;
18993
17961
  if (key === LOGO_PLACEHOLDER_KEY) continue;
18994
17962
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
18995
- if (key === BRAND_KIT_KEY) continue;
18996
- if (key === STYLE_STORE_KEY) continue;
18997
- if (BRAND_CHROME_KEYS.has(key)) continue;
18998
17963
  if (applyVideoSettingNode(key, val)) continue;
18999
17964
  if (applyCarouselNode(key, val)) continue;
19000
17965
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19096,10 +18061,7 @@ function OhhwellsBridge() {
19096
18061
  const payload = e.data.payload;
19097
18062
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19098
18063
  const previous = aiSectionsRef.current;
19099
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19100
- ...payload,
19101
- path: payload.path ?? window.location.pathname
19102
- });
18064
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19103
18065
  const nextValue = serializeAiSectionsState(nextState);
19104
18066
  aiSectionsRef.current = nextValue;
19105
18067
  applyAiSectionsToDom(nextState);
@@ -19136,55 +18098,12 @@ function OhhwellsBridge() {
19136
18098
  const value = typeof e.data.value === "string" ? e.data.value : "";
19137
18099
  aiSectionsRef.current = value;
19138
18100
  applyAiSectionsToDom(parseAiSectionsState(value));
19139
- applyStylesToDom(parseStyleStore(stylesRef.current));
19140
18101
  const restoredHeight = document.documentElement.scrollHeight;
19141
18102
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19142
18103
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19143
18104
  postAiSectionsChanged();
19144
18105
  };
19145
18106
  window.addEventListener("message", handleAiSetSections);
19146
- const handleMoveSection = (e) => {
19147
- if (e.data?.type !== "ow:move-section") return;
19148
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19149
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19150
- if (!instanceId || !direction) return;
19151
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19152
- if (!entries) return;
19153
- const orderJson = JSON.stringify(entries);
19154
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19155
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19156
- window.dispatchEvent(new Event("resize"));
19157
- };
19158
- window.addEventListener("message", handleMoveSection);
19159
- const handleAiSetBrand = (e) => {
19160
- if (e.data?.type !== "ow:ai-set-brand") return;
19161
- const value = typeof e.data.value === "string" ? e.data.value : "";
19162
- const previous = brandKitRef.current;
19163
- brandKitRef.current = value;
19164
- applyBrandToDom(parseBrandKit(value));
19165
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19166
- applyStylesToDom(parseStyleStore(stylesRef.current));
19167
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19168
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19169
- };
19170
- window.addEventListener("message", handleAiSetBrand);
19171
- const handleAiSetStyles = (e) => {
19172
- if (e.data?.type !== "ow:ai-set-styles") return;
19173
- const value = typeof e.data.value === "string" ? e.data.value : "";
19174
- const previous = stylesRef.current;
19175
- stylesRef.current = value;
19176
- applyStylesToDom(parseStyleStore(value));
19177
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19178
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19179
- };
19180
- window.addEventListener("message", handleAiSetStyles);
19181
- const handleGetBrand = (e) => {
19182
- if (e.data?.type !== "ow:get-brand") return;
19183
- const template = deriveTemplateBrand();
19184
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19185
- postToParentRef.current({ type: "ow:brand-value", value });
19186
- };
19187
- window.addEventListener("message", handleGetBrand);
19188
18107
  const handleDeactivate = (e) => {
19189
18108
  if (e.data?.type !== "ow:deactivate") return;
19190
18109
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
@@ -19193,12 +18112,6 @@ function OhhwellsBridge() {
19193
18112
  closeLinkPopoverRef.current();
19194
18113
  return;
19195
18114
  }
19196
- if (floatingPanelOpenRef.current) {
19197
- setFloatingPanelRef.current(null);
19198
- deselectRef.current();
19199
- deactivateRef.current();
19200
- return;
19201
- }
19202
18115
  deselectRef.current();
19203
18116
  deactivateRef.current();
19204
18117
  };
@@ -19286,10 +18199,6 @@ function OhhwellsBridge() {
19286
18199
  const handleKeyDown = (e) => {
19287
18200
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19288
18201
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19289
- if (e.key === "Escape" && selectedMediaElRef.current) {
19290
- clearMediaSelectionRef.current();
19291
- return;
19292
- }
19293
18202
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19294
18203
  e.preventDefault();
19295
18204
  selectAllTextInEditable(activeElRef.current);
@@ -19449,12 +18358,6 @@ function OhhwellsBridge() {
19449
18358
  if (aiSectionsRef.current) {
19450
18359
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19451
18360
  }
19452
- if (stylesRef.current) {
19453
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19454
- }
19455
- if (brandKitRef.current) {
19456
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19457
- }
19458
18361
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19459
18362
  const formKey = formKeyOf(form);
19460
18363
  if (!formKey) return;
@@ -19472,12 +18375,8 @@ function OhhwellsBridge() {
19472
18375
  if (inserted) {
19473
18376
  const tracker = getSectionsTracker();
19474
18377
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19475
- const reportHeight = () => {
19476
- const h = document.body.scrollHeight;
19477
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19478
- };
19479
- reportHeight();
19480
- setTimeout(reportHeight, 500);
18378
+ const h = document.documentElement.scrollHeight;
18379
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19481
18380
  }
19482
18381
  };
19483
18382
  const handleSwitchSchedule = (e) => {
@@ -19864,10 +18763,6 @@ function OhhwellsBridge() {
19864
18763
  window.removeEventListener("message", handleAiApplyTree);
19865
18764
  window.removeEventListener("message", handleAiDeleteSection);
19866
18765
  window.removeEventListener("message", handleAiSetSections);
19867
- window.removeEventListener("message", handleMoveSection);
19868
- window.removeEventListener("message", handleAiSetBrand);
19869
- window.removeEventListener("message", handleAiSetStyles);
19870
- window.removeEventListener("message", handleGetBrand);
19871
18766
  window.removeEventListener("message", handleDeactivate);
19872
18767
  window.removeEventListener("message", handleToastAction);
19873
18768
  window.removeEventListener("message", handleFormCount);
@@ -19878,7 +18773,7 @@ function OhhwellsBridge() {
19878
18773
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
19879
18774
  };
19880
18775
  }, [isEditMode, refreshStateRules]);
19881
- useEffect13(() => {
18776
+ useEffect12(() => {
19882
18777
  if (!isEditMode) return;
19883
18778
  const THRESHOLD = 10;
19884
18779
  const resolveWasSelected = (el) => {
@@ -20034,7 +18929,7 @@ function OhhwellsBridge() {
20034
18929
  unlockFooterDragInteraction();
20035
18930
  };
20036
18931
  }, [isEditMode]);
20037
- useEffect13(() => {
18932
+ useEffect12(() => {
20038
18933
  const handler = (e) => {
20039
18934
  if (e.data?.type !== "ow:request-schedule-config") return;
20040
18935
  const insertAfterVal = e.data.insertAfter;
@@ -20050,7 +18945,7 @@ function OhhwellsBridge() {
20050
18945
  window.addEventListener("message", handler);
20051
18946
  return () => window.removeEventListener("message", handler);
20052
18947
  }, [processConfigRequest]);
20053
- useEffect13(() => {
18948
+ useEffect12(() => {
20054
18949
  if (!isEditMode) return;
20055
18950
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20056
18951
  el.removeAttribute("data-ohw-active-state");
@@ -20074,7 +18969,7 @@ function OhhwellsBridge() {
20074
18969
  postToParent2({
20075
18970
  type: "ow:ready",
20076
18971
  version: "1",
20077
- bridgeVersion: "0.1.67",
18972
+ bridgeVersion: "0.1.66",
20078
18973
  path: pathname,
20079
18974
  nodes: collectEditableNodes(editContentRef.current),
20080
18975
  sections
@@ -20086,13 +18981,13 @@ function OhhwellsBridge() {
20086
18981
  clearTimeout(timer);
20087
18982
  };
20088
18983
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20089
- useEffect13(() => {
18984
+ useEffect12(() => {
20090
18985
  scrollToHashSectionWhenReady();
20091
18986
  const onHashChange = () => scrollToHashSectionWhenReady();
20092
18987
  window.addEventListener("hashchange", onHashChange);
20093
18988
  return () => window.removeEventListener("hashchange", onHashChange);
20094
18989
  }, [pathname]);
20095
- const handleCommand = useCallback8((cmd) => {
18990
+ const handleCommand = useCallback7((cmd) => {
20096
18991
  const el = activeElRef.current;
20097
18992
  const selBefore = window.getSelection();
20098
18993
  let savedOffsets = null;
@@ -20128,7 +19023,7 @@ function OhhwellsBridge() {
20128
19023
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20129
19024
  refreshActiveCommandsRef.current();
20130
19025
  }, []);
20131
- useEffect13(() => {
19026
+ useEffect12(() => {
20132
19027
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20133
19028
  if (!session || !logoSizeDraft) return;
20134
19029
  const onPanelAction = (e) => {
@@ -20166,7 +19061,7 @@ function OhhwellsBridge() {
20166
19061
  window.addEventListener("message", onPanelAction);
20167
19062
  return () => window.removeEventListener("message", onPanelAction);
20168
19063
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20169
- const handleStateChange = useCallback8((state) => {
19064
+ const handleStateChange = useCallback7((state) => {
20170
19065
  if (!activeStateElRef.current) return;
20171
19066
  const el = activeStateElRef.current;
20172
19067
  if (state === "Default") {
@@ -20179,7 +19074,7 @@ function OhhwellsBridge() {
20179
19074
  }
20180
19075
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20181
19076
  }, [deactivate]);
20182
- const reselectAfterLinkPopover = useCallback8(
19077
+ const reselectAfterLinkPopover = useCallback7(
20183
19078
  (hrefKey) => {
20184
19079
  requestAnimationFrame(() => {
20185
19080
  const el = resolveHrefKeyElement(hrefKey);
@@ -20188,7 +19083,7 @@ function OhhwellsBridge() {
20188
19083
  },
20189
19084
  [resolveHrefKeyElement]
20190
19085
  );
20191
- const closeLinkPopover = useCallback8(() => {
19086
+ const closeLinkPopover = useCallback7(() => {
20192
19087
  const session = linkPopoverSessionRef.current;
20193
19088
  addNavAfterAnchorRef.current = null;
20194
19089
  setLinkPopover(null);
@@ -20196,9 +19091,9 @@ function OhhwellsBridge() {
20196
19091
  reselectAfterLinkPopover(session.key);
20197
19092
  }
20198
19093
  }, [reselectAfterLinkPopover]);
20199
- const closeLinkPopoverRef = useRef10(closeLinkPopover);
19094
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
20200
19095
  closeLinkPopoverRef.current = closeLinkPopover;
20201
- const openLinkPopoverForActive = useCallback8(() => {
19096
+ const openLinkPopoverForActive = useCallback7(() => {
20202
19097
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20203
19098
  if (!hrefCtx) return;
20204
19099
  bumpLinkPopoverGrace();
@@ -20209,7 +19104,7 @@ function OhhwellsBridge() {
20209
19104
  });
20210
19105
  deactivate();
20211
19106
  }, [deactivate]);
20212
- const openLinkPopoverForSelected = useCallback8(() => {
19107
+ const openLinkPopoverForSelected = useCallback7(() => {
20213
19108
  const anchor = selectedElRef.current;
20214
19109
  if (!anchor) return;
20215
19110
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20226,7 +19121,7 @@ function OhhwellsBridge() {
20226
19121
  });
20227
19122
  deselect();
20228
19123
  }, [deselect]);
20229
- const handleSelectParent = useCallback8(() => {
19124
+ const handleSelectParent = useCallback7(() => {
20230
19125
  const selected = selectedElRef.current;
20231
19126
  if (!selected) return;
20232
19127
  if (toolbarVariantRef.current === "select-frame") {
@@ -20253,7 +19148,7 @@ function OhhwellsBridge() {
20253
19148
  }
20254
19149
  deselectRef.current();
20255
19150
  }, []);
20256
- const handleDuplicateSelected = useCallback8(() => {
19151
+ const handleDuplicateSelected = useCallback7(() => {
20257
19152
  const selected = selectedElRef.current;
20258
19153
  if (!selected || !isNavigationItem2(selected)) return;
20259
19154
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20369,7 +19264,7 @@ function OhhwellsBridge() {
20369
19264
  });
20370
19265
  }
20371
19266
  }, [postToParent2]);
20372
- const runPendingDeleteUndo = useCallback8(() => {
19267
+ const runPendingDeleteUndo = useCallback7(() => {
20373
19268
  const pending = pendingDeleteUndoRef.current;
20374
19269
  if (!pending) return false;
20375
19270
  pendingDeleteUndoRef.current = null;
@@ -20377,7 +19272,7 @@ function OhhwellsBridge() {
20377
19272
  enforceLinkHrefs();
20378
19273
  return true;
20379
19274
  }, []);
20380
- const handleDeleteSelected = useCallback8(() => {
19275
+ const handleDeleteSelected = useCallback7(() => {
20381
19276
  const selected = selectedElRef.current;
20382
19277
  if (!selected) return false;
20383
19278
  return deleteSelectedNavFooterItem({
@@ -20398,7 +19293,7 @@ function OhhwellsBridge() {
20398
19293
  }, [postToParent2]);
20399
19294
  handleDeleteSelectedRef.current = handleDeleteSelected;
20400
19295
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20401
- const handleLinkPopoverSubmit = useCallback8(
19296
+ const handleLinkPopoverSubmit = useCallback7(
20402
19297
  (target) => {
20403
19298
  const session = linkPopoverSessionRef.current;
20404
19299
  if (!session) return;
@@ -20464,30 +19359,19 @@ function OhhwellsBridge() {
20464
19359
  const showEditLink = toolbarShowEditLink;
20465
19360
  const currentSections = sectionsByPath[pathname] ?? [];
20466
19361
  linkPopoverOpenRef.current = linkPopover !== null;
20467
- const handleMediaSelect = useCallback8((key) => {
20468
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
20469
- (m) => (m.dataset.ohwKey ?? "") === key
20470
- ) ?? null;
20471
- if (!el) return;
20472
- selectMediaElementRef.current(el);
20473
- }, []);
20474
- const handleMediaReplace = useCallback8(
19362
+ const handleMediaReplace = useCallback7(
20475
19363
  (key) => {
20476
- postToParent2({
20477
- type: "ow:image-pick",
20478
- key,
20479
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
20480
- });
19364
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20481
19365
  },
20482
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19366
+ [postToParent2, mediaHover?.elementType]
20483
19367
  );
20484
- const handleEditCarousel = useCallback8(
19368
+ const handleEditCarousel = useCallback7(
20485
19369
  (key) => {
20486
19370
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20487
19371
  },
20488
19372
  [postToParent2]
20489
19373
  );
20490
- const handleMediaFadeOutComplete = useCallback8((key) => {
19374
+ const handleMediaFadeOutComplete = useCallback7((key) => {
20491
19375
  setUploadingRects((prev) => {
20492
19376
  if (!(key in prev)) return prev;
20493
19377
  const next = { ...prev };
@@ -20495,7 +19379,7 @@ function OhhwellsBridge() {
20495
19379
  return next;
20496
19380
  });
20497
19381
  }, []);
20498
- const handleVideoSettingsChange = useCallback8(
19382
+ const handleVideoSettingsChange = useCallback7(
20499
19383
  (key, settings) => {
20500
19384
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20501
19385
  const video = getVideoEl2(el);
@@ -20517,506 +19401,414 @@ function OhhwellsBridge() {
20517
19401
  },
20518
19402
  [postToParent2]
20519
19403
  );
20520
- return /* @__PURE__ */ jsxs20(Fragment8, { children: [
20521
- /* @__PURE__ */ jsx33("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ jsx33(OhwLoaderSpinner, {}) }),
20522
- /* @__PURE__ */ jsx33("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20523
- bridgeRoot ? createPortal2(
20524
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
20525
- /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20526
- isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20527
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20528
- "div",
20529
- {
20530
- className: "pointer-events-none fixed z-2147483646",
20531
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20532
- children: /* @__PURE__ */ jsx33(
20533
- DropIndicator,
20534
- {
20535
- direction: "horizontal",
20536
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20537
- className: "!h-full !w-full"
20538
- }
20539
- )
20540
- },
20541
- `section-drop-${slot.insertIndex}-${i}`
20542
- )),
20543
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
20544
- MediaOverlay,
20545
- {
20546
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20547
- isUploading: true,
20548
- fadingOut,
20549
- onFadeOutComplete: handleMediaFadeOutComplete,
20550
- onReplace: handleMediaReplace
20551
- },
20552
- `uploading-${key}`
20553
- )),
20554
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ jsx33(
20555
- MediaOverlay,
20556
- {
20557
- hover: mediaHover,
20558
- isUploading: false,
20559
- onReplace: handleMediaReplace,
20560
- onSelect: handleMediaSelect,
20561
- onVideoSettingsChange: handleVideoSettingsChange
20562
- }
20563
- ),
20564
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ jsx33(
20565
- MediaOverlay,
20566
- {
20567
- hover: selectedMedia,
20568
- selected: true,
20569
- hovered: mediaHover?.key === selectedMedia.key,
20570
- isUploading: false,
20571
- onReplace: handleMediaReplace,
20572
- onSelect: handleMediaSelect,
20573
- onVideoSettingsChange: handleVideoSettingsChange
20574
- }
20575
- ),
20576
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20577
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20578
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20579
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20580
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20581
- "div",
20582
- {
20583
- className: "pointer-events-none fixed z-2147483646",
20584
- style: {
20585
- left: slot.left,
20586
- top: slot.top,
20587
- width: slot.width,
20588
- height: slot.height
20589
- },
20590
- children: /* @__PURE__ */ jsx33(
20591
- DropIndicator,
20592
- {
20593
- direction: slot.direction,
20594
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20595
- className: "!h-full !w-full"
20596
- }
20597
- )
20598
- },
20599
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20600
- )),
20601
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20602
- "div",
20603
- {
20604
- className: "pointer-events-none fixed z-2147483646",
20605
- style: {
20606
- left: slot.left,
20607
- top: slot.top,
20608
- width: slot.width,
20609
- height: slot.height
20610
- },
20611
- children: /* @__PURE__ */ jsx33(
20612
- DropIndicator,
20613
- {
20614
- direction: slot.direction,
20615
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20616
- className: "!h-full !w-full"
20617
- }
20618
- )
19404
+ return bridgeRoot ? createPortal2(
19405
+ /* @__PURE__ */ jsxs20(Fragment8, { children: [
19406
+ /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19407
+ isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19408
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
19409
+ MediaOverlay,
19410
+ {
19411
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19412
+ isUploading: true,
19413
+ fadingOut,
19414
+ onFadeOutComplete: handleMediaFadeOutComplete,
19415
+ onReplace: handleMediaReplace
19416
+ },
19417
+ `uploading-${key}`
19418
+ )),
19419
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
19420
+ MediaOverlay,
19421
+ {
19422
+ hover: mediaHover,
19423
+ isUploading: false,
19424
+ onReplace: handleMediaReplace,
19425
+ onVideoSettingsChange: handleVideoSettingsChange
19426
+ }
19427
+ ),
19428
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19429
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19430
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19431
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19432
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19433
+ "div",
19434
+ {
19435
+ className: "pointer-events-none fixed z-2147483646",
19436
+ style: {
19437
+ left: slot.left,
19438
+ top: slot.top,
19439
+ width: slot.width,
19440
+ height: slot.height
20619
19441
  },
20620
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20621
- )),
20622
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20623
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20624
- hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20625
- formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
20626
- ItemInteractionLayer,
20627
- {
20628
- rect: formPickRect,
20629
- state: "active-top",
20630
- itemDragSurface: false,
20631
- toolbarAlign: "left",
20632
- chromeGap: 24,
20633
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
20634
- "div",
20635
- {
20636
- "data-ohw-form-toolbar": "",
20637
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20638
- children: [
20639
- /* @__PURE__ */ jsx33(
20640
- "button",
20641
- {
20642
- type: "button",
20643
- "aria-label": "Add field",
20644
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20645
- onClick: () => setFieldTypePickerOpen((open) => !open),
20646
- "data-ohw-add-field": "",
20647
- children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
20648
- }
20649
- ),
20650
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20651
- /* @__PURE__ */ jsxs20(
20652
- "button",
20653
- {
20654
- type: "button",
20655
- 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",
20656
- onClick: () => {
20657
- const form = formPickElRef.current;
20658
- if (!form) return;
20659
- postToParent2({
20660
- type: "ow:form-pick",
20661
- formKey: formKeyOf(form),
20662
- hasLongText: formHasLongText(form)
20663
- });
20664
- },
20665
- children: [
20666
- /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
20667
- "Form settings",
20668
- formPickCount ? (
20669
- // Counter pill, per the design — not a text suffix.
20670
- /* @__PURE__ */ jsx33(
20671
- "span",
20672
- {
20673
- "data-ohw-form-count": "",
20674
- 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",
20675
- children: formPickCount
20676
- }
20677
- )
20678
- ) : null
20679
- ]
20680
- }
20681
- ),
20682
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20683
- /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
20684
- "button",
20685
- {
20686
- type: "button",
20687
- "aria-pressed": formViewState === state,
20688
- 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"),
20689
- onClick: () => {
20690
- const form = formPickElRef.current;
20691
- const key = form ? formKeyOf(form) : null;
20692
- if (!form || !key) return;
20693
- const initial = successInitialFor(form, key, editContentRef.current);
20694
- setFormViewState(form, key, state, initial);
20695
- setFormViewStateUi(state);
20696
- setFormPickRect(form.getBoundingClientRect());
20697
- if (state === "success") {
20698
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20699
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20700
- } else {
20701
- deactivateRef.current();
20702
- }
20703
- },
20704
- children: state
20705
- },
20706
- state
20707
- )) })
20708
- ]
20709
- }
20710
- )
20711
- }
20712
- ),
20713
- formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
20714
- ItemInteractionLayer,
20715
- {
20716
- rect: formHoverRect,
20717
- state: "hover",
20718
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20719
- }
20720
- ),
20721
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
20722
- ItemInteractionLayer,
20723
- {
20724
- rect: fieldPickRect,
20725
- state: fieldDragging ? "dragging" : "active-top",
20726
- itemDragSurface: false,
20727
- toolbarAlign: "left",
20728
- chromeGap: 10,
20729
- showHandle: true,
20730
- dragHandleLabel: "Reorder field",
20731
- onDragHandleDragStart: handleFieldDragStart,
20732
- onDragHandleDragEnd: handleFieldDragEnd,
20733
- toolbar: /* @__PURE__ */ jsx33(
20734
- FormFieldToolbar,
20735
- {
20736
- type: fieldPickState.type,
20737
- required: fieldPickState.required,
20738
- onTypeChange: handleFieldTypeChange,
20739
- onRequiredToggle: handleFieldRequiredToggle,
20740
- onDuplicate: handleFieldDuplicate,
20741
- onDelete: handleFieldDelete
20742
- }
20743
- )
20744
- }
20745
- ),
20746
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20747
- "div",
20748
- {
20749
- className: "pointer-events-none fixed z-[2147483644]",
20750
- style: { top: slot.top, left: slot.left, width: slot.width },
20751
- children: /* @__PURE__ */ jsx33(
20752
- DropIndicator,
20753
- {
20754
- direction: "horizontal",
20755
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20756
- className: "!w-full"
20757
- }
20758
- )
19442
+ children: /* @__PURE__ */ jsx33(
19443
+ DropIndicator,
19444
+ {
19445
+ direction: slot.direction,
19446
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19447
+ className: "!h-full !w-full"
19448
+ }
19449
+ )
19450
+ },
19451
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19452
+ )),
19453
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19454
+ "div",
19455
+ {
19456
+ className: "pointer-events-none fixed z-2147483646",
19457
+ style: {
19458
+ left: slot.left,
19459
+ top: slot.top,
19460
+ width: slot.width,
19461
+ height: slot.height
20759
19462
  },
20760
- `field-drop-${i}`
20761
- )) : null,
20762
- fieldTypePickerOpen && formPickRect ? (() => {
20763
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20764
- return /* @__PURE__ */ jsx33(
20765
- "div",
19463
+ children: /* @__PURE__ */ jsx33(
19464
+ DropIndicator,
20766
19465
  {
20767
- className: "pointer-events-none fixed z-[2147483645]",
20768
- style: {
20769
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20770
- left: toolbar ? toolbar.left : formPickRect.left + 24
20771
- },
20772
- children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
19466
+ direction: slot.direction,
19467
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19468
+ className: "!h-full !w-full"
20773
19469
  }
20774
- );
20775
- })() : null,
20776
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20777
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
20778
- FooterContainerChrome,
20779
- {
20780
- rect: toolbarRect,
20781
- onAdd: handleAddFooterColumn,
20782
- addDisabled: !canAddFooterColumn()
20783
- }
20784
- ),
20785
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
20786
- ItemInteractionLayer,
20787
- {
20788
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20789
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20790
- elRef: glowElRef,
20791
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20792
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20793
- dragDisabled: reorderDragDisabled,
20794
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20795
- onDragHandleDragStart: handleItemDragStart,
20796
- onDragHandleDragEnd: handleItemDragEnd,
20797
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20798
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20799
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20800
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
20801
- ItemActionToolbar,
20802
- {
20803
- onEditLink: openLinkPopoverForSelected,
20804
- onStyle: () => {
20805
- const row = selectedElRef.current;
20806
- if (!row) return;
20807
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20808
- else openSocialsDisplayPanel(row);
20809
- },
20810
- showStyle: selectedIsSocialsRow,
20811
- styleActive: floatingPanel?.kind === "socials-display",
20812
- onAddItem: handleAddChildItem,
20813
- onSelectParent: handleSelectParent,
20814
- onDuplicate: handleDuplicateSelected,
20815
- onDelete: handleDeleteSelected,
20816
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20817
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20818
- return row ? !canAddSocialItem(row) : false;
20819
- })(),
20820
- editLinkDisabled: false,
20821
- moreDisabled: false,
20822
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20823
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20824
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20825
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19470
+ )
19471
+ },
19472
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19473
+ )),
19474
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19475
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19476
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19477
+ formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
19478
+ ItemInteractionLayer,
19479
+ {
19480
+ rect: formPickRect,
19481
+ state: "active-top",
19482
+ itemDragSurface: false,
19483
+ toolbarAlign: "left",
19484
+ chromeGap: 24,
19485
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
19486
+ "div",
19487
+ {
19488
+ "data-ohw-form-toolbar": "",
19489
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19490
+ children: [
19491
+ /* @__PURE__ */ jsx33(
19492
+ "button",
19493
+ {
19494
+ type: "button",
19495
+ "aria-label": "Add field",
19496
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19497
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19498
+ "data-ohw-add-field": "",
19499
+ children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
19500
+ }
20826
19501
  ),
20827
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20828
- dropdownOpen: navDropdownPreviewOpen,
20829
- onDropdownOpenChange: handleNavDropdownOpenChange,
20830
- headingVisible: footerHeadingVisible,
20831
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20832
- }
20833
- ) : void 0
20834
- }
20835
- ),
20836
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
20837
- /* @__PURE__ */ jsx33(
20838
- EditGlowChrome,
19502
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19503
+ /* @__PURE__ */ jsxs20(
19504
+ "button",
19505
+ {
19506
+ type: "button",
19507
+ 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",
19508
+ onClick: () => {
19509
+ const form = formPickElRef.current;
19510
+ if (!form) return;
19511
+ postToParent2({
19512
+ type: "ow:form-pick",
19513
+ formKey: formKeyOf(form),
19514
+ hasLongText: formHasLongText(form)
19515
+ });
19516
+ },
19517
+ children: [
19518
+ /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
19519
+ "Form settings",
19520
+ formPickCount ? (
19521
+ // Counter pill, per the design — not a text suffix.
19522
+ /* @__PURE__ */ jsx33(
19523
+ "span",
19524
+ {
19525
+ "data-ohw-form-count": "",
19526
+ 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",
19527
+ children: formPickCount
19528
+ }
19529
+ )
19530
+ ) : null
19531
+ ]
19532
+ }
19533
+ ),
19534
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19535
+ /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
19536
+ "button",
19537
+ {
19538
+ type: "button",
19539
+ "aria-pressed": formViewState === state,
19540
+ 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"),
19541
+ onClick: () => {
19542
+ const form = formPickElRef.current;
19543
+ const key = form ? formKeyOf(form) : null;
19544
+ if (!form || !key) return;
19545
+ const initial = successInitialFor(form, key, editContentRef.current);
19546
+ setFormViewState(form, key, state, initial);
19547
+ setFormViewStateUi(state);
19548
+ setFormPickRect(form.getBoundingClientRect());
19549
+ if (state === "success") {
19550
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19551
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19552
+ } else {
19553
+ deactivateRef.current();
19554
+ }
19555
+ },
19556
+ children: state
19557
+ },
19558
+ state
19559
+ )) })
19560
+ ]
19561
+ }
19562
+ )
19563
+ }
19564
+ ),
19565
+ formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
19566
+ ItemInteractionLayer,
19567
+ {
19568
+ rect: formHoverRect,
19569
+ state: "hover",
19570
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19571
+ }
19572
+ ),
19573
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
19574
+ ItemInteractionLayer,
19575
+ {
19576
+ rect: fieldPickRect,
19577
+ state: fieldDragging ? "dragging" : "active-top",
19578
+ itemDragSurface: false,
19579
+ toolbarAlign: "left",
19580
+ chromeGap: 10,
19581
+ showHandle: true,
19582
+ dragHandleLabel: "Reorder field",
19583
+ onDragHandleDragStart: handleFieldDragStart,
19584
+ onDragHandleDragEnd: handleFieldDragEnd,
19585
+ toolbar: /* @__PURE__ */ jsx33(
19586
+ FormFieldToolbar,
20839
19587
  {
20840
- rect: toolbarRect,
20841
- elRef: glowElRef,
20842
- reorderHrefKey,
20843
- dragDisabled: reorderDragDisabled,
20844
- hideHandle: isItemDragging
19588
+ type: fieldPickState.type,
19589
+ required: fieldPickState.required,
19590
+ onTypeChange: handleFieldTypeChange,
19591
+ onRequiredToggle: handleFieldRequiredToggle,
19592
+ onDuplicate: handleFieldDuplicate,
19593
+ onDelete: handleFieldDelete
20845
19594
  }
20846
- ),
20847
- /* @__PURE__ */ jsx33(
20848
- FloatingToolbar,
19595
+ )
19596
+ }
19597
+ ),
19598
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19599
+ "div",
19600
+ {
19601
+ className: "pointer-events-none fixed z-[2147483644]",
19602
+ style: { top: slot.top, left: slot.left, width: slot.width },
19603
+ children: /* @__PURE__ */ jsx33(
19604
+ DropIndicator,
20849
19605
  {
20850
- rect: toolbarRect,
20851
- parentScroll: parentScrollRef.current,
20852
- elRef: toolbarElRef,
20853
- onCommand: handleCommand,
20854
- activeCommands,
20855
- showEditLink,
20856
- onEditLink: openLinkPopoverForActive
19606
+ direction: "horizontal",
19607
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19608
+ className: "!w-full"
20857
19609
  }
20858
19610
  )
20859
- ] }),
20860
- maxBadge && /* @__PURE__ */ jsxs20(
20861
- "div",
20862
- {
20863
- "data-ohw-max-badge": "",
20864
- style: {
20865
- position: "fixed",
20866
- top: maxBadge.rect.bottom + 4,
20867
- left: maxBadge.rect.right,
20868
- transform: "translateX(-100%)",
20869
- zIndex: 2147483647,
20870
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20871
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20872
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20873
- borderRadius: 4,
20874
- padding: "2px 6px",
20875
- fontSize: 11,
20876
- fontWeight: 500,
20877
- pointerEvents: "none"
20878
- },
20879
- children: [
20880
- maxBadge.current,
20881
- "/",
20882
- maxBadge.max
20883
- ]
20884
- }
20885
- ),
20886
- toggleState && !linkPopover && /* @__PURE__ */ jsx33(
20887
- StateToggle,
19611
+ },
19612
+ `field-drop-${i}`
19613
+ )) : null,
19614
+ fieldTypePickerOpen && formPickRect && /* @__PURE__ */ jsx33(
19615
+ "div",
19616
+ {
19617
+ className: "pointer-events-none fixed z-[2147483645]",
19618
+ style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
19619
+ children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
19620
+ }
19621
+ ),
19622
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19623
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
19624
+ FooterContainerChrome,
19625
+ {
19626
+ rect: toolbarRect,
19627
+ onAdd: handleAddFooterColumn,
19628
+ addDisabled: !canAddFooterColumn()
19629
+ }
19630
+ ),
19631
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
19632
+ ItemInteractionLayer,
19633
+ {
19634
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19635
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19636
+ elRef: glowElRef,
19637
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19638
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19639
+ dragDisabled: reorderDragDisabled,
19640
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19641
+ onDragHandleDragStart: handleItemDragStart,
19642
+ onDragHandleDragEnd: handleItemDragEnd,
19643
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19644
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19645
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19646
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
19647
+ ItemActionToolbar,
19648
+ {
19649
+ onEditLink: openLinkPopoverForSelected,
19650
+ onStyle: () => {
19651
+ const row = selectedElRef.current;
19652
+ if (!row) return;
19653
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19654
+ else openSocialsDisplayPanel(row);
19655
+ },
19656
+ showStyle: selectedIsSocialsRow,
19657
+ styleActive: floatingPanel?.kind === "socials-display",
19658
+ onAddItem: handleAddChildItem,
19659
+ onSelectParent: handleSelectParent,
19660
+ onDuplicate: handleDuplicateSelected,
19661
+ onDelete: handleDeleteSelected,
19662
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19663
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19664
+ return row ? !canAddSocialItem(row) : false;
19665
+ })(),
19666
+ editLinkDisabled: false,
19667
+ moreDisabled: false,
19668
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19669
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19670
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19671
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19672
+ ),
19673
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19674
+ dropdownOpen: navDropdownPreviewOpen,
19675
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19676
+ headingVisible: footerHeadingVisible,
19677
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19678
+ }
19679
+ ) : void 0
19680
+ }
19681
+ ),
19682
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
19683
+ /* @__PURE__ */ jsx33(
19684
+ EditGlowChrome,
20888
19685
  {
20889
- rect: toggleState.rect,
20890
- activeState: toggleState.activeState,
20891
- states: toggleState.states,
20892
- onStateChange: handleStateChange
19686
+ rect: toolbarRect,
19687
+ elRef: glowElRef,
19688
+ reorderHrefKey,
19689
+ dragDisabled: reorderDragDisabled,
19690
+ hideHandle: isItemDragging
20893
19691
  }
20894
19692
  ),
20895
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
20896
- "div",
19693
+ /* @__PURE__ */ jsx33(
19694
+ FloatingToolbar,
20897
19695
  {
20898
- "data-ohw-section-insert-line": "",
20899
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20900
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
20901
- children: [
20902
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20903
- /* @__PURE__ */ jsx33(
20904
- Badge,
20905
- {
20906
- 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",
20907
- onClick: () => {
20908
- window.parent.postMessage(
20909
- {
20910
- type: "ow:add-section",
20911
- insertAfter: sectionGap.insertAfter,
20912
- insertBefore: sectionGap.insertBefore
20913
- },
20914
- "*"
20915
- );
20916
- },
20917
- children: "Add Section"
20918
- }
20919
- ),
20920
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20921
- ]
19696
+ rect: toolbarRect,
19697
+ parentScroll: parentScrollRef.current,
19698
+ elRef: toolbarElRef,
19699
+ onCommand: handleCommand,
19700
+ activeCommands,
19701
+ showEditLink,
19702
+ onEditLink: openLinkPopoverForActive
20922
19703
  }
20923
- ),
20924
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
20925
- LinkPopover,
20926
- {
20927
- panelRef: linkPopoverPanelRef,
20928
- portalContainer: dialogPortalContainer,
20929
- open: true,
20930
- mode: linkPopover.mode ?? "edit",
20931
- pages: sitePages,
20932
- sections: currentSections,
20933
- sectionsByPath,
20934
- initialTarget: linkPopover.target,
20935
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
20936
- onClose: closeLinkPopover,
20937
- onSubmit: handleLinkPopoverSubmit
19704
+ )
19705
+ ] }),
19706
+ maxBadge && /* @__PURE__ */ jsxs20(
19707
+ "div",
19708
+ {
19709
+ "data-ohw-max-badge": "",
19710
+ style: {
19711
+ position: "fixed",
19712
+ top: maxBadge.rect.bottom + 4,
19713
+ left: maxBadge.rect.right,
19714
+ transform: "translateX(-100%)",
19715
+ zIndex: 2147483647,
19716
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19717
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19718
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19719
+ borderRadius: 4,
19720
+ padding: "2px 6px",
19721
+ fontSize: 11,
19722
+ fontWeight: 500,
19723
+ pointerEvents: "none"
20938
19724
  },
20939
- linkPopover.key
20940
- ) : null,
20941
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
20942
- FloatingPanel,
20943
- {
20944
- open: true,
20945
- title: floatingPanel.title,
20946
- context: floatingPanel.context,
20947
- position: floatingPanelPos,
20948
- onPositionChange: setFloatingPanelPos,
20949
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
20950
- onClose: closeFloatingPanelOnly,
20951
- children: /* @__PURE__ */ jsx33(
20952
- SocialsDisplayPanel,
19725
+ children: [
19726
+ maxBadge.current,
19727
+ "/",
19728
+ maxBadge.max
19729
+ ]
19730
+ }
19731
+ ),
19732
+ toggleState && !linkPopover && /* @__PURE__ */ jsx33(
19733
+ StateToggle,
19734
+ {
19735
+ rect: toggleState.rect,
19736
+ activeState: toggleState.activeState,
19737
+ states: toggleState.states,
19738
+ onStateChange: handleStateChange
19739
+ }
19740
+ ),
19741
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
19742
+ "div",
19743
+ {
19744
+ "data-ohw-section-insert-line": "",
19745
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19746
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19747
+ children: [
19748
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19749
+ /* @__PURE__ */ jsx33(
19750
+ Badge,
20953
19751
  {
20954
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
20955
- onChange: (next) => {
20956
- changeSocialsDisplay(floatingPanel.row, next);
20957
- setFloatingPanel({ ...floatingPanel });
20958
- }
19752
+ 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",
19753
+ onClick: () => {
19754
+ window.parent.postMessage(
19755
+ {
19756
+ type: "ow:add-section",
19757
+ insertAfter: sectionGap.insertAfter,
19758
+ insertBefore: sectionGap.insertBefore
19759
+ },
19760
+ "*"
19761
+ );
19762
+ },
19763
+ children: "Add Section"
20959
19764
  }
20960
- )
20961
- }
20962
- ) : null
20963
- ] }),
20964
- bridgeRoot
20965
- ) : null
20966
- ] });
20967
- }
20968
-
20969
- // src/ui/EmptySection.tsx
20970
- import Link3 from "next/link";
20971
- import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
20972
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
20973
- return /* @__PURE__ */ jsxs21(Fragment9, { children: [
20974
- /* @__PURE__ */ jsx34(
20975
- "p",
20976
- {
20977
- style: {
20978
- fontFamily: "var(--brand-font-body)",
20979
- fontSize: "0.75rem",
20980
- fontWeight: 500,
20981
- letterSpacing: "0.15em",
20982
- textTransform: "uppercase",
20983
- color: "var(--brand-accent)",
20984
- marginBottom: "1.5rem"
20985
- },
20986
- children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
20987
- }
20988
- ),
20989
- /* @__PURE__ */ jsx34(
20990
- "h1",
20991
- {
20992
- style: {
20993
- fontFamily: "var(--brand-font-heading)",
20994
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
20995
- lineHeight: 1.1,
20996
- letterSpacing: "-0.025em",
20997
- color: "var(--brand-text)",
20998
- marginBottom: "1rem"
20999
- },
21000
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21001
- children: title
21002
- }
21003
- ),
21004
- /* @__PURE__ */ jsx34(
21005
- "p",
21006
- {
21007
- style: {
21008
- fontFamily: "var(--brand-font-body)",
21009
- fontSize: "1rem",
21010
- lineHeight: 1.7,
21011
- fontWeight: 300,
21012
- color: "var(--brand-text-muted)",
21013
- maxWidth: "340px"
19765
+ ),
19766
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19767
+ ]
19768
+ }
19769
+ ),
19770
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
19771
+ LinkPopover,
19772
+ {
19773
+ panelRef: linkPopoverPanelRef,
19774
+ portalContainer: dialogPortalContainer,
19775
+ open: true,
19776
+ mode: linkPopover.mode ?? "edit",
19777
+ pages: sitePages,
19778
+ sections: currentSections,
19779
+ sectionsByPath,
19780
+ initialTarget: linkPopover.target,
19781
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19782
+ onClose: closeLinkPopover,
19783
+ onSubmit: handleLinkPopoverSubmit
21014
19784
  },
21015
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21016
- children: "This page doesn't have any content yet."
21017
- }
21018
- )
21019
- ] });
19785
+ linkPopover.key
19786
+ ) : null,
19787
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
19788
+ FloatingPanel,
19789
+ {
19790
+ open: true,
19791
+ title: floatingPanel.title,
19792
+ context: floatingPanel.context,
19793
+ position: floatingPanelPos,
19794
+ onPositionChange: setFloatingPanelPos,
19795
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19796
+ onClose: closeFloatingPanelOnly,
19797
+ children: /* @__PURE__ */ jsx33(
19798
+ SocialsDisplayPanel,
19799
+ {
19800
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19801
+ onChange: (next) => {
19802
+ changeSocialsDisplay(floatingPanel.row, next);
19803
+ setFloatingPanel({ ...floatingPanel });
19804
+ }
19805
+ }
19806
+ )
19807
+ }
19808
+ ) : null
19809
+ ] }),
19810
+ bridgeRoot
19811
+ ) : null;
21020
19812
  }
21021
19813
  export {
21022
19814
  AI_DEFAULT_BRAND,
@@ -21034,7 +19826,6 @@ export {
21034
19826
  DropdownMenuItem,
21035
19827
  DropdownMenuSeparator,
21036
19828
  DropdownMenuTrigger,
21037
- EmptySection,
21038
19829
  ItemActionToolbar,
21039
19830
  ItemInteractionLayer,
21040
19831
  LinkEditorPanel,