@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.cjs CHANGED
@@ -46,7 +46,6 @@ __export(index_exports, {
46
46
  DropdownMenuItem: () => DropdownMenuItem,
47
47
  DropdownMenuSeparator: () => DropdownMenuSeparator,
48
48
  DropdownMenuTrigger: () => DropdownMenuTrigger,
49
- EmptySection: () => EmptySection,
50
49
  ItemActionToolbar: () => ItemActionToolbar,
51
50
  ItemInteractionLayer: () => ItemInteractionLayer,
52
51
  LinkEditorPanel: () => LinkEditorPanel,
@@ -75,7 +74,7 @@ __export(index_exports, {
75
74
  module.exports = __toCommonJS(index_exports);
76
75
 
77
76
  // src/OhhwellsBridge.tsx
78
- var import_react17 = __toESM(require("react"), 1);
77
+ var import_react16 = __toESM(require("react"), 1);
79
78
  var import_client2 = require("react-dom/client");
80
79
  var import_react_dom3 = require("react-dom");
81
80
 
@@ -157,12 +156,7 @@ function parseAiSectionsState(raw) {
157
156
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
158
157
  }));
159
158
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
160
- return {
161
- v: 1,
162
- sections,
163
- ...removed.length ? { removed } : {},
164
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
165
- };
159
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
166
160
  } catch {
167
161
  return EMPTY_AI_SECTIONS;
168
162
  }
@@ -175,7 +169,6 @@ function applyTreeToState(state, payload) {
175
169
  const entry = {
176
170
  id: payload.id,
177
171
  label: payload.label ?? "Generated section",
178
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
179
172
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
180
173
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
181
174
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -198,317 +191,6 @@ function deleteSectionFromState(state, sectionId) {
198
191
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
199
192
  }
200
193
 
201
- // src/lib/brand-chrome.ts
202
- var BRAND_NAME_KEY = "__ohw_brand_name";
203
- var BRAND_TITLE_KEY = "__ohw_site_title";
204
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
205
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
206
- BRAND_NAME_KEY,
207
- BRAND_TITLE_KEY,
208
- BRAND_FAVICON_LETTER_KEY
209
- ]);
210
- function upsertMeta(selector, attr, token, value) {
211
- let el = document.head.querySelector(selector);
212
- if (!el) {
213
- el = document.createElement("meta");
214
- el.setAttribute(attr, token);
215
- document.head.appendChild(el);
216
- }
217
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
218
- }
219
- function escapeXml(value) {
220
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
221
- }
222
- function applyLetterFavicon(letter) {
223
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
224
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
225
- let link = document.head.querySelector('link[rel="icon"]');
226
- if (!link) {
227
- link = document.createElement("link");
228
- link.rel = "icon";
229
- document.head.appendChild(link);
230
- }
231
- link.type = "image/svg+xml";
232
- if (link.href !== href) link.href = href;
233
- }
234
- function applyBrandChrome(content) {
235
- const name = content[BRAND_NAME_KEY];
236
- if (typeof name === "string" && name.length > 0) {
237
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
238
- if (el.textContent !== name) el.textContent = name;
239
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
240
- });
241
- }
242
- const title = content[BRAND_TITLE_KEY];
243
- if (typeof title === "string" && title.length > 0) {
244
- if (document.title !== title) document.title = title;
245
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
246
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
247
- }
248
- const letter = content[BRAND_FAVICON_LETTER_KEY];
249
- if (typeof letter === "string" && letter.length > 0) {
250
- applyLetterFavicon(letter);
251
- }
252
- }
253
-
254
- // src/lib/brand-kit.ts
255
- var BRAND_KIT_KEY = "__ohw_brand";
256
- var BRAND_VAR_PREFIX = "--ohw-brand-";
257
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
258
- (role) => `${BRAND_VAR_PREFIX}${role}`
259
- );
260
- var FONT_VARS = {
261
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
262
- body: ["--font-body", "--brand-font-body"]
263
- };
264
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
265
- function brandColorVars(kit) {
266
- const { dark, primary, accent, light } = kit.palette;
267
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
268
- return {
269
- [`${BRAND_VAR_PREFIX}primary`]: primary,
270
- [`${BRAND_VAR_PREFIX}accent`]: accent,
271
- [`${BRAND_VAR_PREFIX}light`]: light,
272
- [`${BRAND_VAR_PREFIX}dark`]: dark,
273
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
274
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
275
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
276
- };
277
- }
278
- function parseBrandKit(raw) {
279
- if (!raw) return null;
280
- try {
281
- const parsed = JSON.parse(raw);
282
- const p = parsed?.palette;
283
- const f = parsed?.fonts;
284
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
285
- return null;
286
- }
287
- return {
288
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
289
- fonts: { heading: f.heading, body: f.body }
290
- };
291
- } catch {
292
- return null;
293
- }
294
- }
295
- function familyOf(stack) {
296
- const first = stack.split(",")[0]?.trim() ?? "";
297
- return first.replace(/^['"]|['"]$/g, "");
298
- }
299
- function loadBrandFonts(families) {
300
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
301
- if (unique.length === 0) return;
302
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
303
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
304
- let link = document.getElementById(BRAND_FONT_LINK_ID);
305
- if (!link) {
306
- link = document.createElement("link");
307
- link.id = BRAND_FONT_LINK_ID;
308
- link.rel = "stylesheet";
309
- document.head.appendChild(link);
310
- }
311
- if (link.href !== href) link.href = href;
312
- }
313
- function applyBrandToDom(kit) {
314
- const root = document.documentElement;
315
- if (!kit) {
316
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
317
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
318
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
319
- return;
320
- }
321
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
322
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
323
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
324
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
325
- }
326
-
327
- // src/lib/section-styles.ts
328
- var STYLE_STORE_KEY = "__ohw_styles";
329
- var STYLE_SHEET_ID = "ohw-section-styles";
330
- function parseStyleStore(raw) {
331
- if (!raw) return null;
332
- try {
333
- const parsed = JSON.parse(raw);
334
- if (parsed?.v !== 1) return null;
335
- return {
336
- v: 1,
337
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
338
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
339
- };
340
- } catch {
341
- return null;
342
- }
343
- }
344
- var BG_VALUES = {
345
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
346
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
347
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
348
- };
349
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
350
- function styleSheetCss() {
351
- const rules = [];
352
- for (const [tone, value] of Object.entries(BG_VALUES)) {
353
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
354
- }
355
- rules.push(
356
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
357
- );
358
- rules.push(
359
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
360
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
361
- );
362
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
363
- rules.push(
364
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
365
- );
366
- }
367
- rules.push(
368
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
369
- );
370
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
371
- rules.push(
372
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
373
- );
374
- }
375
- const pad = { tight: 40, balanced: 64, airy: 96 };
376
- for (const [spacing, px] of Object.entries(pad)) {
377
- rules.push(
378
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
379
- );
380
- }
381
- return rules.join("\n");
382
- }
383
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
384
- function loadStyleFonts(families) {
385
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
386
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
387
- if (unique.length === 0) {
388
- existing?.remove();
389
- return;
390
- }
391
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
392
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
393
- let link = existing;
394
- if (!link) {
395
- link = document.createElement("link");
396
- link.id = STYLE_FONT_LINK_ID;
397
- link.rel = "stylesheet";
398
- document.head.appendChild(link);
399
- }
400
- if (link.href !== href) link.href = href;
401
- }
402
- var SECTION_ATTRS = {
403
- sectionBackground: "data-ohw-style-bg",
404
- textDistribution: "data-ohw-style-distribution",
405
- headlineScale: "data-ohw-style-headline",
406
- imageAspect: "data-ohw-style-aspect",
407
- spacing: "data-ohw-style-spacing"
408
- };
409
- var NODE_WROTE_ATTR = "data-ohw-style-node";
410
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
411
- function saveInline(el, prop) {
412
- const attr = `data-ohw-style-prev-${prop}`;
413
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
414
- }
415
- function restoreInline(el, prop) {
416
- const attr = `data-ohw-style-prev-${prop}`;
417
- if (!el.hasAttribute(attr)) return;
418
- const prev = el.getAttribute(attr) ?? "";
419
- if (prev) el.style.setProperty(prop, prev);
420
- else el.style.removeProperty(prop);
421
- el.removeAttribute(attr);
422
- }
423
- function ensureStyleSheet() {
424
- let el = document.getElementById(STYLE_SHEET_ID);
425
- if (!el) {
426
- el = document.createElement("style");
427
- el.id = STYLE_SHEET_ID;
428
- document.head.appendChild(el);
429
- }
430
- const css = styleSheetCss();
431
- if (el.textContent !== css) el.textContent = css;
432
- }
433
- function clearSectionAttrs(root) {
434
- for (const attr of Object.values(SECTION_ATTRS)) {
435
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
436
- }
437
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
438
- restoreInline(el, "background");
439
- el.removeAttribute("data-ohw-style-bgcolor");
440
- }
441
- }
442
- function clearNodeProps(root) {
443
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
444
- const h = el;
445
- for (const prop of NODE_PROPS) restoreInline(h, prop);
446
- h.removeAttribute(NODE_WROTE_ATTR);
447
- }
448
- }
449
- function buttonSurfaceOf(el) {
450
- return el.closest("a, button") ?? el;
451
- }
452
- function applyStylesToDom(store) {
453
- ensureStyleSheet();
454
- clearSectionAttrs(document);
455
- clearNodeProps(document);
456
- loadStyleFonts(
457
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
458
- );
459
- if (!store) return;
460
- for (const [sectionId, override] of Object.entries(store.sections)) {
461
- const sections = document.querySelectorAll(
462
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
463
- );
464
- for (const section of Array.from(sections)) {
465
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
466
- const value = override[prop];
467
- if (value === void 0) continue;
468
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
469
- section.setAttribute(attr, String(value).replace(":", "-"));
470
- }
471
- if (override.sectionBackgroundColor !== void 0) {
472
- saveInline(section, "background");
473
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
474
- section.setAttribute("data-ohw-style-bgcolor", "");
475
- }
476
- }
477
- }
478
- for (const [key, override] of Object.entries(store.nodes)) {
479
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
480
- for (const el of Array.from(nodes)) {
481
- if (override.color !== void 0) {
482
- saveInline(el, "color");
483
- el.style.setProperty("color", override.color, "important");
484
- el.setAttribute(NODE_WROTE_ATTR, "");
485
- }
486
- if (override.fontFamily !== void 0) {
487
- saveInline(el, "font-family");
488
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
489
- el.setAttribute(NODE_WROTE_ATTR, "");
490
- }
491
- if (override.fontSize !== void 0) {
492
- saveInline(el, "font-size");
493
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
494
- el.setAttribute(NODE_WROTE_ATTR, "");
495
- }
496
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
497
- const surface = buttonSurfaceOf(el);
498
- if (override.buttonBackground !== void 0) {
499
- saveInline(surface, "background");
500
- surface.style.setProperty("background", override.buttonBackground, "important");
501
- }
502
- if (override.buttonText !== void 0) {
503
- saveInline(surface, "color");
504
- surface.style.setProperty("color", override.buttonText, "important");
505
- }
506
- surface.setAttribute(NODE_WROTE_ATTR, "");
507
- }
508
- }
509
- }
510
- }
511
-
512
194
  // src/ui/ai-tree/aiSectionsManager.tsx
513
195
  var import_react_dom = require("react-dom");
514
196
  var import_client = require("react-dom/client");
@@ -523,8 +205,7 @@ function lucideByName(name) {
523
205
  }
524
206
  var typeStyle = (spec, font) => ({
525
207
  fontFamily: font,
526
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
527
- fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
208
+ fontSize: spec.size,
528
209
  lineHeight: spec.line,
529
210
  fontWeight: spec.weight
530
211
  });
@@ -539,36 +220,6 @@ var FEATURE_LINE_CSS = [
539
220
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
540
221
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
541
222
  ].join("");
542
- function hexLuminance(color) {
543
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
544
- if (!m) return null;
545
- const [r2, g, b] = [0, 2, 4].map((i) => {
546
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
547
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
548
- });
549
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
550
- }
551
- function hexContrast(a, b) {
552
- const la = hexLuminance(a);
553
- const lb = hexLuminance(b);
554
- if (la === null || lb === null) return null;
555
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
556
- return (hi + 0.05) / (lo + 0.05);
557
- }
558
- function accentBandContext(brand) {
559
- const p = brand.palette;
560
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
561
- if (lightWins) {
562
- return {
563
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
564
- buttonLabel: p.primary
565
- };
566
- }
567
- return {
568
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
569
- buttonLabel: p.light
570
- };
571
- }
572
223
  function textAttrs(ctx, path) {
573
224
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
574
225
  }
@@ -581,8 +232,6 @@ var AI_RESPONSIVE_CSS = [
581
232
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
582
233
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
583
234
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
584
- " [data-ai-responsive] { overflow-x: hidden; }",
585
- " [data-ai-responsive] img { max-width: 100%; }",
586
235
  "}"
587
236
  ].join("\n");
588
237
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -660,7 +309,7 @@ function ButtonEl({
660
309
  }) {
661
310
  const secondary = slots.variant === "secondary";
662
311
  const href = str(slots.href);
663
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
312
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
664
313
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
665
314
  "a",
666
315
  {
@@ -676,7 +325,7 @@ function ButtonEl({
676
325
  textDecoration: "none",
677
326
  cursor: "pointer",
678
327
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
679
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
328
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
680
329
  },
681
330
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
682
331
  }
@@ -1578,14 +1227,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1578
1227
  return null;
1579
1228
  }
1580
1229
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1581
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1582
- const blockBrand = band?.brand ?? resolvedBrand;
1583
1230
  const ctx = {
1584
- brand: blockBrand,
1231
+ brand: resolvedBrand,
1585
1232
  resolveMedia: resolveMedia ?? (() => null),
1586
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1587
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1588
- ...band ? { buttonLabel: band.buttonLabel } : {}
1233
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1234
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1589
1235
  };
1590
1236
  const settings = tree.settings ?? {};
1591
1237
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1593,20 +1239,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1593
1239
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1594
1240
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1595
1241
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1596
- const toneBackground = (() => {
1597
- const { dark, primary, light } = resolvedBrand.palette;
1598
- switch (settings.sectionBackground) {
1599
- case "surface":
1600
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1601
- case "accent":
1602
- return primary;
1603
- case "accent-soft":
1604
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1605
- default:
1606
- return void 0;
1607
- }
1608
- })();
1609
- const distributed = !isOverlay && settings.textDistribution;
1610
1242
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1611
1243
  "section",
1612
1244
  {
@@ -1616,11 +1248,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1616
1248
  style: {
1617
1249
  position: "relative",
1618
1250
  padding: `${pad}px 0`,
1619
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1251
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1620
1252
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1621
1253
  backgroundSize: "cover",
1622
- backgroundPosition: "center",
1623
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1254
+ backgroundPosition: "center"
1624
1255
  },
1625
1256
  children: [
1626
1257
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
@@ -1644,24 +1275,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1644
1275
  display: "grid",
1645
1276
  gridTemplateColumns: "repeat(12, 1fr)",
1646
1277
  gap: AI_TREE_TOKENS.spacing6,
1647
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1278
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1648
1279
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1649
1280
  },
1650
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1651
- "div",
1652
- {
1653
- "data-ai-cell": "",
1654
- style: {
1655
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1656
- minWidth: 0,
1657
- // space-between: each column becomes a flex column whose content spreads over
1658
- // the full row height instead of clumping at the top.
1659
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1660
- },
1661
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1662
- },
1663
- b
1664
- ))
1281
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1665
1282
  },
1666
1283
  r2
1667
1284
  ))
@@ -1677,36 +1294,17 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1677
1294
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1678
1295
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1679
1296
  var REMOVED_ATTR = "data-ohw-ai-removed";
1680
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1681
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1682
- function readRootVar(name) {
1683
- if (typeof document === "undefined") return "";
1684
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1685
- }
1686
- function deriveBrandOverride() {
1687
- const dark = readRootVar("--ohw-brand-dark");
1688
- const primary = readRootVar("--ohw-brand-primary");
1689
- const light = readRootVar("--ohw-brand-light");
1690
- if (!dark || !primary || !light) return null;
1691
- const accent = readRootVar("--ohw-brand-accent");
1692
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1693
- const body = readRootVar("--font-body");
1694
- return {
1695
- palette: { dark, primary, accent: accent || dark, light },
1696
- fonts: {
1697
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1698
- body: body || AI_DEFAULT_BRAND.fonts.body
1699
- }
1700
- };
1701
- }
1702
1297
  function deriveTemplateBrand() {
1703
- const dark = readRootVar("--color-dark");
1704
- const primary = readRootVar("--color-primary");
1705
- const light = readRootVar("--color-light");
1298
+ if (typeof document === "undefined") return null;
1299
+ const cs = getComputedStyle(document.documentElement);
1300
+ const read = (name) => cs.getPropertyValue(name).trim();
1301
+ const dark = read("--color-dark");
1302
+ const primary = read("--color-primary");
1303
+ const light = read("--color-light");
1706
1304
  if (!dark || !primary || !light) return null;
1707
- const accent = readRootVar("--color-accent");
1708
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1709
- const body = readRootVar("--font-body");
1305
+ const accent = read("--color-accent");
1306
+ const heading = read("--font-heading") || read("--font-display");
1307
+ const body = read("--font-body");
1710
1308
  return {
1711
1309
  palette: { dark, primary, accent: accent || dark, light },
1712
1310
  fonts: {
@@ -1778,24 +1376,6 @@ function syncRemovedSections(state) {
1778
1376
  }
1779
1377
  }
1780
1378
  }
1781
- function syncTemplateHidden(state, pageHasSections) {
1782
- const hide = state.hideTemplate === true && pageHasSections;
1783
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1784
- if (!hide) {
1785
- el.style.removeProperty("display");
1786
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1787
- }
1788
- }
1789
- if (!hide) return;
1790
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1791
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1792
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1793
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1794
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1795
- el.style.display = "none";
1796
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1797
- }
1798
- }
1799
1379
  function syncReplacedOriginals(state) {
1800
1380
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1801
1381
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1816,12 +1396,8 @@ function syncReplacedOriginals(state) {
1816
1396
  }
1817
1397
  function applyAiSectionsToDom(state, options) {
1818
1398
  if (typeof document === "undefined") return;
1819
- const brandOverride = deriveBrandOverride();
1820
1399
  const templateBrand = deriveTemplateBrand();
1821
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1822
- const pagePath = window.location.pathname;
1823
- const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
1824
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1400
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1825
1401
  for (const [id, section] of mounted) {
1826
1402
  if (!activeIds.has(id)) {
1827
1403
  section.root.unmount();
@@ -1829,8 +1405,8 @@ function applyAiSectionsToDom(state, options) {
1829
1405
  mounted.delete(id);
1830
1406
  }
1831
1407
  }
1832
- for (const entry of pageSections) {
1833
- const serialized = JSON.stringify(entry) + brandKey;
1408
+ for (const entry of state.sections) {
1409
+ const serialized = JSON.stringify(entry);
1834
1410
  const existing = mounted.get(entry.id);
1835
1411
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1836
1412
  continue;
@@ -1844,7 +1420,6 @@ function applyAiSectionsToDom(state, options) {
1844
1420
  mounted.delete(entry.id);
1845
1421
  }
1846
1422
  container.setAttribute("data-ohw-section", entry.id);
1847
- container.setAttribute("data-ohw-instance", entry.id);
1848
1423
  container.setAttribute("data-ohw-section-label", entry.label);
1849
1424
  placeContainer(container, entry);
1850
1425
  const root = mounted.get(entry.id)?.root ?? (0, import_client.createRoot)(container);
@@ -1855,7 +1430,7 @@ function applyAiSectionsToDom(state, options) {
1855
1430
  AiTreeRenderer,
1856
1431
  {
1857
1432
  tree: entry.tree,
1858
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1433
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1859
1434
  resolveMedia,
1860
1435
  editKeyPrefix: `ai.${entry.id}`
1861
1436
  }
@@ -1866,7 +1441,6 @@ function applyAiSectionsToDom(state, options) {
1866
1441
  }
1867
1442
  syncReplacedOriginals(state);
1868
1443
  syncRemovedSections(state);
1869
- syncTemplateHidden(state, pageSections.length > 0);
1870
1444
  }
1871
1445
 
1872
1446
  // src/useLinkHrefGuardian.ts
@@ -2473,7 +2047,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2473
2047
  const autoId = (0, import_react5.useId)();
2474
2048
  const insertAfter = insertAfterProp ?? autoId;
2475
2049
  const [schedule, setSchedule] = (0, import_react5.useState)(null);
2476
- const [loading, setLoading] = (0, import_react5.useState)(initialScheduleId !== null);
2050
+ const [loading, setLoading] = (0, import_react5.useState)(true);
2477
2051
  const [inEditor, setInEditor] = (0, import_react5.useState)(false);
2478
2052
  const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
2479
2053
  const [modalState, setModalState] = (0, import_react5.useState)(null);
@@ -2647,10 +2221,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2647
2221
  "*"
2648
2222
  );
2649
2223
  };
2224
+ if (!inEditor && !loading && !schedule) return null;
2650
2225
  const sectionId = `scheduling-${insertAfter}`;
2651
- if (!inEditor && !loading && !schedule) {
2652
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2653
- }
2654
2226
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2655
2227
  "section",
2656
2228
  {
@@ -7181,7 +6753,6 @@ function applyFieldType(wrapper, type) {
7181
6753
  if (inputType) input.type = inputType;
7182
6754
  shedSize(input);
7183
6755
  applyDefaults(input);
7184
- requireIfEmail(wrapper, type);
7185
6756
  return;
7186
6757
  }
7187
6758
  const next = document.createElement(tag);
@@ -7194,11 +6765,6 @@ function applyFieldType(wrapper, type) {
7194
6765
  if (type === "long-text") next.setAttribute("rows", "4");
7195
6766
  input.replaceWith(next);
7196
6767
  applyDefaults(next);
7197
- requireIfEmail(wrapper, type);
7198
- }
7199
- function requireIfEmail(wrapper, type) {
7200
- if (type !== "email") return;
7201
- setFieldRequired(wrapper, true);
7202
6768
  }
7203
6769
  var REQUIRED_MARK_ATTR = "data-ohw-field-required";
7204
6770
  function fieldLabelText(label) {
@@ -7281,7 +6847,6 @@ function insertField(form, type) {
7281
6847
  const label = ensureFieldLabel(wrapper, key);
7282
6848
  label.textContent = defaults.label;
7283
6849
  label.setAttribute("data-ohw-key", `${key}-label`);
7284
- requireIfEmail(wrapper, type);
7285
6850
  return wrapper;
7286
6851
  }
7287
6852
  function duplicateField(form, wrapper) {
@@ -7423,7 +6988,7 @@ function FormFieldToolbar({
7423
6988
  "aria-pressed": required,
7424
6989
  onClick: onRequiredToggle,
7425
6990
  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"),
7426
- "data-ohw-field-required-toggle": "",
6991
+ "data-ohw-field-required": "",
7427
6992
  children: [
7428
6993
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
7429
6994
  "Required"
@@ -7558,17 +7123,13 @@ function MediaOverlay({
7558
7123
  hover,
7559
7124
  isUploading,
7560
7125
  fadingOut = false,
7561
- selected = false,
7562
- hovered = false,
7563
7126
  onFadeOutComplete,
7564
7127
  onReplace,
7565
- onSelect,
7566
7128
  onVideoSettingsChange
7567
7129
  }) {
7568
7130
  const { rect } = hover;
7569
7131
  const skeletonRef = React7.useRef(null);
7570
7132
  const isVideo = hover.elementType === "video";
7571
- const showChrome = !selected || hovered;
7572
7133
  const autoplay = hover.videoAutoplay ?? true;
7573
7134
  const muted = hover.videoMuted ?? true;
7574
7135
  const box = {
@@ -7603,7 +7164,7 @@ function MediaOverlay({
7603
7164
  }
7604
7165
  );
7605
7166
  }
7606
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7167
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7607
7168
  "div",
7608
7169
  {
7609
7170
  "data-ohw-bridge": "",
@@ -7673,13 +7234,11 @@ function MediaOverlay({
7673
7234
  // in-document, pointer-events does it natively. The button below opts back in, so
7674
7235
  // Replace still works.
7675
7236
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7676
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7677
- // than hovered. Hover keeps the existing tinted preview.
7678
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7679
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7237
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7238
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7680
7239
  },
7681
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7682
- children: showChrome && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7240
+ onClick: () => onReplace(hover.key),
7241
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7683
7242
  Button,
7684
7243
  {
7685
7244
  "data-ohw-media-overlay": "",
@@ -7768,9 +7327,6 @@ var import_lucide_react7 = require("lucide-react");
7768
7327
 
7769
7328
  // src/lib/sections.ts
7770
7329
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7771
- function isChromeSection(el) {
7772
- return el.matches("header, nav, footer, aside");
7773
- }
7774
7330
  function titleCaseSectionId(id) {
7775
7331
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7776
7332
  }
@@ -7781,8 +7337,6 @@ function parseSectionsFromRoot(root) {
7781
7337
  const id = el.getAttribute("data-ohw-section") ?? "";
7782
7338
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7783
7339
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7784
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7785
- continue;
7786
7340
  seen.add(id);
7787
7341
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7788
7342
  sections.push({ id, label });
@@ -7800,12 +7354,8 @@ function parseSectionsFromHtml(html) {
7800
7354
 
7801
7355
  // src/ui/ai-section/AiSectionOverlay.tsx
7802
7356
  var import_jsx_runtime17 = require("react/jsx-runtime");
7803
- function findSectionElement(instanceId) {
7804
- const escaped = CSS.escape(instanceId);
7805
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7806
- }
7807
- function readRect(instanceId) {
7808
- const el = findSectionElement(instanceId);
7357
+ function readRect(sectionId) {
7358
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7809
7359
  if (!el) return null;
7810
7360
  const r2 = el.getBoundingClientRect();
7811
7361
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7828,7 +7378,7 @@ function useLiveSectionRect(sectionId) {
7828
7378
  const opts = { capture: true, passive: true };
7829
7379
  window.addEventListener("scroll", update, opts);
7830
7380
  window.addEventListener("resize", update);
7831
- const el = findSectionElement(sectionId);
7381
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7832
7382
  const ro = el ? new ResizeObserver(update) : null;
7833
7383
  if (el && ro) ro.observe(el);
7834
7384
  const interval = setInterval(update, 500);
@@ -7841,14 +7391,6 @@ function useLiveSectionRect(sectionId) {
7841
7391
  }, [sectionId]);
7842
7392
  return rect;
7843
7393
  }
7844
- function computeSectionBoundaryFlags(instanceId) {
7845
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7846
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7847
- );
7848
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7849
- if (index === -1) return { isFirst: true, isLast: true };
7850
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7851
- }
7852
7394
  var PRIMARY2 = "#0885FE";
7853
7395
  function edgeAwareRadius(rect) {
7854
7396
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7922,7 +7464,6 @@ function AiSectionOverlay({
7922
7464
  }) {
7923
7465
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
7924
7466
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
7925
- const [reviewButtonsHidden, setReviewButtonsHidden] = (0, import_react8.useState)(false);
7926
7467
  const reviewIdRef = (0, import_react8.useRef)(null);
7927
7468
  reviewIdRef.current = reviewId;
7928
7469
  const selectedIdRef = (0, import_react8.useRef)(null);
@@ -7931,7 +7472,7 @@ function AiSectionOverlay({
7931
7472
  (el) => {
7932
7473
  postToParent2({
7933
7474
  type: "ow:section-selected",
7934
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7475
+ sectionId: el?.dataset.ohwSection ?? null,
7935
7476
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7936
7477
  });
7937
7478
  },
@@ -7940,7 +7481,7 @@ function AiSectionOverlay({
7940
7481
  const selectFromElement = (0, import_react8.useCallback)(
7941
7482
  (el, options) => {
7942
7483
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7943
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7484
+ const id = sectionEl?.dataset.ohwSection ?? null;
7944
7485
  if (id === selectedIdRef.current) return;
7945
7486
  setSelectedId(id);
7946
7487
  if (options?.report !== false) report(sectionEl);
@@ -7981,10 +7522,9 @@ function AiSectionOverlay({
7981
7522
  }
7982
7523
  const found = readRect(sectionId) != null;
7983
7524
  setReviewId(found ? sectionId : null);
7984
- setReviewButtonsHidden(e.data.hideButtons === true);
7985
7525
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7986
7526
  if (found) {
7987
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7527
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7988
7528
  }
7989
7529
  }
7990
7530
  };
@@ -8003,7 +7543,7 @@ function AiSectionOverlay({
8003
7543
  return;
8004
7544
  }
8005
7545
  const sec = t.closest("[data-ohw-section]");
8006
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7546
+ setHoveredId(sec?.dataset.ohwSection ?? null);
8007
7547
  };
8008
7548
  const onLeave = () => setHoveredId(null);
8009
7549
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -8035,30 +7575,9 @@ function AiSectionOverlay({
8035
7575
  },
8036
7576
  [postToParent2]
8037
7577
  );
8038
- const activeSelectionId = reviewId ? null : selectedId;
8039
- const selectionRect = useLiveSectionRect(activeSelectionId);
7578
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
8040
7579
  const reviewRect = useLiveSectionRect(reviewId);
8041
7580
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
8042
- (0, import_react8.useEffect)(() => {
8043
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
8044
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
8045
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
8046
- return;
8047
- }
8048
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
8049
- postToParent2({
8050
- type: "ow:section-rect",
8051
- instanceId: activeSelectionId,
8052
- rect: {
8053
- top: selectionRect.top + window.scrollY,
8054
- left: selectionRect.left + window.scrollX,
8055
- width: selectionRect.width,
8056
- height: selectionRect.height
8057
- },
8058
- isFirst,
8059
- isLast
8060
- });
8061
- }, [activeSelectionId, selectionRect, postToParent2]);
8062
7581
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
8063
7582
  hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8064
7583
  "div",
@@ -8109,16 +7628,13 @@ function AiSectionOverlay({
8109
7628
  border: `2px solid ${PRIMARY2}`,
8110
7629
  borderRadius: edgeAwareRadius(reviewRect),
8111
7630
  zIndex: 2147483200,
8112
- // The veil itself: swallows clicks so the section stays locked until decided. This
8113
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8114
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8115
- // Accept/Discard resolves to the media beneath and opens the file picker.
7631
+ // The veil itself: swallows clicks so the section stays locked until decided.
8116
7632
  background: "rgba(8, 133, 254, 0.04)",
8117
7633
  pointerEvents: "auto",
8118
7634
  cursor: "default"
8119
7635
  },
8120
7636
  onClick: (e) => e.stopPropagation(),
8121
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7637
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8122
7638
  "div",
8123
7639
  {
8124
7640
  style: {
@@ -8143,58 +7659,6 @@ function AiSectionOverlay({
8143
7659
 
8144
7660
  // src/lib/section-instances.ts
8145
7661
  var SECTION_ORDER_KEY = "__ohw_section_order";
8146
- function topLevelSections() {
8147
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8148
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8149
- );
8150
- }
8151
- function instanceIdOf(el) {
8152
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8153
- }
8154
- function planSectionMove(instanceId, targetIndex, currentPath) {
8155
- const sections = topLevelSections();
8156
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8157
- if (index === -1) return null;
8158
- const dragged = sections[index];
8159
- const others = sections.filter((_, i) => i !== index);
8160
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8161
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8162
- return reordered.map((el, order) => ({
8163
- instanceId: instanceIdOf(el),
8164
- type: el.getAttribute("data-ohw-section") ?? "",
8165
- order,
8166
- pagePath: currentPath
8167
- }));
8168
- }
8169
- function moveSectionInstance(instanceId, direction, currentPath) {
8170
- const sections = topLevelSections();
8171
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8172
- if (index === -1) return null;
8173
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8174
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8175
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8176
- if (!entries) return null;
8177
- applyPersistedOrder(entries);
8178
- return entries;
8179
- }
8180
- function applyPersistedOrder(entries) {
8181
- if (entries.length === 0) return;
8182
- const sections = topLevelSections();
8183
- if (sections.length === 0) return;
8184
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8185
- const ordered = [...sections].sort((a, b) => {
8186
- const aOrder = orderIndex.get(instanceIdOf(a));
8187
- const bOrder = orderIndex.get(instanceIdOf(b));
8188
- if (aOrder === void 0 && bOrder === void 0) return 0;
8189
- if (aOrder === void 0) return 1;
8190
- if (bOrder === void 0) return -1;
8191
- return aOrder - bOrder;
8192
- });
8193
- const parent = sections[0].parentElement;
8194
- if (!parent) return;
8195
- const anchor = sections[sections.length - 1].nextSibling;
8196
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8197
- }
8198
7662
  function getPageSectionOrderEntries(raw, currentPath) {
8199
7663
  if (!raw) return [];
8200
7664
  try {
@@ -8232,7 +7696,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8232
7696
  rekeySectionSubtree(clone, entry.instanceId);
8233
7697
  original.insertAdjacentElement("afterend", clone);
8234
7698
  }
8235
- applyPersistedOrder(entries);
8236
7699
  }
8237
7700
 
8238
7701
  // src/OhhwellsBridge.tsx
@@ -12077,12 +11540,17 @@ function deleteFooterColumn(column) {
12077
11540
  }
12078
11541
 
12079
11542
  // src/lib/logo-identity.ts
12080
- var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
12081
- var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
11543
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text", "nav-logo", "logo"];
11544
+ var LOGO_IMAGE_KEYS = [
11545
+ "nav-logo-image",
11546
+ "footer-logo",
11547
+ "footer-logo-image",
11548
+ "logo-image",
11549
+ "footer-logo-img"
11550
+ ];
12082
11551
  var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
12083
11552
  var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
12084
11553
  var LOGO_ALT_KEY = "logo-alt";
12085
- var LOGO_IMAGE_URL_KEY = "nav-logo-image";
12086
11554
  var PLACEHOLDER_BUSINESS_NAME = "Business name";
12087
11555
  function resolveLogoDisplayText(text) {
12088
11556
  const trimmed = (text ?? "").trim();
@@ -12102,6 +11570,21 @@ function ensureLogoHrefKey(root) {
12102
11570
  if (root.hasAttribute("data-ohw-href-key")) return;
12103
11571
  root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
12104
11572
  }
11573
+ function logoTextElement(root) {
11574
+ const SELECTOR = '[data-ohw-editable="plain"], [data-ohw-editable="text"]';
11575
+ if (root.matches(SELECTOR)) return root;
11576
+ const marked = root.querySelector(SELECTOR);
11577
+ if (marked) return marked;
11578
+ const hasOwnText = Array.from(root.childNodes).some(
11579
+ (node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
11580
+ );
11581
+ return hasOwnText ? root : null;
11582
+ }
11583
+ function logoRootImage(root) {
11584
+ const img = root.querySelector("img");
11585
+ const src = img?.getAttribute("src")?.trim() ?? "";
11586
+ return img && src && img.style.display !== "none" ? img : null;
11587
+ }
12105
11588
  function applyLogoIdentity(text, isPlaceholder) {
12106
11589
  const display = resolveLogoDisplayText(text);
12107
11590
  const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
@@ -12119,6 +11602,9 @@ function applyLogoIdentity(text, isPlaceholder) {
12119
11602
  document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
12120
11603
  if (placeholder) el.setAttribute("data-ohw-placeholder", "");
12121
11604
  else el.removeAttribute("data-ohw-placeholder");
11605
+ if (logoRootImage(el)) return;
11606
+ const textEl = logoTextElement(el);
11607
+ if (textEl && textEl.textContent !== display) textEl.textContent = display;
12122
11608
  });
12123
11609
  return display;
12124
11610
  }
@@ -12129,7 +11615,7 @@ function applyLogoImage(url, alt) {
12129
11615
  const imageKey = imageKeyForRoot(root);
12130
11616
  const textKey = textKeyForRoot(root);
12131
11617
  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");
12132
- let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
11618
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]') ?? logoTextElement(root);
12133
11619
  if (url) {
12134
11620
  if (!img) {
12135
11621
  img = document.createElement("img");
@@ -12151,7 +11637,11 @@ function applyLogoImage(url, alt) {
12151
11637
  img.src = url;
12152
11638
  img.alt = displayAlt;
12153
11639
  img.style.display = "block";
12154
- if (textEl) textEl.style.display = "none";
11640
+ if (textEl === root) {
11641
+ Array.from(root.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).forEach((node) => node.remove());
11642
+ } else if (textEl) {
11643
+ textEl.style.display = "none";
11644
+ }
12155
11645
  root.removeAttribute("data-ohw-placeholder");
12156
11646
  return;
12157
11647
  }
@@ -12200,6 +11690,13 @@ function readLogoIdentityFromDom() {
12200
11690
  }
12201
11691
  let text = PLACEHOLDER_BUSINESS_NAME;
12202
11692
  let isPlaceholder = true;
11693
+ const rootWithText = Array.from(
11694
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
11695
+ ).find((root) => logoTextElement(root)?.textContent?.trim());
11696
+ if (rootWithText) {
11697
+ text = logoTextElement(rootWithText).textContent.trim();
11698
+ isPlaceholder = rootWithText.hasAttribute("data-ohw-placeholder") || text === PLACEHOLDER_BUSINESS_NAME;
11699
+ }
12203
11700
  for (const key of LOGO_TEXT_KEYS) {
12204
11701
  const el = document.querySelector(`[data-ohw-key="${key}"]`);
12205
11702
  if (el?.textContent?.trim()) {
@@ -12230,7 +11727,7 @@ function applyLogoFromContent(content) {
12230
11727
  if (!hasLogoIdentity) return false;
12231
11728
  const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
12232
11729
  const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
12233
- const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11730
+ const rawLogoImage = LOGO_IMAGE_KEYS.map((key) => content[key]).find((value) => typeof value === "string" && value.trim()) ?? null;
12234
11731
  const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
12235
11732
  const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
12236
11733
  const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
@@ -12365,7 +11862,6 @@ function readLogoSizeState(content, placement) {
12365
11862
  function getLogoElement(el) {
12366
11863
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12367
11864
  if (marked) return marked;
12368
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12369
11865
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12370
11866
  if (!root) return null;
12371
11867
  const anchor = el.closest("a");
@@ -13230,449 +12726,122 @@ function useNavItemDrag({
13230
12726
  };
13231
12727
  }
13232
12728
 
13233
- // src/useSectionDrag.ts
13234
- var import_react15 = require("react");
12729
+ // src/ui/footer-container-chrome.tsx
12730
+ var import_lucide_react15 = require("lucide-react");
12731
+ var import_jsx_runtime29 = require("react/jsx-runtime");
12732
+ function FooterContainerChrome({
12733
+ rect,
12734
+ onAdd,
12735
+ addDisabled = false
12736
+ }) {
12737
+ const chromeGap = 6;
12738
+ const buttonMargin = 7;
12739
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12740
+ "div",
12741
+ {
12742
+ "data-ohw-footer-container-chrome": "",
12743
+ "data-ohw-bridge": "",
12744
+ className: "pointer-events-none fixed z-[2147483647]",
12745
+ style: {
12746
+ top: rect.top - chromeGap,
12747
+ left: rect.left - chromeGap,
12748
+ width: rect.width + chromeGap * 2,
12749
+ height: rect.height + chromeGap * 2
12750
+ },
12751
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12752
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12753
+ "button",
12754
+ {
12755
+ type: "button",
12756
+ "data-ohw-footer-add-button": "",
12757
+ disabled: addDisabled,
12758
+ 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",
12759
+ style: { top: chromeGap - buttonMargin },
12760
+ "aria-label": "Add item",
12761
+ onMouseDown: (e) => {
12762
+ e.preventDefault();
12763
+ e.stopPropagation();
12764
+ },
12765
+ onClick: (e) => {
12766
+ e.preventDefault();
12767
+ e.stopPropagation();
12768
+ if (addDisabled) return;
12769
+ onAdd();
12770
+ },
12771
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12772
+ }
12773
+ ) }),
12774
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12775
+ ] })
12776
+ }
12777
+ ) });
12778
+ }
13235
12779
 
13236
- // src/lib/section-dnd.ts
13237
- function isFooterSection(el) {
13238
- return el.dataset.ohwSection === "footer";
12780
+ // src/lib/carousel.ts
12781
+ var import_react15 = require("react");
12782
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12783
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12784
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12785
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12786
+ function listCarouselKeys() {
12787
+ const keys = /* @__PURE__ */ new Set();
12788
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12789
+ const key = el.getAttribute("data-ohw-key");
12790
+ if (key) keys.add(key);
12791
+ });
12792
+ return [...keys];
13239
12793
  }
13240
- function buildSectionDropSlots(draggedInstanceId) {
13241
- const sections = topLevelSections().filter(
13242
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12794
+ function containersForKey(key) {
12795
+ return Array.from(
12796
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13243
12797
  );
13244
- const slots = [];
13245
- if (sections.length === 0) return slots;
13246
- const left = 0;
13247
- const width = document.documentElement.clientWidth;
13248
- for (let i = 0; i <= sections.length; i++) {
13249
- let y;
13250
- if (i === 0) {
13251
- y = sections[0].getBoundingClientRect().top;
13252
- } else if (i === sections.length) {
13253
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13254
- } else {
13255
- const prev = sections[i - 1].getBoundingClientRect();
13256
- const next = sections[i].getBoundingClientRect();
13257
- y = (prev.bottom + next.top) / 2;
13258
- }
13259
- slots.push({ insertIndex: i, y, left, width });
12798
+ }
12799
+ function isCarouselKey(key) {
12800
+ return containersForKey(key).length > 0;
12801
+ }
12802
+ function parseSlides(raw) {
12803
+ if (!raw) return [];
12804
+ try {
12805
+ const parsed = JSON.parse(raw);
12806
+ if (!Array.isArray(parsed)) return [];
12807
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12808
+ } catch {
12809
+ return [];
13260
12810
  }
13261
- return slots;
13262
12811
  }
13263
- function hitTestSectionDropSlot(y, slots) {
13264
- let best = null;
13265
- for (const slot of slots) {
13266
- const dist = Math.abs(y - slot.y);
13267
- if (!best || dist < best.dist) best = { slot, dist };
12812
+ function readCarouselValue(key) {
12813
+ const container = containersForKey(key)[0];
12814
+ if (!container) return [];
12815
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
12816
+ if (fromAttr.length > 0) return fromAttr;
12817
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
12818
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
12819
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
12820
+ });
12821
+ }
12822
+ function slideIndex(el) {
12823
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
12824
+ const n = raw ? parseInt(raw, 10) : NaN;
12825
+ return Number.isFinite(n) ? n : 0;
12826
+ }
12827
+ function applyCarouselValue(key, slides) {
12828
+ const value = JSON.stringify(slides);
12829
+ for (const container of containersForKey(key)) {
12830
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
12831
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
12832
+ container.dispatchEvent(
12833
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
12834
+ );
13268
12835
  }
13269
- return best?.slot ?? null;
13270
12836
  }
13271
-
13272
- // src/useSectionDrag.ts
13273
- var PRESS_THRESHOLD = 10;
13274
- var EDGE_ZONE = 60;
13275
- var MAX_AUTO_SCROLL_SPEED = 18;
13276
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13277
- "[data-ohw-toolbar]",
13278
- "[data-ohw-edit-chrome]",
13279
- "[data-ohw-item-interaction]",
13280
- "[data-ohw-drag-handle-container]",
13281
- '[data-slot="drag-handle"]',
13282
- "[data-ohw-item-toolbar-anchor]",
13283
- "[data-ohw-item-drag-surface]",
13284
- "[data-ohw-more-menu]",
13285
- '[data-slot="dropdown-menu-content"]',
13286
- '[data-slot="dropdown-menu-item"]',
13287
- "[data-ohw-state-toggle]",
13288
- "[data-ohw-max-badge]",
13289
- "[data-ohw-floating-panel]",
13290
- "[data-ohw-section-picker]",
13291
- "[data-ohw-link-popover-root]",
13292
- "[data-ohw-link-modal-root]",
13293
- "[data-ohw-link-page-dropdown]",
13294
- '[data-slot="popover-content"]',
13295
- '[data-slot="dialog-content"]',
13296
- '[data-slot="dialog-overlay"]',
13297
- "[data-ohw-ai-review]",
13298
- "[data-ohw-editable]",
13299
- "[data-ohw-editable-state]",
13300
- "[contenteditable]",
13301
- "[data-ohw-href-key]",
13302
- "[data-ohw-footer-col]",
13303
- "[data-ohw-social-label]",
13304
- "a",
13305
- "button",
13306
- '[role="button"]',
13307
- '[data-ohw-role="navbar-button"]',
13308
- '[data-ohw-role="button"]',
13309
- "[data-ohw-carousel]",
13310
- "[data-ohw-carousel-value]",
13311
- "[data-ohw-carousel-slide]",
13312
- "[data-ohw-carousel-overlay]",
13313
- "[data-ohw-media-chrome]",
13314
- "[data-ohw-media-overlay]",
13315
- "[data-ohw-media-skeleton]"
13316
- ].join(", ");
13317
- function visibleClip(ps) {
13318
- if (!ps) return null;
13319
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13320
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13321
- return { top, bottom: Math.max(top, bottom) };
13322
- }
13323
- function useSectionDrag({
13324
- isEditMode,
13325
- editContentRef,
13326
- postToParentRef,
13327
- parentScrollRef,
13328
- navDragRef,
13329
- footerDragRef,
13330
- suppressNextClickRef,
13331
- suppressClickUntilRef
13332
- }) {
13333
- const sectionDragRef = (0, import_react15.useRef)(null);
13334
- const [sectionDropSlots, setSectionDropSlots] = (0, import_react15.useState)([]);
13335
- const [activeSectionDropIndex, setActiveSectionDropIndex] = (0, import_react15.useState)(null);
13336
- const [isSectionDragging, setIsSectionDragging] = (0, import_react15.useState)(false);
13337
- const sectionPointerDragRef = (0, import_react15.useRef)(null);
13338
- const autoScrollRafRef = (0, import_react15.useRef)(null);
13339
- const autoScrollDeltaRef = (0, import_react15.useRef)(0);
13340
- const stopAutoScroll = (0, import_react15.useCallback)(() => {
13341
- if (autoScrollRafRef.current != null) {
13342
- cancelAnimationFrame(autoScrollRafRef.current);
13343
- autoScrollRafRef.current = null;
13344
- }
13345
- autoScrollDeltaRef.current = 0;
13346
- }, []);
13347
- const tickAutoScroll = (0, import_react15.useCallback)(() => {
13348
- if (!sectionDragRef.current) {
13349
- stopAutoScroll();
13350
- return;
13351
- }
13352
- if (autoScrollDeltaRef.current !== 0) {
13353
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13354
- }
13355
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13356
- }, [postToParentRef, stopAutoScroll]);
13357
- const updateAutoScroll = (0, import_react15.useCallback)(
13358
- (clientY) => {
13359
- const clip = visibleClip(parentScrollRef.current);
13360
- let delta = 0;
13361
- if (clip) {
13362
- const distTop = clientY - clip.top;
13363
- const distBottom = clip.bottom - clientY;
13364
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13365
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13366
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13367
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13368
- }
13369
- }
13370
- autoScrollDeltaRef.current = delta;
13371
- if (delta !== 0 && autoScrollRafRef.current == null) {
13372
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13373
- } else if (delta === 0) {
13374
- stopAutoScroll();
13375
- }
13376
- },
13377
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13378
- );
13379
- const clearSectionDragVisuals = (0, import_react15.useCallback)(() => {
13380
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13381
- sectionDragRef.current = null;
13382
- setSectionDropSlots([]);
13383
- setActiveSectionDropIndex(null);
13384
- setIsSectionDragging(false);
13385
- stopAutoScroll();
13386
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13387
- unlockItemDragInteraction();
13388
- }, [stopAutoScroll]);
13389
- const refreshSectionDragVisuals = (0, import_react15.useCallback)(
13390
- (session, clientX, clientY) => {
13391
- session.lastClientX = clientX;
13392
- session.lastClientY = clientY;
13393
- const slots = buildSectionDropSlots(session.instanceId);
13394
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13395
- session.activeSlot = activeSlot;
13396
- setSectionDropSlots(slots);
13397
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13398
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13399
- updateAutoScroll(clientY);
13400
- },
13401
- [updateAutoScroll]
13402
- );
13403
- const beginSectionDrag = (0, import_react15.useCallback)(
13404
- (session) => {
13405
- sectionDragRef.current = session;
13406
- setIsSectionDragging(true);
13407
- lockItemDuringDrag();
13408
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13409
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13410
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13411
- },
13412
- [refreshSectionDragVisuals]
13413
- );
13414
- const commitSectionDrag = (0, import_react15.useCallback)(() => {
13415
- const session = sectionDragRef.current;
13416
- if (!session) {
13417
- clearSectionDragVisuals();
13418
- return;
13419
- }
13420
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13421
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13422
- if (!entries) {
13423
- clearSectionDragVisuals();
13424
- return;
13425
- }
13426
- const orderJson = JSON.stringify(entries);
13427
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13428
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13429
- applyPersistedOrder(entries);
13430
- clearSectionDragVisuals();
13431
- requestAnimationFrame(() => {
13432
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13433
- applyPersistedOrder(entries);
13434
- }
13435
- requestAnimationFrame(() => {
13436
- window.dispatchEvent(new Event("resize"));
13437
- });
13438
- });
13439
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13440
- const startSectionPressDrag = (0, import_react15.useCallback)(
13441
- (el, clientX, clientY, pointerId) => {
13442
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13443
- const instanceId = instanceIdOf(el);
13444
- if (!instanceId) return false;
13445
- sectionPointerDragRef.current = {
13446
- el,
13447
- instanceId,
13448
- startX: clientX,
13449
- startY: clientY,
13450
- pointerId,
13451
- started: false
13452
- };
13453
- return true;
13454
- },
13455
- [footerDragRef, navDragRef]
13456
- );
13457
- (0, import_react15.useEffect)(() => {
13458
- if (!isEditMode) return;
13459
- const onPointerDown = (e) => {
13460
- if (e.button !== 0) return;
13461
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13462
- if (sectionPointerDragRef.current) return;
13463
- const target = e.target;
13464
- if (!(target instanceof HTMLElement)) return;
13465
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13466
- const sectionEl = target.closest("[data-ohw-section]");
13467
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13468
- if (!topLevelSections().includes(sectionEl)) return;
13469
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13470
- };
13471
- const onPointerMove = (e) => {
13472
- const pending = sectionPointerDragRef.current;
13473
- if (!pending) return;
13474
- if (pending.started) {
13475
- e.preventDefault();
13476
- clearTextSelection();
13477
- const session = sectionDragRef.current;
13478
- if (!session) return;
13479
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13480
- return;
13481
- }
13482
- const dx = e.clientX - pending.startX;
13483
- const dy = e.clientY - pending.startY;
13484
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13485
- e.preventDefault();
13486
- pending.started = true;
13487
- armItemPressDrag();
13488
- clearTextSelection();
13489
- try {
13490
- document.body.setPointerCapture(pending.pointerId);
13491
- } catch {
13492
- }
13493
- beginSectionDrag({
13494
- instanceId: pending.instanceId,
13495
- draggedEl: pending.el,
13496
- lastClientX: e.clientX,
13497
- lastClientY: e.clientY,
13498
- activeSlot: null
13499
- });
13500
- };
13501
- const endPointerDrag = (e) => {
13502
- const pending = sectionPointerDragRef.current;
13503
- sectionPointerDragRef.current = null;
13504
- try {
13505
- if (document.body.hasPointerCapture(e.pointerId)) {
13506
- document.body.releasePointerCapture(e.pointerId);
13507
- }
13508
- } catch {
13509
- }
13510
- if (!pending) return;
13511
- if (!pending.started) {
13512
- unlockItemDragInteraction();
13513
- return;
13514
- }
13515
- suppressNextClickRef.current = true;
13516
- suppressClickUntilRef.current = Date.now() + 500;
13517
- commitSectionDrag();
13518
- };
13519
- const onKeyDown = (e) => {
13520
- if (e.key !== "Escape") return;
13521
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13522
- sectionPointerDragRef.current = null;
13523
- clearSectionDragVisuals();
13524
- };
13525
- document.addEventListener("pointerdown", onPointerDown, true);
13526
- document.addEventListener("pointermove", onPointerMove, true);
13527
- document.addEventListener("pointerup", endPointerDrag, true);
13528
- document.addEventListener("pointercancel", endPointerDrag, true);
13529
- document.addEventListener("keydown", onKeyDown, true);
13530
- return () => {
13531
- document.removeEventListener("pointerdown", onPointerDown, true);
13532
- document.removeEventListener("pointermove", onPointerMove, true);
13533
- document.removeEventListener("pointerup", endPointerDrag, true);
13534
- document.removeEventListener("pointercancel", endPointerDrag, true);
13535
- document.removeEventListener("keydown", onKeyDown, true);
13536
- unlockItemDragInteraction();
13537
- stopAutoScroll();
13538
- };
13539
- }, [
13540
- beginSectionDrag,
13541
- clearSectionDragVisuals,
13542
- commitSectionDrag,
13543
- footerDragRef,
13544
- isEditMode,
13545
- navDragRef,
13546
- refreshSectionDragVisuals,
13547
- startSectionPressDrag,
13548
- stopAutoScroll,
13549
- suppressClickUntilRef,
13550
- suppressNextClickRef
13551
- ]);
13552
- return {
13553
- sectionDragRef,
13554
- sectionDropSlots,
13555
- activeSectionDropIndex,
13556
- isSectionDragging
13557
- };
13558
- }
13559
-
13560
- // src/ui/footer-container-chrome.tsx
13561
- var import_lucide_react15 = require("lucide-react");
13562
- var import_jsx_runtime29 = require("react/jsx-runtime");
13563
- function FooterContainerChrome({
13564
- rect,
13565
- onAdd,
13566
- addDisabled = false
13567
- }) {
13568
- const chromeGap = 6;
13569
- const buttonMargin = 7;
13570
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13571
- "div",
13572
- {
13573
- "data-ohw-footer-container-chrome": "",
13574
- "data-ohw-bridge": "",
13575
- className: "pointer-events-none fixed z-[2147483647]",
13576
- style: {
13577
- top: rect.top - chromeGap,
13578
- left: rect.left - chromeGap,
13579
- width: rect.width + chromeGap * 2,
13580
- height: rect.height + chromeGap * 2
13581
- },
13582
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
13583
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13584
- "button",
13585
- {
13586
- type: "button",
13587
- "data-ohw-footer-add-button": "",
13588
- disabled: addDisabled,
13589
- 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",
13590
- style: { top: chromeGap - buttonMargin },
13591
- "aria-label": "Add item",
13592
- onMouseDown: (e) => {
13593
- e.preventDefault();
13594
- e.stopPropagation();
13595
- },
13596
- onClick: (e) => {
13597
- e.preventDefault();
13598
- e.stopPropagation();
13599
- if (addDisabled) return;
13600
- onAdd();
13601
- },
13602
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13603
- }
13604
- ) }),
13605
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13606
- ] })
13607
- }
13608
- ) });
13609
- }
13610
-
13611
- // src/lib/carousel.ts
13612
- var import_react16 = require("react");
13613
- var CAROUSEL_ATTR = "data-ohw-carousel";
13614
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13615
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13616
- var CAROUSEL_EVENT = "ohw:carousel-change";
13617
- function listCarouselKeys() {
13618
- const keys = /* @__PURE__ */ new Set();
13619
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13620
- const key = el.getAttribute("data-ohw-key");
13621
- if (key) keys.add(key);
13622
- });
13623
- return [...keys];
13624
- }
13625
- function containersForKey(key) {
13626
- return Array.from(
13627
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13628
- );
13629
- }
13630
- function isCarouselKey(key) {
13631
- return containersForKey(key).length > 0;
13632
- }
13633
- function parseSlides(raw) {
13634
- if (!raw) return [];
13635
- try {
13636
- const parsed = JSON.parse(raw);
13637
- if (!Array.isArray(parsed)) return [];
13638
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13639
- } catch {
13640
- return [];
13641
- }
13642
- }
13643
- function readCarouselValue(key) {
13644
- const container = containersForKey(key)[0];
13645
- if (!container) return [];
13646
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
13647
- if (fromAttr.length > 0) return fromAttr;
13648
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
13649
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
13650
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
13651
- });
13652
- }
13653
- function slideIndex(el) {
13654
- const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
13655
- const n = raw ? parseInt(raw, 10) : NaN;
13656
- return Number.isFinite(n) ? n : 0;
13657
- }
13658
- function applyCarouselValue(key, slides) {
13659
- const value = JSON.stringify(slides);
13660
- for (const container of containersForKey(key)) {
13661
- if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
13662
- container.setAttribute(CAROUSEL_VALUE_ATTR, value);
13663
- container.dispatchEvent(
13664
- new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
13665
- );
13666
- }
13667
- }
13668
- function applyCarouselNode(key, val) {
13669
- if (!isCarouselKey(key)) return false;
13670
- applyCarouselValue(key, parseSlides(val));
13671
- return true;
12837
+ function applyCarouselNode(key, val) {
12838
+ if (!isCarouselKey(key)) return false;
12839
+ applyCarouselValue(key, parseSlides(val));
12840
+ return true;
13672
12841
  }
13673
12842
  function useOhwCarousel(key, initial) {
13674
- const [images, setImages] = (0, import_react16.useState)(initial);
13675
- (0, import_react16.useEffect)(() => {
12843
+ const [images, setImages] = (0, import_react15.useState)(initial);
12844
+ (0, import_react15.useEffect)(() => {
13676
12845
  const el = document.querySelector(
13677
12846
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13678
12847
  );
@@ -13750,7 +12919,7 @@ function collectEditableNodes(extraContent, root = document) {
13750
12919
  nodes.push({ key, type: "link", text: href });
13751
12920
  }
13752
12921
  if (extraContent) {
13753
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12922
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13754
12923
  const text = extraContent[key];
13755
12924
  if (typeof text === "string" && text.length > 0) {
13756
12925
  nodes.push({ key, type: "meta", text });
@@ -13787,18 +12956,6 @@ function collectEditableNodes(extraContent, root = document) {
13787
12956
  }
13788
12957
  if (extraContent && !isScoped) {
13789
12958
  applyNavFooterDeleteOverrides(byKey, extraContent);
13790
- for (const key of LOGO_IMAGE_KEYS) {
13791
- if (!(key in extraContent)) continue;
13792
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13793
- }
13794
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13795
- if (!(key in extraContent)) continue;
13796
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13797
- }
13798
- for (const key of LOGO_SIZE_KEYS) {
13799
- if (!(key in extraContent)) continue;
13800
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13801
- }
13802
12959
  }
13803
12960
  return Array.from(byKey.values());
13804
12961
  }
@@ -14267,10 +13424,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14267
13424
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14268
13425
  };
14269
13426
  }
14270
- function resolveEntryAnchor(entry) {
14271
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14272
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14273
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13427
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13428
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13429
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13430
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13431
+ return { effectiveInsertAfter, insertBefore };
13432
+ }
13433
+ function getSchedulingMountPoint(insertAfter) {
13434
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13435
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13436
+ if (!anchorEl && anchor === "scheduling") {
13437
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13438
+ anchorEl = widgets.at(-1) ?? null;
13439
+ }
13440
+ if (!anchorEl) return null;
13441
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14274
13442
  }
14275
13443
  function schedulingMountDepth(insertAfter) {
14276
13444
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14287,7 +13455,8 @@ function getPageSchedulingEntries(raw) {
14287
13455
  }
14288
13456
  }
14289
13457
  function isSchedulingWidgetMissing(entry) {
14290
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13458
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13459
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14291
13460
  }
14292
13461
  function hasMissingSchedulingWidgets(entries) {
14293
13462
  return entries.some(isSchedulingWidgetMissing);
@@ -14317,17 +13486,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14317
13486
  } catch {
14318
13487
  }
14319
13488
  }
14320
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14321
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14322
- const sectionId = schedulingSectionId(widgetId);
13489
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13490
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13491
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14323
13492
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14324
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14325
- if (!anchorEl) return false;
14326
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13493
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13494
+ if (!mountPoint) return false;
14327
13495
  const container = document.createElement("div");
14328
13496
  container.dataset.ohwSectionContainer = "scheduling";
14329
- if (beforeId) {
14330
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13497
+ if (insertBefore) {
13498
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14331
13499
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14332
13500
  if (!beforePoint) return false;
14333
13501
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14338,25 +13506,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14338
13506
  }
14339
13507
  tail.insertAdjacentElement("afterend", container);
14340
13508
  }
14341
- try {
14342
- const root = (0, import_client2.createRoot)(container);
14343
- (0, import_react_dom3.flushSync)(() => {
14344
- root.render(
14345
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14346
- SchedulingWidget,
14347
- {
14348
- notifyOnConnect,
14349
- initialScheduleId: scheduleId,
14350
- insertAfter: widgetId
14351
- }
14352
- )
14353
- );
14354
- });
14355
- } catch (err) {
14356
- console.error("[ow:scheduling] render threw", err);
14357
- container.remove();
14358
- return false;
14359
- }
13509
+ const root = (0, import_client2.createRoot)(container);
13510
+ (0, import_react_dom3.flushSync)(() => {
13511
+ root.render(
13512
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13513
+ SchedulingWidget,
13514
+ {
13515
+ notifyOnConnect,
13516
+ initialScheduleId: scheduleId,
13517
+ insertAfter: effectiveInsertAfter
13518
+ }
13519
+ )
13520
+ );
13521
+ });
14360
13522
  const tracker = getSectionsTracker();
14361
13523
  let sections = [];
14362
13524
  try {
@@ -14364,12 +13526,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14364
13526
  } catch {
14365
13527
  }
14366
13528
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14367
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13529
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14368
13530
  sections.push({
14369
13531
  type: "scheduling",
14370
- insertAfter: widgetId,
14371
- anchorId,
14372
- beforeId: beforeId ?? null,
13532
+ insertAfter: effectiveInsertAfter,
14373
13533
  pagePath: window.location.pathname,
14374
13534
  ...scheduleId ? { scheduleId } : {}
14375
13535
  });
@@ -14383,8 +13543,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14383
13543
  for (let i = pending.length - 1; i >= 0; i--) {
14384
13544
  const entry = pending[i];
14385
13545
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14386
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14387
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13546
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14388
13547
  pending.splice(i, 1);
14389
13548
  }
14390
13549
  }
@@ -14532,13 +13691,6 @@ function isInsideLinkEditor(target) {
14532
13691
  target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
14533
13692
  );
14534
13693
  }
14535
- function isInsideFloatingPanel(target) {
14536
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14537
- }
14538
- function isPointOverFloatingPanel(clientX, clientY) {
14539
- const el = document.elementFromPoint(clientX, clientY);
14540
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14541
- }
14542
13694
  function getHrefKeyFromElement(el) {
14543
13695
  if (!el) return null;
14544
13696
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14689,6 +13841,13 @@ function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
14689
13841
  if (isPointOverNavItem(column, clientX, clientY)) return null;
14690
13842
  return column;
14691
13843
  }
13844
+ function isPointOverLogo(x, y) {
13845
+ for (const root of document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')) {
13846
+ const r2 = root.getBoundingClientRect();
13847
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
13848
+ }
13849
+ return false;
13850
+ }
14692
13851
  function isPointOverNavigation(x, y) {
14693
13852
  const roots = /* @__PURE__ */ new Set();
14694
13853
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
@@ -14777,7 +13936,7 @@ function getNavigationSelectionParent(el) {
14777
13936
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14778
13937
  return getFooterLinksContainer();
14779
13938
  }
14780
- 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)) {
13939
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14781
13940
  return getNavigationRoot(el);
14782
13941
  }
14783
13942
  return null;
@@ -15246,9 +14405,9 @@ function FloatingToolbar({
15246
14405
  showEditLink,
15247
14406
  onEditLink
15248
14407
  }) {
15249
- const localRef = import_react17.default.useRef(null);
15250
- const [measuredW, setMeasuredW] = import_react17.default.useState(330);
15251
- const setRefs = import_react17.default.useCallback(
14408
+ const localRef = import_react16.default.useRef(null);
14409
+ const [measuredW, setMeasuredW] = import_react16.default.useState(330);
14410
+ const setRefs = import_react16.default.useCallback(
15252
14411
  (node) => {
15253
14412
  localRef.current = node;
15254
14413
  if (typeof elRef === "function") elRef(node);
@@ -15260,7 +14419,7 @@ function FloatingToolbar({
15260
14419
  },
15261
14420
  [elRef]
15262
14421
  );
15263
- import_react17.default.useLayoutEffect(() => {
14422
+ import_react16.default.useLayoutEffect(() => {
15264
14423
  const node = localRef.current;
15265
14424
  if (!node) return;
15266
14425
  const update = () => {
@@ -15286,7 +14445,7 @@ function FloatingToolbar({
15286
14445
  pointerEvents: "auto"
15287
14446
  },
15288
14447
  children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
15289
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react17.default.Fragment, { children: [
14448
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
15290
14449
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
15291
14450
  btns.map((btn) => {
15292
14451
  const isActive = activeCommands.has(btn.cmd);
@@ -15370,45 +14529,6 @@ function StateToggle({
15370
14529
  );
15371
14530
  }
15372
14531
  var contentCache = /* @__PURE__ */ new Map();
15373
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15374
- var OHW_LOADER_STYLE = {
15375
- position: "fixed",
15376
- inset: 0,
15377
- background: "#fff",
15378
- zIndex: 2147483646,
15379
- display: "flex",
15380
- alignItems: "center",
15381
- justifyContent: "center"
15382
- };
15383
- function OhwLoaderSpinner() {
15384
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15385
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15386
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15387
- "circle",
15388
- {
15389
- cx: "14",
15390
- cy: "14",
15391
- r: "11",
15392
- stroke: "#1C1917",
15393
- strokeWidth: "3",
15394
- strokeDasharray: "17 52",
15395
- strokeLinecap: "round",
15396
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15397
- "animateTransform",
15398
- {
15399
- attributeName: "transform",
15400
- type: "rotate",
15401
- from: "0 14 14",
15402
- to: "360 14 14",
15403
- dur: "0.7s",
15404
- repeatCount: "indefinite"
15405
- }
15406
- )
15407
- }
15408
- )
15409
- ] });
15410
- }
15411
- 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){}})();`;
15412
14532
  function resolveSubdomain(subdomainFromQuery) {
15413
14533
  if (subdomainFromQuery) return subdomainFromQuery;
15414
14534
  if (typeof window !== "undefined") {
@@ -15431,8 +14551,8 @@ function OhhwellsBridge() {
15431
14551
  const router = (0, import_navigation3.useRouter)();
15432
14552
  const searchParams = (0, import_navigation3.useSearchParams)();
15433
14553
  const isEditMode = isEditSessionActive();
15434
- const [bridgeRoot, setBridgeRoot] = (0, import_react17.useState)(null);
15435
- (0, import_react17.useEffect)(() => {
14554
+ const [bridgeRoot, setBridgeRoot] = (0, import_react16.useState)(null);
14555
+ (0, import_react16.useEffect)(() => {
15436
14556
  const figtreeFontId = "ohw-figtree-font";
15437
14557
  if (!document.getElementById(figtreeFontId)) {
15438
14558
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15461,146 +14581,82 @@ function OhhwellsBridge() {
15461
14581
  const subdomain = resolveSubdomain(subdomainFromQuery);
15462
14582
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15463
14583
  useSavedLinkNavigation(isEditMode);
15464
- const postToParent2 = (0, import_react17.useCallback)((data) => {
14584
+ const postToParent2 = (0, import_react16.useCallback)((data) => {
15465
14585
  if (typeof window !== "undefined" && window.parent !== window) {
15466
14586
  window.parent.postMessage(data, "*");
15467
14587
  }
15468
14588
  }, []);
15469
- const [fetchState, setFetchState] = (0, import_react17.useState)("idle");
15470
- const autoSaveTimers = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
15471
- const activeElRef = (0, import_react17.useRef)(null);
15472
- const pointerHeldRef = (0, import_react17.useRef)(false);
15473
- const selectedElRef = (0, import_react17.useRef)(null);
15474
- const selectedHrefKeyRef = (0, import_react17.useRef)(null);
15475
- const selectedFooterColAttrRef = (0, import_react17.useRef)(null);
15476
- const originalContentRef = (0, import_react17.useRef)(null);
15477
- const activeStateElRef = (0, import_react17.useRef)(null);
15478
- const parentScrollRef = (0, import_react17.useRef)(null);
15479
- const visibleViewportRef = (0, import_react17.useRef)(null);
15480
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react17.useState)(null);
15481
- const attachVisibleViewport = (0, import_react17.useCallback)((node) => {
14589
+ const [fetchState, setFetchState] = (0, import_react16.useState)("idle");
14590
+ const autoSaveTimers = (0, import_react16.useRef)(/* @__PURE__ */ new Map());
14591
+ const activeElRef = (0, import_react16.useRef)(null);
14592
+ const pointerHeldRef = (0, import_react16.useRef)(false);
14593
+ const selectedElRef = (0, import_react16.useRef)(null);
14594
+ const selectedHrefKeyRef = (0, import_react16.useRef)(null);
14595
+ const selectedFooterColAttrRef = (0, import_react16.useRef)(null);
14596
+ const originalContentRef = (0, import_react16.useRef)(null);
14597
+ const activeStateElRef = (0, import_react16.useRef)(null);
14598
+ const parentScrollRef = (0, import_react16.useRef)(null);
14599
+ const visibleViewportRef = (0, import_react16.useRef)(null);
14600
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react16.useState)(null);
14601
+ const attachVisibleViewport = (0, import_react16.useCallback)((node) => {
15482
14602
  visibleViewportRef.current = node;
15483
14603
  setDialogPortalContainer(node);
15484
14604
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15485
14605
  }, []);
15486
- const toolbarElRef = (0, import_react17.useRef)(null);
15487
- const glowElRef = (0, import_react17.useRef)(null);
15488
- const hoveredImageRef = (0, import_react17.useRef)(null);
15489
- const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
15490
- const dragOverElRef = (0, import_react17.useRef)(null);
15491
- const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
15492
- const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
15493
- const selectedMediaElRef = (0, import_react17.useRef)(null);
15494
- const clearMediaSelection = (0, import_react17.useCallback)(() => {
15495
- const prev = selectedMediaElRef.current;
15496
- selectedMediaElRef.current = null;
15497
- setSelectedMedia(null);
15498
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15499
- if (sectionEl) {
15500
- postToParentRef.current({
15501
- type: "ow:section-selected",
15502
- sectionId: sectionEl.dataset.ohwSection ?? null,
15503
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15504
- key: null
15505
- });
15506
- }
15507
- }, []);
15508
- const clearMediaSelectionRef = (0, import_react17.useRef)(clearMediaSelection);
15509
- clearMediaSelectionRef.current = clearMediaSelection;
15510
- const selectMediaElement = (0, import_react17.useCallback)((el) => {
15511
- const r2 = el.getBoundingClientRect();
15512
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15513
- selectedMediaElRef.current = el;
15514
- setSelectedMedia({
15515
- key: el.dataset.ohwKey ?? "",
15516
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15517
- elementType: el.dataset.ohwEditable ?? "image",
15518
- hasTextOverlap: false,
15519
- isDragOver: false,
15520
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15521
- });
15522
- const sectionEl = el.closest("[data-ohw-section]");
15523
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15524
- postToParentRef.current({
15525
- type: "ow:section-selected",
15526
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15527
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15528
- key: el.dataset.ohwKey ?? null,
15529
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15530
- // bridge knows what the node IS, so it names it.
15531
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : "Image"
15532
- });
15533
- }, []);
15534
- const selectMediaElementRef = (0, import_react17.useRef)(selectMediaElement);
15535
- selectMediaElementRef.current = selectMediaElement;
15536
- (0, import_react17.useEffect)(() => {
15537
- if (!selectedMedia) return;
15538
- const update = () => {
15539
- const el = selectedMediaElRef.current;
15540
- if (!el || !el.isConnected) {
15541
- clearMediaSelection();
15542
- return;
15543
- }
15544
- const r2 = el.getBoundingClientRect();
15545
- setSelectedMedia(
15546
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15547
- );
15548
- };
15549
- window.addEventListener("scroll", update, true);
15550
- window.addEventListener("resize", update);
15551
- return () => {
15552
- window.removeEventListener("scroll", update, true);
15553
- window.removeEventListener("resize", update);
15554
- };
15555
- }, [selectedMedia !== null]);
15556
- const [carouselHover, setCarouselHover] = (0, import_react17.useState)(null);
15557
- const [uploadingRects, setUploadingRects] = (0, import_react17.useState)({});
15558
- const hoveredGapRef = (0, import_react17.useRef)(null);
15559
- const imageUnhoverTimerRef = (0, import_react17.useRef)(null);
15560
- const imageShowTimerRef = (0, import_react17.useRef)(null);
15561
- const editStylesRef = (0, import_react17.useRef)(null);
15562
- const activateRef = (0, import_react17.useRef)(() => {
14606
+ const toolbarElRef = (0, import_react16.useRef)(null);
14607
+ const glowElRef = (0, import_react16.useRef)(null);
14608
+ const hoveredImageRef = (0, import_react16.useRef)(null);
14609
+ const hoveredImageHasTextOverlapRef = (0, import_react16.useRef)(false);
14610
+ const dragOverElRef = (0, import_react16.useRef)(null);
14611
+ const [mediaHover, setMediaHover] = (0, import_react16.useState)(null);
14612
+ const [carouselHover, setCarouselHover] = (0, import_react16.useState)(null);
14613
+ const [uploadingRects, setUploadingRects] = (0, import_react16.useState)({});
14614
+ const hoveredGapRef = (0, import_react16.useRef)(null);
14615
+ const imageUnhoverTimerRef = (0, import_react16.useRef)(null);
14616
+ const imageShowTimerRef = (0, import_react16.useRef)(null);
14617
+ const editStylesRef = (0, import_react16.useRef)(null);
14618
+ const activateRef = (0, import_react16.useRef)(() => {
15563
14619
  });
15564
- const deactivateRef = (0, import_react17.useRef)(() => {
14620
+ const deactivateRef = (0, import_react16.useRef)(() => {
15565
14621
  });
15566
- const selectRef = (0, import_react17.useRef)(() => {
14622
+ const selectRef = (0, import_react16.useRef)(() => {
15567
14623
  });
15568
- const selectFrameRef = (0, import_react17.useRef)(() => {
14624
+ const selectFrameRef = (0, import_react16.useRef)(() => {
15569
14625
  });
15570
- const selectLogoRef = (0, import_react17.useRef)(() => {
14626
+ const selectLogoRef = (0, import_react16.useRef)(() => {
15571
14627
  });
15572
- const openLogoSizePanelRef = (0, import_react17.useRef)(() => {
14628
+ const openLogoSizePanelRef = (0, import_react16.useRef)(() => {
15573
14629
  });
15574
- const deselectRef = (0, import_react17.useRef)(() => {
14630
+ const deselectRef = (0, import_react16.useRef)(() => {
15575
14631
  });
15576
- const closeFloatingPanelOnlyRef = (0, import_react17.useRef)(() => {
14632
+ const closeFloatingPanelOnlyRef = (0, import_react16.useRef)(() => {
15577
14633
  });
15578
- const reselectNavigationItemRef = (0, import_react17.useRef)(() => {
14634
+ const reselectNavigationItemRef = (0, import_react16.useRef)(() => {
15579
14635
  });
15580
- const commitNavigationTextEditRef = (0, import_react17.useRef)(() => {
14636
+ const commitNavigationTextEditRef = (0, import_react16.useRef)(() => {
15581
14637
  });
15582
- const handleDeleteSelectedRef = (0, import_react17.useRef)(() => false);
15583
- const runPendingDeleteUndoRef = (0, import_react17.useRef)(() => false);
15584
- const isFooterFrameSelectionRef = (0, import_react17.useRef)(false);
15585
- const refreshActiveCommandsRef = (0, import_react17.useRef)(() => {
14638
+ const handleDeleteSelectedRef = (0, import_react16.useRef)(() => false);
14639
+ const runPendingDeleteUndoRef = (0, import_react16.useRef)(() => false);
14640
+ const isFooterFrameSelectionRef = (0, import_react16.useRef)(false);
14641
+ const refreshActiveCommandsRef = (0, import_react16.useRef)(() => {
15586
14642
  });
15587
- const postToParentRef = (0, import_react17.useRef)(postToParent2);
14643
+ const postToParentRef = (0, import_react16.useRef)(postToParent2);
15588
14644
  postToParentRef.current = postToParent2;
15589
- const aiSectionApiRef = (0, import_react17.useRef)(null);
15590
- const sectionsLoadedRef = (0, import_react17.useRef)(false);
15591
- const pendingScheduleConfigRequests = (0, import_react17.useRef)([]);
15592
- const [toolbarRect, setToolbarRect] = (0, import_react17.useState)(null);
15593
- const [formPickRect, setFormPickRect] = (0, import_react17.useState)(null);
15594
- const formPickElRef = (0, import_react17.useRef)(null);
15595
- const [formViewState, setFormViewStateUi] = (0, import_react17.useState)("default");
15596
- const [formPickCount, setFormPickCount] = (0, import_react17.useState)(null);
15597
- const [formHoverRect, setFormHoverRect] = (0, import_react17.useState)(null);
15598
- const formHoverElRef = (0, import_react17.useRef)(null);
15599
- const [fieldPickRect, setFieldPickRect] = (0, import_react17.useState)(null);
15600
- const fieldPickElRef = (0, import_react17.useRef)(null);
15601
- const [fieldPickState, setFieldPickState] = (0, import_react17.useState)(null);
15602
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react17.useState)(false);
15603
- const clearFormPick = (0, import_react17.useCallback)(() => {
14645
+ const aiSectionApiRef = (0, import_react16.useRef)(null);
14646
+ const sectionsLoadedRef = (0, import_react16.useRef)(false);
14647
+ const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14648
+ const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
14649
+ const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
14650
+ const formPickElRef = (0, import_react16.useRef)(null);
14651
+ const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
14652
+ const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
14653
+ const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
14654
+ const formHoverElRef = (0, import_react16.useRef)(null);
14655
+ const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
14656
+ const fieldPickElRef = (0, import_react16.useRef)(null);
14657
+ const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
14658
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
14659
+ const clearFormPick = (0, import_react16.useCallback)(() => {
15604
14660
  const form = formPickElRef.current;
15605
14661
  const editing = fieldPickElRef.current;
15606
14662
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15620,7 +14676,7 @@ function OhhwellsBridge() {
15620
14676
  formPickElRef.current = null;
15621
14677
  setFormPickRect(null);
15622
14678
  }, []);
15623
- const clearFieldPick = (0, import_react17.useCallback)(() => {
14679
+ const clearFieldPick = (0, import_react16.useCallback)(() => {
15624
14680
  const wrapper = fieldPickElRef.current;
15625
14681
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15626
14682
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15630,9 +14686,9 @@ function OhhwellsBridge() {
15630
14686
  setFieldPickRect(null);
15631
14687
  setFieldPickState(null);
15632
14688
  }, []);
15633
- const persistFieldsRef = (0, import_react17.useRef)(() => {
14689
+ const persistFieldsRef = (0, import_react16.useRef)(() => {
15634
14690
  });
15635
- const persistFields = (0, import_react17.useCallback)(
14691
+ const persistFields = (0, import_react16.useCallback)(
15636
14692
  (form) => {
15637
14693
  const key = formKeyOf(form);
15638
14694
  if (!key) return;
@@ -15643,7 +14699,7 @@ function OhhwellsBridge() {
15643
14699
  []
15644
14700
  );
15645
14701
  persistFieldsRef.current = persistFields;
15646
- const selectField = (0, import_react17.useCallback)((wrapper) => {
14702
+ const selectField = (0, import_react16.useCallback)((wrapper) => {
15647
14703
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15648
14704
  commitPlaceholderEdit(fieldPickElRef.current);
15649
14705
  }
@@ -15656,7 +14712,7 @@ function OhhwellsBridge() {
15656
14712
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15657
14713
  setFieldTypePickerOpen(false);
15658
14714
  }, []);
15659
- const withSelectedField = (0, import_react17.useCallback)(
14715
+ const withSelectedField = (0, import_react16.useCallback)(
15660
14716
  (run) => {
15661
14717
  const wrapper = fieldPickElRef.current;
15662
14718
  const form = formPickElRef.current;
@@ -15669,28 +14725,28 @@ function OhhwellsBridge() {
15669
14725
  },
15670
14726
  [persistFields]
15671
14727
  );
15672
- const handleFieldTypeChange = (0, import_react17.useCallback)(
14728
+ const handleFieldTypeChange = (0, import_react16.useCallback)(
15673
14729
  (type) => withSelectedField((_form, wrapper) => {
15674
14730
  applyFieldType(wrapper, type);
15675
14731
  selectField(wrapper);
15676
14732
  }),
15677
14733
  [selectField, withSelectedField]
15678
14734
  );
15679
- const handleFieldRequiredToggle = (0, import_react17.useCallback)(
14735
+ const handleFieldRequiredToggle = (0, import_react16.useCallback)(
15680
14736
  () => withSelectedField((_form, wrapper) => {
15681
14737
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15682
14738
  selectField(wrapper);
15683
14739
  }),
15684
14740
  [selectField, withSelectedField]
15685
14741
  );
15686
- const handleFieldDuplicate = (0, import_react17.useCallback)(
14742
+ const handleFieldDuplicate = (0, import_react16.useCallback)(
15687
14743
  () => withSelectedField((form, wrapper) => {
15688
14744
  const copy = duplicateField(form, wrapper);
15689
14745
  selectField(copy);
15690
14746
  }),
15691
14747
  [selectField, withSelectedField]
15692
14748
  );
15693
- const handleFieldDelete = (0, import_react17.useCallback)(
14749
+ const handleFieldDelete = (0, import_react16.useCallback)(
15694
14750
  () => withSelectedField((_form, wrapper) => {
15695
14751
  removeField(wrapper);
15696
14752
  clearFieldPick();
@@ -15698,7 +14754,7 @@ function OhhwellsBridge() {
15698
14754
  }),
15699
14755
  [clearFieldPick, withSelectedField]
15700
14756
  );
15701
- const handleAddField = (0, import_react17.useCallback)(
14757
+ const handleAddField = (0, import_react16.useCallback)(
15702
14758
  (type) => {
15703
14759
  const form = formPickElRef.current;
15704
14760
  if (!form) return;
@@ -15714,8 +14770,8 @@ function OhhwellsBridge() {
15714
14770
  },
15715
14771
  [persistFields, selectField]
15716
14772
  );
15717
- const fieldDragRef = (0, import_react17.useRef)(null);
15718
- const buildFieldDropSlots = (0, import_react17.useCallback)((form, draggedKey) => {
14773
+ const fieldDragRef = (0, import_react16.useRef)(null);
14774
+ const buildFieldDropSlots = (0, import_react16.useCallback)((form, draggedKey) => {
15719
14775
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15720
14776
  const slots = others.map((el) => {
15721
14777
  const rect = el.getBoundingClientRect();
@@ -15728,7 +14784,7 @@ function OhhwellsBridge() {
15728
14784
  }
15729
14785
  return slots;
15730
14786
  }, []);
15731
- const handleFieldDragStart = (0, import_react17.useCallback)(() => {
14787
+ const handleFieldDragStart = (0, import_react16.useCallback)(() => {
15732
14788
  const wrapper = fieldPickElRef.current;
15733
14789
  const form = formPickElRef.current;
15734
14790
  if (!wrapper || !form) return;
@@ -15737,18 +14793,18 @@ function OhhwellsBridge() {
15737
14793
  setFieldDragging(true);
15738
14794
  setFieldDropSlots(buildFieldDropSlots(form, key));
15739
14795
  }, [buildFieldDropSlots]);
15740
- const handleFieldDragEnd = (0, import_react17.useCallback)(() => {
14796
+ const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
15741
14797
  fieldDragRef.current = null;
15742
14798
  setFieldDropIndex(null);
15743
14799
  setFieldDropSlots([]);
15744
14800
  setFieldDragging(false);
15745
14801
  }, []);
15746
- const [fieldDropIndex, setFieldDropIndex] = (0, import_react17.useState)(null);
15747
- const [fieldDropSlots, setFieldDropSlots] = (0, import_react17.useState)([]);
15748
- const [fieldDragging, setFieldDragging] = (0, import_react17.useState)(false);
15749
- const clearFormPickRef = (0, import_react17.useRef)(clearFormPick);
14802
+ const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
14803
+ const [fieldDropSlots, setFieldDropSlots] = (0, import_react16.useState)([]);
14804
+ const [fieldDragging, setFieldDragging] = (0, import_react16.useState)(false);
14805
+ const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
15750
14806
  clearFormPickRef.current = clearFormPick;
15751
- (0, import_react17.useEffect)(() => {
14807
+ (0, import_react16.useEffect)(() => {
15752
14808
  const el = fieldPickElRef.current;
15753
14809
  if (!el || fieldPickRect === null) return;
15754
14810
  const observer = new ResizeObserver(() => {
@@ -15757,7 +14813,7 @@ function OhhwellsBridge() {
15757
14813
  observer.observe(el);
15758
14814
  return () => observer.disconnect();
15759
14815
  }, [fieldPickRect !== null, fieldPickState]);
15760
- (0, import_react17.useEffect)(() => {
14816
+ (0, import_react16.useEffect)(() => {
15761
14817
  const el = formPickElRef.current;
15762
14818
  if (!el || formPickRect === null) return;
15763
14819
  const observer = new ResizeObserver(() => {
@@ -15766,25 +14822,25 @@ function OhhwellsBridge() {
15766
14822
  observer.observe(el);
15767
14823
  return () => observer.disconnect();
15768
14824
  }, [formPickRect !== null, formViewState]);
15769
- const [toolbarVariant, setToolbarVariant] = (0, import_react17.useState)("none");
15770
- const toolbarVariantRef = (0, import_react17.useRef)("none");
14825
+ const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
14826
+ const toolbarVariantRef = (0, import_react16.useRef)("none");
15771
14827
  toolbarVariantRef.current = toolbarVariant;
15772
- const [selectedIsCta, setSelectedIsCta] = (0, import_react17.useState)(false);
15773
- const [selectedIsSocial, setSelectedIsSocial] = (0, import_react17.useState)(false);
15774
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react17.useState)(false);
15775
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react17.useState)(null);
15776
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react17.useState)(false);
15777
- const [toggleState, setToggleState] = (0, import_react17.useState)(null);
15778
- const [maxBadge, setMaxBadge] = (0, import_react17.useState)(null);
15779
- const [activeCommands, setActiveCommands] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
15780
- const [sectionGap, setSectionGap] = (0, import_react17.useState)(null);
15781
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react17.useState)(false);
15782
- const hoveredNavContainerRef = (0, import_react17.useRef)(null);
15783
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react17.useState)(null);
15784
- const hoveredItemElRef = (0, import_react17.useRef)(null);
15785
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react17.useState)(null);
15786
- const [hoveredTextRect, setHoveredTextRect] = (0, import_react17.useState)(null);
15787
- (0, import_react17.useEffect)(() => {
14828
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react16.useState)(false);
14829
+ const [selectedIsSocial, setSelectedIsSocial] = (0, import_react16.useState)(false);
14830
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = (0, import_react16.useState)(false);
14831
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react16.useState)(null);
14832
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react16.useState)(false);
14833
+ const [toggleState, setToggleState] = (0, import_react16.useState)(null);
14834
+ const [maxBadge, setMaxBadge] = (0, import_react16.useState)(null);
14835
+ const [activeCommands, setActiveCommands] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
14836
+ const [sectionGap, setSectionGap] = (0, import_react16.useState)(null);
14837
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react16.useState)(false);
14838
+ const hoveredNavContainerRef = (0, import_react16.useRef)(null);
14839
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
14840
+ const hoveredItemElRef = (0, import_react16.useRef)(null);
14841
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
14842
+ const [hoveredTextRect, setHoveredTextRect] = (0, import_react16.useState)(null);
14843
+ (0, import_react16.useEffect)(() => {
15788
14844
  const sync = () => {
15789
14845
  const el = document.querySelector(
15790
14846
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15805,56 +14861,43 @@ function OhhwellsBridge() {
15805
14861
  });
15806
14862
  return () => observer.disconnect();
15807
14863
  }, []);
15808
- const siblingHintElRef = (0, import_react17.useRef)(null);
15809
- const [siblingHintRect, setSiblingHintRect] = (0, import_react17.useState)(null);
15810
- const [siblingHintRects, setSiblingHintRects] = (0, import_react17.useState)([]);
15811
- const [isItemDragging, setIsItemDragging] = (0, import_react17.useState)(false);
15812
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react17.useState)(false);
14864
+ const siblingHintElRef = (0, import_react16.useRef)(null);
14865
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
14866
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
14867
+ const [isItemDragging, setIsItemDragging] = (0, import_react16.useState)(false);
14868
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react16.useState)(false);
15813
14869
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15814
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react17.useState)(null);
15815
- const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react17.useState)(null);
15816
- const footerDragRef = (0, import_react17.useRef)(null);
15817
- const [footerDropSlots, setFooterDropSlots] = (0, import_react17.useState)([]);
15818
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react17.useState)(null);
15819
- const [draggedItemRect, setDraggedItemRect] = (0, import_react17.useState)(null);
15820
- const footerPointerDragRef = (0, import_react17.useRef)(null);
15821
- const suppressNextClickRef = (0, import_react17.useRef)(false);
15822
- const suppressClickUntilRef = (0, import_react17.useRef)(0);
15823
- const [linkPopover, setLinkPopover] = (0, import_react17.useState)(null);
15824
- const linkPopoverSessionRef = (0, import_react17.useRef)(null);
15825
- const addNavAfterAnchorRef = (0, import_react17.useRef)(null);
15826
- const editContentRef = (0, import_react17.useRef)({});
15827
- const aiSectionsRef = (0, import_react17.useRef)("");
15828
- const brandKitRef = (0, import_react17.useRef)("");
15829
- const stylesRef = (0, import_react17.useRef)("");
15830
- const pendingDeleteUndoRef = (0, import_react17.useRef)(null);
15831
- const [floatingPanel, setFloatingPanel] = (0, import_react17.useState)(null);
15832
- const floatingPanelOpenRef = (0, import_react17.useRef)(false);
15833
- const setFloatingPanelRef = (0, import_react17.useRef)(setFloatingPanel);
15834
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react17.useState)(null);
15835
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react17.useState)(null);
15836
- const [editorViewport, setEditorViewport] = (0, import_react17.useState)("desktop");
15837
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react17.useState)(null);
15838
- const [sitePages, setSitePages] = (0, import_react17.useState)([]);
15839
- const [sectionsByPath, setSectionsByPath] = (0, import_react17.useState)({});
15840
- const sectionsPrefetchGenRef = (0, import_react17.useRef)(0);
15841
- const setLinkPopoverRef = (0, import_react17.useRef)(setLinkPopover);
15842
- const linkPopoverPanelRef = (0, import_react17.useRef)(null);
15843
- const linkPopoverOpenRef = (0, import_react17.useRef)(false);
15844
- const linkPopoverGraceUntilRef = (0, import_react17.useRef)(0);
14870
+ const [floatingPanel, setFloatingPanel] = (0, import_react16.useState)(null);
14871
+ const floatingPanelOpenRef = (0, import_react16.useRef)(false);
14872
+ floatingPanelOpenRef.current = floatingPanel !== null;
14873
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react16.useState)(null);
14874
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react16.useState)(null);
14875
+ const [editorViewport, setEditorViewport] = (0, import_react16.useState)("desktop");
14876
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react16.useState)(null);
14877
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react16.useState)(null);
14878
+ const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react16.useState)(null);
14879
+ const footerDragRef = (0, import_react16.useRef)(null);
14880
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react16.useState)([]);
14881
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react16.useState)(null);
14882
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react16.useState)(null);
14883
+ const footerPointerDragRef = (0, import_react16.useRef)(null);
14884
+ const suppressNextClickRef = (0, import_react16.useRef)(false);
14885
+ const suppressClickUntilRef = (0, import_react16.useRef)(0);
14886
+ const [linkPopover, setLinkPopover] = (0, import_react16.useState)(null);
14887
+ const linkPopoverSessionRef = (0, import_react16.useRef)(null);
14888
+ const addNavAfterAnchorRef = (0, import_react16.useRef)(null);
14889
+ const editContentRef = (0, import_react16.useRef)({});
14890
+ const aiSectionsRef = (0, import_react16.useRef)("");
14891
+ const pendingDeleteUndoRef = (0, import_react16.useRef)(null);
14892
+ const [sitePages, setSitePages] = (0, import_react16.useState)([]);
14893
+ const [sectionsByPath, setSectionsByPath] = (0, import_react16.useState)({});
14894
+ const sectionsPrefetchGenRef = (0, import_react16.useRef)(0);
14895
+ const setLinkPopoverRef = (0, import_react16.useRef)(setLinkPopover);
14896
+ const linkPopoverPanelRef = (0, import_react16.useRef)(null);
14897
+ const linkPopoverOpenRef = (0, import_react16.useRef)(false);
14898
+ const linkPopoverGraceUntilRef = (0, import_react16.useRef)(0);
15845
14899
  setLinkPopoverRef.current = setLinkPopover;
15846
- setFloatingPanelRef.current = setFloatingPanel;
15847
14900
  linkPopoverSessionRef.current = linkPopover;
15848
- floatingPanelOpenRef.current = Boolean(floatingPanel);
15849
- (0, import_react17.useEffect)(() => {
15850
- const syncViewport = () => {
15851
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
15852
- setEditorViewport((prev) => prev === next ? prev : next);
15853
- };
15854
- syncViewport();
15855
- window.addEventListener("resize", syncViewport);
15856
- return () => window.removeEventListener("resize", syncViewport);
15857
- }, []);
15858
14901
  const {
15859
14902
  navDragRef,
15860
14903
  navDropSlots,
@@ -15887,20 +14930,10 @@ function OhhwellsBridge() {
15887
14930
  getNavigationItemAnchor,
15888
14931
  isDragHandleDisabled
15889
14932
  });
15890
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15891
- isEditMode,
15892
- editContentRef,
15893
- postToParentRef,
15894
- parentScrollRef,
15895
- navDragRef,
15896
- footerDragRef,
15897
- suppressNextClickRef,
15898
- suppressClickUntilRef
15899
- });
15900
14933
  const bumpLinkPopoverGrace = () => {
15901
14934
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15902
14935
  };
15903
- const runSectionsPrefetch = (0, import_react17.useCallback)((pages) => {
14936
+ const runSectionsPrefetch = (0, import_react16.useCallback)((pages) => {
15904
14937
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15905
14938
  const gen = ++sectionsPrefetchGenRef.current;
15906
14939
  const paths = pages.map((p) => p.path);
@@ -15919,9 +14952,9 @@ function OhhwellsBridge() {
15919
14952
  );
15920
14953
  });
15921
14954
  }, [isEditMode, pathname]);
15922
- const runSectionsPrefetchRef = (0, import_react17.useRef)(runSectionsPrefetch);
14955
+ const runSectionsPrefetchRef = (0, import_react16.useRef)(runSectionsPrefetch);
15923
14956
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15924
- (0, import_react17.useEffect)(() => {
14957
+ (0, import_react16.useEffect)(() => {
15925
14958
  if (!linkPopover) {
15926
14959
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15927
14960
  return;
@@ -15949,7 +14982,7 @@ function OhhwellsBridge() {
15949
14982
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15950
14983
  };
15951
14984
  }, [linkPopover, postToParent2]);
15952
- (0, import_react17.useEffect)(() => {
14985
+ (0, import_react16.useEffect)(() => {
15953
14986
  if (!isEditMode) return;
15954
14987
  const useFixtures = shouldUseDevFixtures();
15955
14988
  if (useFixtures) {
@@ -15973,14 +15006,14 @@ function OhhwellsBridge() {
15973
15006
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
15974
15007
  return () => window.removeEventListener("message", onSitePages);
15975
15008
  }, [isEditMode, postToParent2]);
15976
- (0, import_react17.useEffect)(() => {
15009
+ (0, import_react16.useEffect)(() => {
15977
15010
  if (!isEditMode || shouldUseDevFixtures()) return;
15978
15011
  void loadAllSectionsManifest().then((manifest) => {
15979
15012
  if (Object.keys(manifest).length === 0) return;
15980
15013
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
15981
15014
  });
15982
15015
  }, [isEditMode]);
15983
- (0, import_react17.useEffect)(() => {
15016
+ (0, import_react16.useEffect)(() => {
15984
15017
  const update = () => {
15985
15018
  const el = activeElRef.current ?? selectedElRef.current;
15986
15019
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -16004,10 +15037,10 @@ function OhhwellsBridge() {
16004
15037
  vvp.removeEventListener("resize", update);
16005
15038
  };
16006
15039
  }, []);
16007
- const refreshStateRules = (0, import_react17.useCallback)(() => {
15040
+ const refreshStateRules = (0, import_react16.useCallback)(() => {
16008
15041
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
16009
15042
  }, []);
16010
- const processConfigRequest = (0, import_react17.useCallback)((insertAfterVal) => {
15043
+ const processConfigRequest = (0, import_react16.useCallback)((insertAfterVal) => {
16011
15044
  const tracker = getSectionsTracker();
16012
15045
  let entries = [];
16013
15046
  try {
@@ -16030,7 +15063,7 @@ function OhhwellsBridge() {
16030
15063
  }
16031
15064
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
16032
15065
  }, [isEditMode]);
16033
- const deactivate = (0, import_react17.useCallback)(() => {
15066
+ const deactivate = (0, import_react16.useCallback)(() => {
16034
15067
  const el = activeElRef.current;
16035
15068
  if (!el) return;
16036
15069
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16071,12 +15104,12 @@ function OhhwellsBridge() {
16071
15104
  setToolbarShowEditLink(false);
16072
15105
  postToParent2({ type: "ow:exit-edit" });
16073
15106
  }, [postToParent2]);
16074
- const clearSelectedAttr = (0, import_react17.useCallback)(() => {
15107
+ const clearSelectedAttr = (0, import_react16.useCallback)(() => {
16075
15108
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16076
15109
  el.removeAttribute("data-ohw-selected");
16077
15110
  });
16078
15111
  }, []);
16079
- const deselect = (0, import_react17.useCallback)(() => {
15112
+ const deselect = (0, import_react16.useCallback)(() => {
16080
15113
  clearSelectedAttr();
16081
15114
  selectedElRef.current = null;
16082
15115
  selectedHrefKeyRef.current = null;
@@ -16105,11 +15138,11 @@ function OhhwellsBridge() {
16105
15138
  setToolbarVariant("none");
16106
15139
  }
16107
15140
  }, [clearSelectedAttr]);
16108
- const markSelected = (0, import_react17.useCallback)((el) => {
15141
+ const markSelected = (0, import_react16.useCallback)((el) => {
16109
15142
  clearSelectedAttr();
16110
15143
  el.setAttribute("data-ohw-selected", "");
16111
15144
  }, [clearSelectedAttr]);
16112
- const resolveHrefKeyElement = (0, import_react17.useCallback)((hrefKey) => {
15145
+ const resolveHrefKeyElement = (0, import_react16.useCallback)((hrefKey) => {
16113
15146
  if (isFooterHrefKey(hrefKey)) {
16114
15147
  return document.querySelector(
16115
15148
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16124,7 +15157,7 @@ function OhhwellsBridge() {
16124
15157
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16125
15158
  );
16126
15159
  }, []);
16127
- const resyncSelectedNavigationItem = (0, import_react17.useCallback)(() => {
15160
+ const resyncSelectedNavigationItem = (0, import_react16.useCallback)(() => {
16128
15161
  const hrefKey = selectedHrefKeyRef.current;
16129
15162
  if (hrefKey) {
16130
15163
  const link = resolveHrefKeyElement(hrefKey);
@@ -16162,7 +15195,7 @@ function OhhwellsBridge() {
16162
15195
  );
16163
15196
  }
16164
15197
  }, [resolveHrefKeyElement]);
16165
- const reselectNavigationItem = (0, import_react17.useCallback)((navAnchor) => {
15198
+ const reselectNavigationItem = (0, import_react16.useCallback)((navAnchor) => {
16166
15199
  selectedElRef.current = navAnchor;
16167
15200
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16168
15201
  selectedFooterColAttrRef.current = null;
@@ -16193,7 +15226,7 @@ function OhhwellsBridge() {
16193
15226
  setToolbarShowEditLink(false);
16194
15227
  setActiveCommands(/* @__PURE__ */ new Set());
16195
15228
  }, [markSelected]);
16196
- const commitNavigationTextEdit = (0, import_react17.useCallback)((navAnchor) => {
15229
+ const commitNavigationTextEdit = (0, import_react16.useCallback)((navAnchor) => {
16197
15230
  const el = activeElRef.current;
16198
15231
  if (!el) return;
16199
15232
  const key = el.dataset.ohwKey;
@@ -16226,7 +15259,7 @@ function OhhwellsBridge() {
16226
15259
  postToParent2({ type: "ow:exit-edit" });
16227
15260
  reselectNavigationItem(navAnchor);
16228
15261
  }, [postToParent2, reselectNavigationItem]);
16229
- const handleAddTopLevelNavItem = (0, import_react17.useCallback)(() => {
15262
+ const handleAddTopLevelNavItem = (0, import_react16.useCallback)(() => {
16230
15263
  const items = listNavbarRootItems();
16231
15264
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16232
15265
  deselectRef.current();
@@ -16238,7 +15271,7 @@ function OhhwellsBridge() {
16238
15271
  intent: "add-nav"
16239
15272
  });
16240
15273
  }, []);
16241
- const maybeWarnNavLinkDropdownConflict = (0, import_react17.useCallback)(
15274
+ const maybeWarnNavLinkDropdownConflict = (0, import_react16.useCallback)(
16242
15275
  (anchor) => {
16243
15276
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16244
15277
  if (!navDropdownsOpenOnClick()) return;
@@ -16251,7 +15284,7 @@ function OhhwellsBridge() {
16251
15284
  },
16252
15285
  [postToParent2]
16253
15286
  );
16254
- const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
15287
+ const handleNavDropdownOpenChange = (0, import_react16.useCallback)((open) => {
16255
15288
  const selected = selectedElRef.current;
16256
15289
  if (!selected || !isNavigationItem2(selected)) return;
16257
15290
  setNavGroupForceOpen(selected, open);
@@ -16263,7 +15296,7 @@ function OhhwellsBridge() {
16263
15296
  }
16264
15297
  });
16265
15298
  }, []);
16266
- const handleFooterHeadingVisibleChange = (0, import_react17.useCallback)(
15299
+ const handleFooterHeadingVisibleChange = (0, import_react16.useCallback)(
16267
15300
  (visible) => {
16268
15301
  const selected = selectedElRef.current;
16269
15302
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16287,7 +15320,7 @@ function OhhwellsBridge() {
16287
15320
  },
16288
15321
  [postToParent2]
16289
15322
  );
16290
- const enterEditOnNewItem = (0, import_react17.useCallback)((anchor) => {
15323
+ const enterEditOnNewItem = (0, import_react16.useCallback)((anchor) => {
16291
15324
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16292
15325
  if (!label) {
16293
15326
  selectRef.current(anchor);
@@ -16296,7 +15329,7 @@ function OhhwellsBridge() {
16296
15329
  setNavGroupForceOpen(anchor, true);
16297
15330
  activateRef.current(label);
16298
15331
  }, []);
16299
- const handleAddChildItem = (0, import_react17.useCallback)(() => {
15332
+ const handleAddChildItem = (0, import_react16.useCallback)(() => {
16300
15333
  const selected = selectedElRef.current;
16301
15334
  if (!selected) return;
16302
15335
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16408,7 +15441,7 @@ function OhhwellsBridge() {
16408
15441
  enterEditOnNewItem(result.anchor);
16409
15442
  });
16410
15443
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16411
- const handleAddFooterColumn = (0, import_react17.useCallback)(() => {
15444
+ const handleAddFooterColumn = (0, import_react16.useCallback)(() => {
16412
15445
  if (!canAddFooterColumn()) {
16413
15446
  postToParent2({
16414
15447
  type: "ow:toast",
@@ -16429,7 +15462,7 @@ function OhhwellsBridge() {
16429
15462
  selectRef.current(result.firstLink);
16430
15463
  });
16431
15464
  }, [postToParent2]);
16432
- const clearFooterDragVisuals = (0, import_react17.useCallback)(() => {
15465
+ const clearFooterDragVisuals = (0, import_react16.useCallback)(() => {
16433
15466
  footerDragRef.current = null;
16434
15467
  setSiblingHintRects([]);
16435
15468
  setFooterDropSlots([]);
@@ -16438,7 +15471,7 @@ function OhhwellsBridge() {
16438
15471
  setIsItemDragging(false);
16439
15472
  unlockFooterDragInteraction();
16440
15473
  }, []);
16441
- const refreshFooterDragVisuals = (0, import_react17.useCallback)((session, activeSlot, clientX, clientY) => {
15474
+ const refreshFooterDragVisuals = (0, import_react16.useCallback)((session, activeSlot, clientX, clientY) => {
16442
15475
  const dragged = session.draggedEl;
16443
15476
  setDraggedItemRect(dragged.getBoundingClientRect());
16444
15477
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16470,13 +15503,13 @@ function OhhwellsBridge() {
16470
15503
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16471
15504
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16472
15505
  }, []);
16473
- const refreshFooterDragVisualsRef = (0, import_react17.useRef)(refreshFooterDragVisuals);
15506
+ const refreshFooterDragVisualsRef = (0, import_react16.useRef)(refreshFooterDragVisuals);
16474
15507
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16475
- const commitFooterDragRef = (0, import_react17.useRef)(() => {
15508
+ const commitFooterDragRef = (0, import_react16.useRef)(() => {
16476
15509
  });
16477
- const beginFooterDragRef = (0, import_react17.useRef)(() => {
15510
+ const beginFooterDragRef = (0, import_react16.useRef)(() => {
16478
15511
  });
16479
- const beginFooterDrag = (0, import_react17.useCallback)(
15512
+ const beginFooterDrag = (0, import_react16.useCallback)(
16480
15513
  (session) => {
16481
15514
  const rect = session.draggedEl.getBoundingClientRect();
16482
15515
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16496,7 +15529,7 @@ function OhhwellsBridge() {
16496
15529
  [refreshFooterDragVisuals]
16497
15530
  );
16498
15531
  beginFooterDragRef.current = beginFooterDrag;
16499
- const commitFooterDrag = (0, import_react17.useCallback)(
15532
+ const commitFooterDrag = (0, import_react16.useCallback)(
16500
15533
  (clientX, clientY) => {
16501
15534
  const session = footerDragRef.current;
16502
15535
  if (!session) {
@@ -16624,7 +15657,7 @@ function OhhwellsBridge() {
16624
15657
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16625
15658
  );
16626
15659
  commitFooterDragRef.current = commitFooterDrag;
16627
- const startFooterLinkDrag = (0, import_react17.useCallback)(
15660
+ const startFooterLinkDrag = (0, import_react16.useCallback)(
16628
15661
  (anchor, clientX, clientY, wasSelected) => {
16629
15662
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16630
15663
  if (!hrefKey) return false;
@@ -16660,7 +15693,7 @@ function OhhwellsBridge() {
16660
15693
  },
16661
15694
  [beginFooterDrag]
16662
15695
  );
16663
- const startFooterColumnDrag = (0, import_react17.useCallback)(
15696
+ const startFooterColumnDrag = (0, import_react16.useCallback)(
16664
15697
  (columnEl, clientX, clientY, wasSelected) => {
16665
15698
  const columns = listFooterColumns();
16666
15699
  const idx = columns.indexOf(columnEl);
@@ -16680,7 +15713,7 @@ function OhhwellsBridge() {
16680
15713
  },
16681
15714
  [beginFooterDrag]
16682
15715
  );
16683
- const handleItemDragStart = (0, import_react17.useCallback)(
15716
+ const handleItemDragStart = (0, import_react16.useCallback)(
16684
15717
  (e) => {
16685
15718
  const selected = selectedElRef.current;
16686
15719
  if (!selected) {
@@ -16700,7 +15733,7 @@ function OhhwellsBridge() {
16700
15733
  },
16701
15734
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16702
15735
  );
16703
- const handleItemDragEnd = (0, import_react17.useCallback)(
15736
+ const handleItemDragEnd = (0, import_react16.useCallback)(
16704
15737
  (e) => {
16705
15738
  if (footerDragRef.current) {
16706
15739
  const x = e?.clientX;
@@ -16726,7 +15759,7 @@ function OhhwellsBridge() {
16726
15759
  },
16727
15760
  [commitFooterDrag, commitNavDrag, navDragRef]
16728
15761
  );
16729
- const handleItemChromePointerDown = (0, import_react17.useCallback)((e) => {
15762
+ const handleItemChromePointerDown = (0, import_react16.useCallback)((e) => {
16730
15763
  if (e.button !== 0) return;
16731
15764
  const selected = selectedElRef.current;
16732
15765
  if (!selected) return;
@@ -16757,7 +15790,7 @@ function OhhwellsBridge() {
16757
15790
  }
16758
15791
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16759
15792
  }, [armNavPressFromChrome]);
16760
- const handleItemChromeClick = (0, import_react17.useCallback)((clientX, clientY) => {
15793
+ const handleItemChromeClick = (0, import_react16.useCallback)((clientX, clientY) => {
16761
15794
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16762
15795
  suppressNextClickRef.current = false;
16763
15796
  return;
@@ -16770,7 +15803,7 @@ function OhhwellsBridge() {
16770
15803
  }, []);
16771
15804
  reselectNavigationItemRef.current = reselectNavigationItem;
16772
15805
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16773
- const select = (0, import_react17.useCallback)((anchor) => {
15806
+ const select = (0, import_react16.useCallback)((anchor) => {
16774
15807
  if (!isNavigationItem2(anchor)) return;
16775
15808
  if (activeElRef.current) deactivate();
16776
15809
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16813,7 +15846,7 @@ function OhhwellsBridge() {
16813
15846
  setFloatingPanel(null);
16814
15847
  setLogoSizeDraft(null);
16815
15848
  }, [deactivate, markSelected]);
16816
- const selectFrame = (0, import_react17.useCallback)((el) => {
15849
+ const selectFrame = (0, import_react16.useCallback)((el) => {
16817
15850
  if (!isNavigationContainer(el)) return;
16818
15851
  if (activeElRef.current) deactivate();
16819
15852
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16864,7 +15897,7 @@ function OhhwellsBridge() {
16864
15897
  setFloatingPanel(null);
16865
15898
  setLogoSizeDraft(null);
16866
15899
  }, [deactivate, markSelected, postToParent2]);
16867
- const selectLogo = (0, import_react17.useCallback)(
15900
+ const selectLogo = (0, import_react16.useCallback)(
16868
15901
  (logoEl) => {
16869
15902
  if (activeElRef.current) deactivate();
16870
15903
  selectedElRef.current = logoEl;
@@ -16893,7 +15926,7 @@ function OhhwellsBridge() {
16893
15926
  },
16894
15927
  [deactivate, markSelected]
16895
15928
  );
16896
- const openLogoSizePanel = (0, import_react17.useCallback)((logoEl) => {
15929
+ const openLogoSizePanel = (0, import_react16.useCallback)((logoEl) => {
16897
15930
  const placement = getLogoPlacement(logoEl);
16898
15931
  const draft = readLogoSizeState(editContentRef.current, placement);
16899
15932
  setLogoSizeDraft(draft);
@@ -16906,7 +15939,7 @@ function OhhwellsBridge() {
16906
15939
  placement
16907
15940
  });
16908
15941
  }, []);
16909
- const openSocialsDisplayPanel = (0, import_react17.useCallback)((row) => {
15942
+ const openSocialsDisplayPanel = (0, import_react16.useCallback)((row) => {
16910
15943
  setParentScrollSnap(parentScrollRef.current);
16911
15944
  setFloatingPanel({
16912
15945
  key: "socials-display",
@@ -16916,7 +15949,7 @@ function OhhwellsBridge() {
16916
15949
  row
16917
15950
  });
16918
15951
  }, []);
16919
- const changeSocialsDisplay = (0, import_react17.useCallback)(
15952
+ const changeSocialsDisplay = (0, import_react16.useCallback)(
16920
15953
  (row, next) => {
16921
15954
  if (next.icon) {
16922
15955
  const missing = socialsMissingIcons(row);
@@ -16939,17 +15972,17 @@ function OhhwellsBridge() {
16939
15972
  },
16940
15973
  []
16941
15974
  );
16942
- const closeFloatingPanelOnly = (0, import_react17.useCallback)(() => {
15975
+ const closeFloatingPanelOnly = (0, import_react16.useCallback)(() => {
16943
15976
  setFloatingPanel(null);
16944
15977
  setLogoSizeDraft(null);
16945
15978
  }, []);
16946
15979
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16947
- const closeFloatingPanelAndDeselect = (0, import_react17.useCallback)(() => {
15980
+ const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
16948
15981
  setFloatingPanel(null);
16949
15982
  setLogoSizeDraft(null);
16950
15983
  deselectRef.current();
16951
15984
  }, []);
16952
- (0, import_react17.useEffect)(() => {
15985
+ (0, import_react16.useEffect)(() => {
16953
15986
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
16954
15987
  if (!session || !logoSizeDraft) {
16955
15988
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -16968,7 +16001,7 @@ function OhhwellsBridge() {
16968
16001
  max: LOGO_SIZE_MAX
16969
16002
  });
16970
16003
  }, [floatingPanel, logoSizeDraft, editorViewport]);
16971
- const persistLogoSizeDraft = (0, import_react17.useCallback)(
16004
+ const persistLogoSizeDraft = (0, import_react16.useCallback)(
16972
16005
  (placement, draft) => {
16973
16006
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
16974
16007
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -17008,7 +16041,7 @@ function OhhwellsBridge() {
17008
16041
  },
17009
16042
  [postToParent2]
17010
16043
  );
17011
- const activate = (0, import_react17.useCallback)((el, options) => {
16044
+ const activate = (0, import_react16.useCallback)((el, options) => {
17012
16045
  if (activeElRef.current === el) return;
17013
16046
  if (isIconEditable(el)) return;
17014
16047
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17092,8 +16125,8 @@ function OhhwellsBridge() {
17092
16125
  openLogoSizePanelRef.current = openLogoSizePanel;
17093
16126
  deselectRef.current = deselect;
17094
16127
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17095
- const lastSiteWideScopeRef = (0, import_react17.useRef)(null);
17096
- (0, import_react17.useEffect)(() => {
16128
+ const lastSiteWideScopeRef = (0, import_react16.useRef)(null);
16129
+ (0, import_react16.useEffect)(() => {
17097
16130
  if (!isEditMode) {
17098
16131
  if (lastSiteWideScopeRef.current !== false) {
17099
16132
  lastSiteWideScopeRef.current = false;
@@ -17119,34 +16152,22 @@ function OhhwellsBridge() {
17119
16152
  isFooterFrameSelection,
17120
16153
  postToParent2
17121
16154
  ]);
17122
- (0, import_react17.useLayoutEffect)(() => {
16155
+ (0, import_react16.useLayoutEffect)(() => {
17123
16156
  if (!subdomain || isEditMode) {
17124
16157
  setFetchState("done");
17125
16158
  return;
17126
16159
  }
17127
16160
  const applyContent = (content) => {
17128
16161
  const imageLoads = [];
17129
- if (typeof content[BRAND_KIT_KEY] === "string") {
17130
- brandKitRef.current = content[BRAND_KIT_KEY];
17131
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17132
- }
17133
16162
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17134
16163
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17135
16164
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17136
16165
  }
17137
- if (typeof content[STYLE_STORE_KEY] === "string") {
17138
- stylesRef.current = content[STYLE_STORE_KEY];
17139
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17140
- }
17141
- applyBrandChrome(content);
17142
16166
  for (const [key, val] of Object.entries(content)) {
17143
16167
  if (key === "__ohw_sections") continue;
17144
16168
  if (key === AI_SECTIONS_KEY) continue;
17145
16169
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17146
16170
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17147
- if (key === BRAND_KIT_KEY) continue;
17148
- if (key === STYLE_STORE_KEY) continue;
17149
- if (BRAND_CHROME_KEYS.has(key)) continue;
17150
16171
  if (applyVideoSettingNode(key, val)) continue;
17151
16172
  if (applyCarouselNode(key, val)) continue;
17152
16173
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17204,9 +16225,7 @@ function OhhwellsBridge() {
17204
16225
  let cancelled = false;
17205
16226
  setFetchState("loading");
17206
16227
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17207
- const initialPath = pathname;
17208
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17209
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16228
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17210
16229
  if (cancelled) return;
17211
16230
  const content = data?.content ?? {};
17212
16231
  contentCache.set(subdomain, content);
@@ -17219,7 +16238,7 @@ function OhhwellsBridge() {
17219
16238
  cancelled = true;
17220
16239
  };
17221
16240
  }, [subdomain, isEditMode]);
17222
- (0, import_react17.useEffect)(() => {
16241
+ (0, import_react16.useEffect)(() => {
17223
16242
  if (!isEditMode) return;
17224
16243
  const resolveIndex = (form, clientY) => {
17225
16244
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17260,7 +16279,7 @@ function OhhwellsBridge() {
17260
16279
  window.removeEventListener("drop", onDrop, true);
17261
16280
  };
17262
16281
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17263
- (0, import_react17.useEffect)(() => {
16282
+ (0, import_react16.useEffect)(() => {
17264
16283
  if (!isEditMode) return;
17265
16284
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17266
16285
  markFormFields(form);
@@ -17272,7 +16291,7 @@ function OhhwellsBridge() {
17272
16291
  });
17273
16292
  return () => observer.disconnect();
17274
16293
  }, [isEditMode, fetchState, pathname]);
17275
- (0, import_react17.useEffect)(() => {
16294
+ (0, import_react16.useEffect)(() => {
17276
16295
  if (!isEditMode) return;
17277
16296
  let saveTimer = null;
17278
16297
  const onInput = (e) => {
@@ -17294,14 +16313,14 @@ function OhhwellsBridge() {
17294
16313
  document.addEventListener("input", onInput, true);
17295
16314
  return () => document.removeEventListener("input", onInput, true);
17296
16315
  }, [isEditMode, persistFields]);
17297
- (0, import_react17.useEffect)(() => {
16316
+ (0, import_react16.useEffect)(() => {
17298
16317
  if (isEditMode || fetchState !== "done") return;
17299
16318
  const content = contentCache.get(subdomain) ?? {};
17300
16319
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17301
16320
  reconcileFieldsFromContent(form, content);
17302
16321
  });
17303
16322
  }, [isEditMode, fetchState, subdomain]);
17304
- (0, import_react17.useEffect)(() => {
16323
+ (0, import_react16.useEffect)(() => {
17305
16324
  if (!isEditMode) return;
17306
16325
  const swallow = (e) => {
17307
16326
  const target = e.target;
@@ -17310,12 +16329,12 @@ function OhhwellsBridge() {
17310
16329
  document.addEventListener("submit", swallow, true);
17311
16330
  return () => document.removeEventListener("submit", swallow, true);
17312
16331
  }, [isEditMode]);
17313
- (0, import_react17.useEffect)(() => {
16332
+ (0, import_react16.useEffect)(() => {
17314
16333
  if (isEditMode || fetchState !== "done") return;
17315
16334
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17316
16335
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17317
16336
  }, [isEditMode, fetchState, subdomain]);
17318
- (0, import_react17.useEffect)(() => {
16337
+ (0, import_react16.useEffect)(() => {
17319
16338
  if (!subdomain || isEditMode) return;
17320
16339
  let debounceTimer = null;
17321
16340
  let observer = null;
@@ -17326,21 +16345,10 @@ function OhhwellsBridge() {
17326
16345
  initSectionInstancesFromContent(content, window.location.pathname);
17327
16346
  observer?.disconnect();
17328
16347
  try {
17329
- applyBrandChrome(content);
17330
- if (typeof content[BRAND_KIT_KEY] === "string") {
17331
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17332
- }
17333
- if (typeof content[STYLE_STORE_KEY] === "string") {
17334
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17335
- }
17336
16348
  for (const [key, val] of Object.entries(content)) {
17337
16349
  if (key === "__ohw_sections") continue;
17338
16350
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17339
16351
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17340
- if (key === BRAND_KIT_KEY) continue;
17341
- if (key === STYLE_STORE_KEY) continue;
17342
- if (key === STYLE_STORE_KEY) continue;
17343
- if (BRAND_CHROME_KEYS.has(key)) continue;
17344
16352
  if (applyVideoSettingNode(key, val)) continue;
17345
16353
  if (applyCarouselNode(key, val)) continue;
17346
16354
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17383,17 +16391,6 @@ function OhhwellsBridge() {
17383
16391
  debounceTimer = setTimeout(applyFromCache, 150);
17384
16392
  };
17385
16393
  applyFromCache();
17386
- const pathCacheKey = `${subdomain}::${pathname}`;
17387
- if (!fetchedContentPaths.has(pathCacheKey)) {
17388
- fetchedContentPaths.add(pathCacheKey);
17389
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17390
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17391
- if (!data?.content) return;
17392
- contentCache.set(subdomain, data.content);
17393
- applyFromCache();
17394
- }).catch(() => {
17395
- });
17396
- }
17397
16394
  observer = new MutationObserver(scheduleApply);
17398
16395
  observer.observe(document.body, { childList: true, subtree: true });
17399
16396
  return () => {
@@ -17401,16 +16398,16 @@ function OhhwellsBridge() {
17401
16398
  if (debounceTimer) clearTimeout(debounceTimer);
17402
16399
  };
17403
16400
  }, [subdomain, isEditMode, pathname]);
17404
- (0, import_react17.useLayoutEffect)(() => {
16401
+ (0, import_react16.useLayoutEffect)(() => {
17405
16402
  const el = document.getElementById("ohw-loader");
17406
16403
  if (!el) return;
17407
16404
  const visible = Boolean(subdomain) && fetchState !== "done";
17408
16405
  el.style.display = visible ? "flex" : "none";
17409
16406
  }, [subdomain, fetchState]);
17410
- (0, import_react17.useEffect)(() => {
16407
+ (0, import_react16.useEffect)(() => {
17411
16408
  postToParent2({ type: "ow:navigation", path: pathname });
17412
16409
  }, [pathname, postToParent2]);
17413
- (0, import_react17.useEffect)(() => {
16410
+ (0, import_react16.useEffect)(() => {
17414
16411
  if (!isEditMode) return;
17415
16412
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17416
16413
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17418,7 +16415,7 @@ function OhhwellsBridge() {
17418
16415
  deselectRef.current();
17419
16416
  deactivateRef.current();
17420
16417
  }, [pathname, isEditMode]);
17421
- (0, import_react17.useEffect)(() => {
16418
+ (0, import_react16.useEffect)(() => {
17422
16419
  const contentForNav = () => {
17423
16420
  if (isEditMode) return editContentRef.current;
17424
16421
  if (!subdomain) return {};
@@ -17485,36 +16482,31 @@ function OhhwellsBridge() {
17485
16482
  observer?.disconnect();
17486
16483
  };
17487
16484
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17488
- (0, import_react17.useEffect)(() => {
16485
+ (0, import_react16.useEffect)(() => {
17489
16486
  if (!isEditMode) return;
17490
- let lastPosted = 0;
17491
16487
  const measure = () => {
17492
16488
  const h = document.body.scrollHeight;
17493
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17494
- lastPosted = h;
17495
- postToParent2({ type: "ow:height", height: h });
17496
- }
17497
- };
17498
- let raf = null;
17499
- const schedule = () => {
17500
- if (raf != null) return;
17501
- raf = requestAnimationFrame(() => {
17502
- raf = null;
17503
- measure();
17504
- });
16489
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17505
16490
  };
17506
16491
  const t1 = setTimeout(measure, 50);
17507
16492
  const t2 = setTimeout(measure, 500);
17508
- const ro = new ResizeObserver(schedule);
17509
- ro.observe(document.body);
16493
+ let lastWidth = window.innerWidth;
16494
+ let resizeTimer = null;
16495
+ const handleResize = () => {
16496
+ if (window.innerWidth === lastWidth) return;
16497
+ lastWidth = window.innerWidth;
16498
+ if (resizeTimer) clearTimeout(resizeTimer);
16499
+ resizeTimer = setTimeout(measure, 150);
16500
+ };
16501
+ window.addEventListener("resize", handleResize);
17510
16502
  return () => {
17511
16503
  clearTimeout(t1);
17512
16504
  clearTimeout(t2);
17513
- if (raf != null) cancelAnimationFrame(raf);
17514
- ro.disconnect();
16505
+ if (resizeTimer) clearTimeout(resizeTimer);
16506
+ window.removeEventListener("resize", handleResize);
17515
16507
  };
17516
16508
  }, [pathname, isEditMode, postToParent2]);
17517
- (0, import_react17.useEffect)(() => {
16509
+ (0, import_react16.useEffect)(() => {
17518
16510
  if (!subdomainFromQuery || isEditMode) return;
17519
16511
  const handleClick = (e) => {
17520
16512
  const anchor = e.target.closest("a");
@@ -17530,7 +16522,7 @@ function OhhwellsBridge() {
17530
16522
  document.addEventListener("click", handleClick, true);
17531
16523
  return () => document.removeEventListener("click", handleClick, true);
17532
16524
  }, [subdomainFromQuery, isEditMode, router]);
17533
- (0, import_react17.useEffect)(() => {
16525
+ (0, import_react16.useEffect)(() => {
17534
16526
  if (!isEditMode) {
17535
16527
  editStylesRef.current?.base.remove();
17536
16528
  editStylesRef.current?.forceHover.remove();
@@ -17692,21 +16684,16 @@ function OhhwellsBridge() {
17692
16684
  return;
17693
16685
  }
17694
16686
  const target = e.target;
17695
- if (target.closest("[data-ohw-ai-review]")) return;
17696
16687
  if (target.closest("[data-ohw-toolbar]")) return;
17697
16688
  if (target.closest("[data-ohw-state-toggle]")) return;
17698
16689
  if (target.closest("[data-ohw-max-badge]")) return;
17699
16690
  if (isInsideLinkEditor(target)) return;
17700
- if (isInsideFloatingPanel(target)) return;
17701
16691
  if (target.closest("[data-ohw-form-toolbar]")) return;
17702
16692
  if (target.closest(
17703
16693
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17704
16694
  )) {
17705
16695
  return;
17706
16696
  }
17707
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
17708
- clearMediaSelectionRef.current();
17709
- }
17710
16697
  {
17711
16698
  const formEl = getFormElement(target);
17712
16699
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -17854,11 +16841,8 @@ function OhhwellsBridge() {
17854
16841
  if (isMediaEditable(editable) && !buttonOnMedia) {
17855
16842
  e.preventDefault();
17856
16843
  e.stopPropagation();
17857
- if (selectedMediaElRef.current === editable) {
17858
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17859
- } else {
17860
- selectMediaElementRef.current(editable);
17861
- }
16844
+ aiSectionApiRef.current?.selectFromElement(editable);
16845
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17862
16846
  return;
17863
16847
  }
17864
16848
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
@@ -17977,12 +16961,10 @@ function OhhwellsBridge() {
17977
16961
  };
17978
16962
  const handleDblClick = (e) => {
17979
16963
  const target = e.target;
17980
- if (target.closest("[data-ohw-ai-review]")) return;
17981
16964
  if (target.closest("[data-ohw-toolbar]")) return;
17982
16965
  if (target.closest("[data-ohw-state-toggle]")) return;
17983
16966
  if (target.closest("[data-ohw-max-badge]")) return;
17984
16967
  if (isInsideLinkEditor(target)) return;
17985
- if (isInsideFloatingPanel(target)) return;
17986
16968
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
17987
16969
  return;
17988
16970
  }
@@ -18023,14 +17005,11 @@ function OhhwellsBridge() {
18023
17005
  setSiblingHintRects([]);
18024
17006
  return;
18025
17007
  }
18026
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
17008
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
18027
17009
  hoveredItemElRef.current = null;
18028
17010
  setHoveredItemRect(null);
18029
17011
  hoveredNavContainerRef.current = null;
18030
17012
  setHoveredNavContainerRect(null);
18031
- siblingHintElRef.current = null;
18032
- setSiblingHintRect(null);
18033
- setSiblingHintRects([]);
18034
17013
  return;
18035
17014
  }
18036
17015
  {
@@ -18139,6 +17118,7 @@ function OhhwellsBridge() {
18139
17118
  hoveredNavContainerRef.current = null;
18140
17119
  setHoveredNavContainerRect(null);
18141
17120
  hoveredItemElRef.current = editable;
17121
+ setHoveredItemRect(editable.getBoundingClientRect());
18142
17122
  }
18143
17123
  }
18144
17124
  }
@@ -18435,7 +17415,7 @@ function OhhwellsBridge() {
18435
17415
  }
18436
17416
  };
18437
17417
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18438
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17418
+ if (linkPopoverOpenRef.current) {
18439
17419
  if (hoveredImageRef.current) {
18440
17420
  hoveredImageRef.current = null;
18441
17421
  hoveredImageHasTextOverlapRef.current = false;
@@ -18451,6 +17431,11 @@ function OhhwellsBridge() {
18451
17431
  probeNavigationHoverAt(x, y);
18452
17432
  return;
18453
17433
  }
17434
+ if (isPointOverLogo(x, y)) {
17435
+ dismissImageHover();
17436
+ probeNavigationHoverAt(x, y);
17437
+ return;
17438
+ }
18454
17439
  const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
18455
17440
  '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
18456
17441
  );
@@ -18689,7 +17674,7 @@ function OhhwellsBridge() {
18689
17674
  }
18690
17675
  };
18691
17676
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18692
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17677
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18693
17678
  if (activeStateElRef.current) {
18694
17679
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18695
17680
  activeStateElRef.current = null;
@@ -18764,7 +17749,8 @@ function OhhwellsBridge() {
18764
17749
  };
18765
17750
  const handleMouseMove = (e) => {
18766
17751
  const { clientX, clientY } = e;
18767
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17752
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17753
+ if (isOverEditorChrome(clientX, clientY)) {
18768
17754
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18769
17755
  formHoverElRef.current = null;
18770
17756
  setFormHoverRect(null);
@@ -18772,12 +17758,6 @@ function OhhwellsBridge() {
18772
17758
  setHoveredItemRect(null);
18773
17759
  hoveredNavContainerRef.current = null;
18774
17760
  setHoveredNavContainerRect(null);
18775
- siblingHintElRef.current = null;
18776
- setSiblingHintRect(null);
18777
- setSiblingHintRects([]);
18778
- dismissImageHover();
18779
- clearImageHover();
18780
- setSectionGap(null);
18781
17761
  return;
18782
17762
  }
18783
17763
  probeSectionGapAt(clientX, clientY);
@@ -18788,11 +17768,7 @@ function OhhwellsBridge() {
18788
17768
  if (e.data?.type !== "ow:pointer-sync") return;
18789
17769
  const { clientX, clientY } = e.data;
18790
17770
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18791
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18792
- dismissImageHover();
18793
- clearImageHover();
18794
- return;
18795
- }
17771
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18796
17772
  probeSectionGapAt(clientX, clientY);
18797
17773
  probeImageAt(clientX, clientY);
18798
17774
  probeHoverCardsAt(clientX, clientY);
@@ -19038,19 +18014,10 @@ function OhhwellsBridge() {
19038
18014
  if (e.data?.type !== "ow:hydrate") return;
19039
18015
  const content = e.data.content;
19040
18016
  if (!content) return;
19041
- if (typeof content[BRAND_KIT_KEY] === "string") {
19042
- brandKitRef.current = content[BRAND_KIT_KEY];
19043
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19044
- }
19045
18017
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19046
18018
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19047
18019
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19048
18020
  }
19049
- if (typeof content[STYLE_STORE_KEY] === "string") {
19050
- stylesRef.current = content[STYLE_STORE_KEY];
19051
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19052
- }
19053
- applyBrandChrome(content);
19054
18021
  let sectionsJson = null;
19055
18022
  for (const [key, val] of Object.entries(content)) {
19056
18023
  if (key === "__ohw_sections") {
@@ -19060,9 +18027,6 @@ function OhhwellsBridge() {
19060
18027
  if (key === AI_SECTIONS_KEY) continue;
19061
18028
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19062
18029
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19063
- if (key === BRAND_KIT_KEY) continue;
19064
- if (key === STYLE_STORE_KEY) continue;
19065
- if (BRAND_CHROME_KEYS.has(key)) continue;
19066
18030
  if (applyVideoSettingNode(key, val)) continue;
19067
18031
  if (applyCarouselNode(key, val)) continue;
19068
18032
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19164,10 +18128,7 @@ function OhhwellsBridge() {
19164
18128
  const payload = e.data.payload;
19165
18129
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19166
18130
  const previous = aiSectionsRef.current;
19167
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19168
- ...payload,
19169
- path: payload.path ?? window.location.pathname
19170
- });
18131
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19171
18132
  const nextValue = serializeAiSectionsState(nextState);
19172
18133
  aiSectionsRef.current = nextValue;
19173
18134
  applyAiSectionsToDom(nextState);
@@ -19204,55 +18165,12 @@ function OhhwellsBridge() {
19204
18165
  const value = typeof e.data.value === "string" ? e.data.value : "";
19205
18166
  aiSectionsRef.current = value;
19206
18167
  applyAiSectionsToDom(parseAiSectionsState(value));
19207
- applyStylesToDom(parseStyleStore(stylesRef.current));
19208
18168
  const restoredHeight = document.documentElement.scrollHeight;
19209
18169
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19210
18170
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19211
18171
  postAiSectionsChanged();
19212
18172
  };
19213
18173
  window.addEventListener("message", handleAiSetSections);
19214
- const handleMoveSection = (e) => {
19215
- if (e.data?.type !== "ow:move-section") return;
19216
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19217
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19218
- if (!instanceId || !direction) return;
19219
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19220
- if (!entries) return;
19221
- const orderJson = JSON.stringify(entries);
19222
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19223
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19224
- window.dispatchEvent(new Event("resize"));
19225
- };
19226
- window.addEventListener("message", handleMoveSection);
19227
- const handleAiSetBrand = (e) => {
19228
- if (e.data?.type !== "ow:ai-set-brand") return;
19229
- const value = typeof e.data.value === "string" ? e.data.value : "";
19230
- const previous = brandKitRef.current;
19231
- brandKitRef.current = value;
19232
- applyBrandToDom(parseBrandKit(value));
19233
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19234
- applyStylesToDom(parseStyleStore(stylesRef.current));
19235
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19236
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19237
- };
19238
- window.addEventListener("message", handleAiSetBrand);
19239
- const handleAiSetStyles = (e) => {
19240
- if (e.data?.type !== "ow:ai-set-styles") return;
19241
- const value = typeof e.data.value === "string" ? e.data.value : "";
19242
- const previous = stylesRef.current;
19243
- stylesRef.current = value;
19244
- applyStylesToDom(parseStyleStore(value));
19245
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19246
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19247
- };
19248
- window.addEventListener("message", handleAiSetStyles);
19249
- const handleGetBrand = (e) => {
19250
- if (e.data?.type !== "ow:get-brand") return;
19251
- const template = deriveTemplateBrand();
19252
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19253
- postToParentRef.current({ type: "ow:brand-value", value });
19254
- };
19255
- window.addEventListener("message", handleGetBrand);
19256
18174
  const handleDeactivate = (e) => {
19257
18175
  if (e.data?.type !== "ow:deactivate") return;
19258
18176
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
@@ -19261,12 +18179,6 @@ function OhhwellsBridge() {
19261
18179
  closeLinkPopoverRef.current();
19262
18180
  return;
19263
18181
  }
19264
- if (floatingPanelOpenRef.current) {
19265
- setFloatingPanelRef.current(null);
19266
- deselectRef.current();
19267
- deactivateRef.current();
19268
- return;
19269
- }
19270
18182
  deselectRef.current();
19271
18183
  deactivateRef.current();
19272
18184
  };
@@ -19354,10 +18266,6 @@ function OhhwellsBridge() {
19354
18266
  const handleKeyDown = (e) => {
19355
18267
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19356
18268
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19357
- if (e.key === "Escape" && selectedMediaElRef.current) {
19358
- clearMediaSelectionRef.current();
19359
- return;
19360
- }
19361
18269
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19362
18270
  e.preventDefault();
19363
18271
  selectAllTextInEditable(activeElRef.current);
@@ -19517,12 +18425,6 @@ function OhhwellsBridge() {
19517
18425
  if (aiSectionsRef.current) {
19518
18426
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19519
18427
  }
19520
- if (stylesRef.current) {
19521
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19522
- }
19523
- if (brandKitRef.current) {
19524
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19525
- }
19526
18428
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19527
18429
  const formKey = formKeyOf(form);
19528
18430
  if (!formKey) return;
@@ -19540,12 +18442,8 @@ function OhhwellsBridge() {
19540
18442
  if (inserted) {
19541
18443
  const tracker = getSectionsTracker();
19542
18444
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19543
- const reportHeight = () => {
19544
- const h = document.body.scrollHeight;
19545
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19546
- };
19547
- reportHeight();
19548
- setTimeout(reportHeight, 500);
18445
+ const h = document.documentElement.scrollHeight;
18446
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19549
18447
  }
19550
18448
  };
19551
18449
  const handleSwitchSchedule = (e) => {
@@ -19932,10 +18830,6 @@ function OhhwellsBridge() {
19932
18830
  window.removeEventListener("message", handleAiApplyTree);
19933
18831
  window.removeEventListener("message", handleAiDeleteSection);
19934
18832
  window.removeEventListener("message", handleAiSetSections);
19935
- window.removeEventListener("message", handleMoveSection);
19936
- window.removeEventListener("message", handleAiSetBrand);
19937
- window.removeEventListener("message", handleAiSetStyles);
19938
- window.removeEventListener("message", handleGetBrand);
19939
18833
  window.removeEventListener("message", handleDeactivate);
19940
18834
  window.removeEventListener("message", handleToastAction);
19941
18835
  window.removeEventListener("message", handleFormCount);
@@ -19946,7 +18840,7 @@ function OhhwellsBridge() {
19946
18840
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
19947
18841
  };
19948
18842
  }, [isEditMode, refreshStateRules]);
19949
- (0, import_react17.useEffect)(() => {
18843
+ (0, import_react16.useEffect)(() => {
19950
18844
  if (!isEditMode) return;
19951
18845
  const THRESHOLD = 10;
19952
18846
  const resolveWasSelected = (el) => {
@@ -20102,7 +18996,7 @@ function OhhwellsBridge() {
20102
18996
  unlockFooterDragInteraction();
20103
18997
  };
20104
18998
  }, [isEditMode]);
20105
- (0, import_react17.useEffect)(() => {
18999
+ (0, import_react16.useEffect)(() => {
20106
19000
  const handler = (e) => {
20107
19001
  if (e.data?.type !== "ow:request-schedule-config") return;
20108
19002
  const insertAfterVal = e.data.insertAfter;
@@ -20118,7 +19012,7 @@ function OhhwellsBridge() {
20118
19012
  window.addEventListener("message", handler);
20119
19013
  return () => window.removeEventListener("message", handler);
20120
19014
  }, [processConfigRequest]);
20121
- (0, import_react17.useEffect)(() => {
19015
+ (0, import_react16.useEffect)(() => {
20122
19016
  if (!isEditMode) return;
20123
19017
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20124
19018
  el.removeAttribute("data-ohw-active-state");
@@ -20142,7 +19036,7 @@ function OhhwellsBridge() {
20142
19036
  postToParent2({
20143
19037
  type: "ow:ready",
20144
19038
  version: "1",
20145
- bridgeVersion: "0.1.67",
19039
+ bridgeVersion: "0.1.66",
20146
19040
  path: pathname,
20147
19041
  nodes: collectEditableNodes(editContentRef.current),
20148
19042
  sections
@@ -20154,13 +19048,13 @@ function OhhwellsBridge() {
20154
19048
  clearTimeout(timer);
20155
19049
  };
20156
19050
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20157
- (0, import_react17.useEffect)(() => {
19051
+ (0, import_react16.useEffect)(() => {
20158
19052
  scrollToHashSectionWhenReady();
20159
19053
  const onHashChange = () => scrollToHashSectionWhenReady();
20160
19054
  window.addEventListener("hashchange", onHashChange);
20161
19055
  return () => window.removeEventListener("hashchange", onHashChange);
20162
19056
  }, [pathname]);
20163
- const handleCommand = (0, import_react17.useCallback)((cmd) => {
19057
+ const handleCommand = (0, import_react16.useCallback)((cmd) => {
20164
19058
  const el = activeElRef.current;
20165
19059
  const selBefore = window.getSelection();
20166
19060
  let savedOffsets = null;
@@ -20196,7 +19090,7 @@ function OhhwellsBridge() {
20196
19090
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20197
19091
  refreshActiveCommandsRef.current();
20198
19092
  }, []);
20199
- (0, import_react17.useEffect)(() => {
19093
+ (0, import_react16.useEffect)(() => {
20200
19094
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20201
19095
  if (!session || !logoSizeDraft) return;
20202
19096
  const onPanelAction = (e) => {
@@ -20234,7 +19128,7 @@ function OhhwellsBridge() {
20234
19128
  window.addEventListener("message", onPanelAction);
20235
19129
  return () => window.removeEventListener("message", onPanelAction);
20236
19130
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20237
- const handleStateChange = (0, import_react17.useCallback)((state) => {
19131
+ const handleStateChange = (0, import_react16.useCallback)((state) => {
20238
19132
  if (!activeStateElRef.current) return;
20239
19133
  const el = activeStateElRef.current;
20240
19134
  if (state === "Default") {
@@ -20247,7 +19141,7 @@ function OhhwellsBridge() {
20247
19141
  }
20248
19142
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20249
19143
  }, [deactivate]);
20250
- const reselectAfterLinkPopover = (0, import_react17.useCallback)(
19144
+ const reselectAfterLinkPopover = (0, import_react16.useCallback)(
20251
19145
  (hrefKey) => {
20252
19146
  requestAnimationFrame(() => {
20253
19147
  const el = resolveHrefKeyElement(hrefKey);
@@ -20256,7 +19150,7 @@ function OhhwellsBridge() {
20256
19150
  },
20257
19151
  [resolveHrefKeyElement]
20258
19152
  );
20259
- const closeLinkPopover = (0, import_react17.useCallback)(() => {
19153
+ const closeLinkPopover = (0, import_react16.useCallback)(() => {
20260
19154
  const session = linkPopoverSessionRef.current;
20261
19155
  addNavAfterAnchorRef.current = null;
20262
19156
  setLinkPopover(null);
@@ -20264,9 +19158,9 @@ function OhhwellsBridge() {
20264
19158
  reselectAfterLinkPopover(session.key);
20265
19159
  }
20266
19160
  }, [reselectAfterLinkPopover]);
20267
- const closeLinkPopoverRef = (0, import_react17.useRef)(closeLinkPopover);
19161
+ const closeLinkPopoverRef = (0, import_react16.useRef)(closeLinkPopover);
20268
19162
  closeLinkPopoverRef.current = closeLinkPopover;
20269
- const openLinkPopoverForActive = (0, import_react17.useCallback)(() => {
19163
+ const openLinkPopoverForActive = (0, import_react16.useCallback)(() => {
20270
19164
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20271
19165
  if (!hrefCtx) return;
20272
19166
  bumpLinkPopoverGrace();
@@ -20277,7 +19171,7 @@ function OhhwellsBridge() {
20277
19171
  });
20278
19172
  deactivate();
20279
19173
  }, [deactivate]);
20280
- const openLinkPopoverForSelected = (0, import_react17.useCallback)(() => {
19174
+ const openLinkPopoverForSelected = (0, import_react16.useCallback)(() => {
20281
19175
  const anchor = selectedElRef.current;
20282
19176
  if (!anchor) return;
20283
19177
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20294,7 +19188,7 @@ function OhhwellsBridge() {
20294
19188
  });
20295
19189
  deselect();
20296
19190
  }, [deselect]);
20297
- const handleSelectParent = (0, import_react17.useCallback)(() => {
19191
+ const handleSelectParent = (0, import_react16.useCallback)(() => {
20298
19192
  const selected = selectedElRef.current;
20299
19193
  if (!selected) return;
20300
19194
  if (toolbarVariantRef.current === "select-frame") {
@@ -20321,7 +19215,7 @@ function OhhwellsBridge() {
20321
19215
  }
20322
19216
  deselectRef.current();
20323
19217
  }, []);
20324
- const handleDuplicateSelected = (0, import_react17.useCallback)(() => {
19218
+ const handleDuplicateSelected = (0, import_react16.useCallback)(() => {
20325
19219
  const selected = selectedElRef.current;
20326
19220
  if (!selected || !isNavigationItem2(selected)) return;
20327
19221
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20437,7 +19331,7 @@ function OhhwellsBridge() {
20437
19331
  });
20438
19332
  }
20439
19333
  }, [postToParent2]);
20440
- const runPendingDeleteUndo = (0, import_react17.useCallback)(() => {
19334
+ const runPendingDeleteUndo = (0, import_react16.useCallback)(() => {
20441
19335
  const pending = pendingDeleteUndoRef.current;
20442
19336
  if (!pending) return false;
20443
19337
  pendingDeleteUndoRef.current = null;
@@ -20445,7 +19339,7 @@ function OhhwellsBridge() {
20445
19339
  enforceLinkHrefs();
20446
19340
  return true;
20447
19341
  }, []);
20448
- const handleDeleteSelected = (0, import_react17.useCallback)(() => {
19342
+ const handleDeleteSelected = (0, import_react16.useCallback)(() => {
20449
19343
  const selected = selectedElRef.current;
20450
19344
  if (!selected) return false;
20451
19345
  return deleteSelectedNavFooterItem({
@@ -20466,7 +19360,7 @@ function OhhwellsBridge() {
20466
19360
  }, [postToParent2]);
20467
19361
  handleDeleteSelectedRef.current = handleDeleteSelected;
20468
19362
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20469
- const handleLinkPopoverSubmit = (0, import_react17.useCallback)(
19363
+ const handleLinkPopoverSubmit = (0, import_react16.useCallback)(
20470
19364
  (target) => {
20471
19365
  const session = linkPopoverSessionRef.current;
20472
19366
  if (!session) return;
@@ -20532,30 +19426,19 @@ function OhhwellsBridge() {
20532
19426
  const showEditLink = toolbarShowEditLink;
20533
19427
  const currentSections = sectionsByPath[pathname] ?? [];
20534
19428
  linkPopoverOpenRef.current = linkPopover !== null;
20535
- const handleMediaSelect = (0, import_react17.useCallback)((key) => {
20536
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
20537
- (m) => (m.dataset.ohwKey ?? "") === key
20538
- ) ?? null;
20539
- if (!el) return;
20540
- selectMediaElementRef.current(el);
20541
- }, []);
20542
- const handleMediaReplace = (0, import_react17.useCallback)(
19429
+ const handleMediaReplace = (0, import_react16.useCallback)(
20543
19430
  (key) => {
20544
- postToParent2({
20545
- type: "ow:image-pick",
20546
- key,
20547
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
20548
- });
19431
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20549
19432
  },
20550
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19433
+ [postToParent2, mediaHover?.elementType]
20551
19434
  );
20552
- const handleEditCarousel = (0, import_react17.useCallback)(
19435
+ const handleEditCarousel = (0, import_react16.useCallback)(
20553
19436
  (key) => {
20554
19437
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20555
19438
  },
20556
19439
  [postToParent2]
20557
19440
  );
20558
- const handleMediaFadeOutComplete = (0, import_react17.useCallback)((key) => {
19441
+ const handleMediaFadeOutComplete = (0, import_react16.useCallback)((key) => {
20559
19442
  setUploadingRects((prev) => {
20560
19443
  if (!(key in prev)) return prev;
20561
19444
  const next = { ...prev };
@@ -20563,7 +19446,7 @@ function OhhwellsBridge() {
20563
19446
  return next;
20564
19447
  });
20565
19448
  }, []);
20566
- const handleVideoSettingsChange = (0, import_react17.useCallback)(
19449
+ const handleVideoSettingsChange = (0, import_react16.useCallback)(
20567
19450
  (key, settings) => {
20568
19451
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20569
19452
  const video = getVideoEl2(el);
@@ -20585,506 +19468,414 @@ function OhhwellsBridge() {
20585
19468
  },
20586
19469
  [postToParent2]
20587
19470
  );
20588
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20589
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(OhwLoaderSpinner, {}) }),
20590
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20591
- bridgeRoot ? (0, import_react_dom4.createPortal)(
20592
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20593
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20594
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20595
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20596
- "div",
20597
- {
20598
- className: "pointer-events-none fixed z-2147483646",
20599
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20600
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20601
- DropIndicator,
20602
- {
20603
- direction: "horizontal",
20604
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20605
- className: "!h-full !w-full"
20606
- }
20607
- )
20608
- },
20609
- `section-drop-${slot.insertIndex}-${i}`
20610
- )),
20611
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20612
- MediaOverlay,
20613
- {
20614
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20615
- isUploading: true,
20616
- fadingOut,
20617
- onFadeOutComplete: handleMediaFadeOutComplete,
20618
- onReplace: handleMediaReplace
20619
- },
20620
- `uploading-${key}`
20621
- )),
20622
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20623
- MediaOverlay,
20624
- {
20625
- hover: mediaHover,
20626
- isUploading: false,
20627
- onReplace: handleMediaReplace,
20628
- onSelect: handleMediaSelect,
20629
- onVideoSettingsChange: handleVideoSettingsChange
20630
- }
20631
- ),
20632
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20633
- MediaOverlay,
20634
- {
20635
- hover: selectedMedia,
20636
- selected: true,
20637
- hovered: mediaHover?.key === selectedMedia.key,
20638
- isUploading: false,
20639
- onReplace: handleMediaReplace,
20640
- onSelect: handleMediaSelect,
20641
- onVideoSettingsChange: handleVideoSettingsChange
20642
- }
20643
- ),
20644
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20645
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20646
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20647
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20648
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20649
- "div",
20650
- {
20651
- className: "pointer-events-none fixed z-2147483646",
20652
- style: {
20653
- left: slot.left,
20654
- top: slot.top,
20655
- width: slot.width,
20656
- height: slot.height
20657
- },
20658
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20659
- DropIndicator,
20660
- {
20661
- direction: slot.direction,
20662
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20663
- className: "!h-full !w-full"
20664
- }
20665
- )
20666
- },
20667
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20668
- )),
20669
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20670
- "div",
20671
- {
20672
- className: "pointer-events-none fixed z-2147483646",
20673
- style: {
20674
- left: slot.left,
20675
- top: slot.top,
20676
- width: slot.width,
20677
- height: slot.height
20678
- },
20679
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20680
- DropIndicator,
20681
- {
20682
- direction: slot.direction,
20683
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20684
- className: "!h-full !w-full"
20685
- }
20686
- )
19471
+ return bridgeRoot ? (0, import_react_dom4.createPortal)(
19472
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19473
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19474
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19475
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19476
+ MediaOverlay,
19477
+ {
19478
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19479
+ isUploading: true,
19480
+ fadingOut,
19481
+ onFadeOutComplete: handleMediaFadeOutComplete,
19482
+ onReplace: handleMediaReplace
19483
+ },
19484
+ `uploading-${key}`
19485
+ )),
19486
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19487
+ MediaOverlay,
19488
+ {
19489
+ hover: mediaHover,
19490
+ isUploading: false,
19491
+ onReplace: handleMediaReplace,
19492
+ onVideoSettingsChange: handleVideoSettingsChange
19493
+ }
19494
+ ),
19495
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19496
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19497
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19498
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19499
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19500
+ "div",
19501
+ {
19502
+ className: "pointer-events-none fixed z-2147483646",
19503
+ style: {
19504
+ left: slot.left,
19505
+ top: slot.top,
19506
+ width: slot.width,
19507
+ height: slot.height
20687
19508
  },
20688
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20689
- )),
20690
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20691
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20692
- hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20693
- formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20694
- ItemInteractionLayer,
20695
- {
20696
- rect: formPickRect,
20697
- state: "active-top",
20698
- itemDragSurface: false,
20699
- toolbarAlign: "left",
20700
- chromeGap: 24,
20701
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20702
- "div",
20703
- {
20704
- "data-ohw-form-toolbar": "",
20705
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20706
- children: [
20707
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20708
- "button",
20709
- {
20710
- type: "button",
20711
- "aria-label": "Add field",
20712
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20713
- onClick: () => setFieldTypePickerOpen((open) => !open),
20714
- "data-ohw-add-field": "",
20715
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
20716
- }
20717
- ),
20718
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20719
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20720
- "button",
20721
- {
20722
- type: "button",
20723
- 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",
20724
- onClick: () => {
20725
- const form = formPickElRef.current;
20726
- if (!form) return;
20727
- postToParent2({
20728
- type: "ow:form-pick",
20729
- formKey: formKeyOf(form),
20730
- hasLongText: formHasLongText(form)
20731
- });
20732
- },
20733
- children: [
20734
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
20735
- "Form settings",
20736
- formPickCount ? (
20737
- // Counter pill, per the design — not a text suffix.
20738
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20739
- "span",
20740
- {
20741
- "data-ohw-form-count": "",
20742
- 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",
20743
- children: formPickCount
20744
- }
20745
- )
20746
- ) : null
20747
- ]
20748
- }
20749
- ),
20750
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20751
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20752
- "button",
20753
- {
20754
- type: "button",
20755
- "aria-pressed": formViewState === state,
20756
- 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"),
20757
- onClick: () => {
20758
- const form = formPickElRef.current;
20759
- const key = form ? formKeyOf(form) : null;
20760
- if (!form || !key) return;
20761
- const initial = successInitialFor(form, key, editContentRef.current);
20762
- setFormViewState(form, key, state, initial);
20763
- setFormViewStateUi(state);
20764
- setFormPickRect(form.getBoundingClientRect());
20765
- if (state === "success") {
20766
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20767
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20768
- } else {
20769
- deactivateRef.current();
20770
- }
20771
- },
20772
- children: state
20773
- },
20774
- state
20775
- )) })
20776
- ]
20777
- }
20778
- )
20779
- }
20780
- ),
20781
- formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20782
- ItemInteractionLayer,
20783
- {
20784
- rect: formHoverRect,
20785
- state: "hover",
20786
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20787
- }
20788
- ),
20789
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20790
- ItemInteractionLayer,
20791
- {
20792
- rect: fieldPickRect,
20793
- state: fieldDragging ? "dragging" : "active-top",
20794
- itemDragSurface: false,
20795
- toolbarAlign: "left",
20796
- chromeGap: 10,
20797
- showHandle: true,
20798
- dragHandleLabel: "Reorder field",
20799
- onDragHandleDragStart: handleFieldDragStart,
20800
- onDragHandleDragEnd: handleFieldDragEnd,
20801
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20802
- FormFieldToolbar,
20803
- {
20804
- type: fieldPickState.type,
20805
- required: fieldPickState.required,
20806
- onTypeChange: handleFieldTypeChange,
20807
- onRequiredToggle: handleFieldRequiredToggle,
20808
- onDuplicate: handleFieldDuplicate,
20809
- onDelete: handleFieldDelete
20810
- }
20811
- )
20812
- }
20813
- ),
20814
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20815
- "div",
20816
- {
20817
- className: "pointer-events-none fixed z-[2147483644]",
20818
- style: { top: slot.top, left: slot.left, width: slot.width },
20819
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20820
- DropIndicator,
20821
- {
20822
- direction: "horizontal",
20823
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20824
- className: "!w-full"
20825
- }
20826
- )
19509
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19510
+ DropIndicator,
19511
+ {
19512
+ direction: slot.direction,
19513
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19514
+ className: "!h-full !w-full"
19515
+ }
19516
+ )
19517
+ },
19518
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19519
+ )),
19520
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19521
+ "div",
19522
+ {
19523
+ className: "pointer-events-none fixed z-2147483646",
19524
+ style: {
19525
+ left: slot.left,
19526
+ top: slot.top,
19527
+ width: slot.width,
19528
+ height: slot.height
20827
19529
  },
20828
- `field-drop-${i}`
20829
- )) : null,
20830
- fieldTypePickerOpen && formPickRect ? (() => {
20831
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20832
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20833
- "div",
19530
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19531
+ DropIndicator,
20834
19532
  {
20835
- className: "pointer-events-none fixed z-[2147483645]",
20836
- style: {
20837
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20838
- left: toolbar ? toolbar.left : formPickRect.left + 24
20839
- },
20840
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
19533
+ direction: slot.direction,
19534
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19535
+ className: "!h-full !w-full"
20841
19536
  }
20842
- );
20843
- })() : null,
20844
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20845
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20846
- FooterContainerChrome,
20847
- {
20848
- rect: toolbarRect,
20849
- onAdd: handleAddFooterColumn,
20850
- addDisabled: !canAddFooterColumn()
20851
- }
20852
- ),
20853
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20854
- ItemInteractionLayer,
20855
- {
20856
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20857
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20858
- elRef: glowElRef,
20859
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20860
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20861
- dragDisabled: reorderDragDisabled,
20862
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20863
- onDragHandleDragStart: handleItemDragStart,
20864
- onDragHandleDragEnd: handleItemDragEnd,
20865
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20866
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20867
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20868
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20869
- ItemActionToolbar,
20870
- {
20871
- onEditLink: openLinkPopoverForSelected,
20872
- onStyle: () => {
20873
- const row = selectedElRef.current;
20874
- if (!row) return;
20875
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20876
- else openSocialsDisplayPanel(row);
20877
- },
20878
- showStyle: selectedIsSocialsRow,
20879
- styleActive: floatingPanel?.kind === "socials-display",
20880
- onAddItem: handleAddChildItem,
20881
- onSelectParent: handleSelectParent,
20882
- onDuplicate: handleDuplicateSelected,
20883
- onDelete: handleDeleteSelected,
20884
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20885
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20886
- return row ? !canAddSocialItem(row) : false;
20887
- })(),
20888
- editLinkDisabled: false,
20889
- moreDisabled: false,
20890
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20891
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20892
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20893
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19537
+ )
19538
+ },
19539
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19540
+ )),
19541
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19542
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19543
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19544
+ formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19545
+ ItemInteractionLayer,
19546
+ {
19547
+ rect: formPickRect,
19548
+ state: "active-top",
19549
+ itemDragSurface: false,
19550
+ toolbarAlign: "left",
19551
+ chromeGap: 24,
19552
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19553
+ "div",
19554
+ {
19555
+ "data-ohw-form-toolbar": "",
19556
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19557
+ children: [
19558
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19559
+ "button",
19560
+ {
19561
+ type: "button",
19562
+ "aria-label": "Add field",
19563
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19564
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19565
+ "data-ohw-add-field": "",
19566
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Plus, { size: 15, "aria-hidden": true })
19567
+ }
20894
19568
  ),
20895
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20896
- dropdownOpen: navDropdownPreviewOpen,
20897
- onDropdownOpenChange: handleNavDropdownOpenChange,
20898
- headingVisible: footerHeadingVisible,
20899
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20900
- }
20901
- ) : void 0
20902
- }
20903
- ),
20904
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
20905
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20906
- EditGlowChrome,
19569
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19570
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19571
+ "button",
19572
+ {
19573
+ type: "button",
19574
+ 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",
19575
+ onClick: () => {
19576
+ const form = formPickElRef.current;
19577
+ if (!form) return;
19578
+ postToParent2({
19579
+ type: "ow:form-pick",
19580
+ formKey: formKeyOf(form),
19581
+ hasLongText: formHasLongText(form)
19582
+ });
19583
+ },
19584
+ children: [
19585
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Settings, { size: 14, "aria-hidden": true }),
19586
+ "Form settings",
19587
+ formPickCount ? (
19588
+ // Counter pill, per the design — not a text suffix.
19589
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19590
+ "span",
19591
+ {
19592
+ "data-ohw-form-count": "",
19593
+ 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",
19594
+ children: formPickCount
19595
+ }
19596
+ )
19597
+ ) : null
19598
+ ]
19599
+ }
19600
+ ),
19601
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19602
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19603
+ "button",
19604
+ {
19605
+ type: "button",
19606
+ "aria-pressed": formViewState === state,
19607
+ 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"),
19608
+ onClick: () => {
19609
+ const form = formPickElRef.current;
19610
+ const key = form ? formKeyOf(form) : null;
19611
+ if (!form || !key) return;
19612
+ const initial = successInitialFor(form, key, editContentRef.current);
19613
+ setFormViewState(form, key, state, initial);
19614
+ setFormViewStateUi(state);
19615
+ setFormPickRect(form.getBoundingClientRect());
19616
+ if (state === "success") {
19617
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19618
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19619
+ } else {
19620
+ deactivateRef.current();
19621
+ }
19622
+ },
19623
+ children: state
19624
+ },
19625
+ state
19626
+ )) })
19627
+ ]
19628
+ }
19629
+ )
19630
+ }
19631
+ ),
19632
+ formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19633
+ ItemInteractionLayer,
19634
+ {
19635
+ rect: formHoverRect,
19636
+ state: "hover",
19637
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19638
+ }
19639
+ ),
19640
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19641
+ ItemInteractionLayer,
19642
+ {
19643
+ rect: fieldPickRect,
19644
+ state: fieldDragging ? "dragging" : "active-top",
19645
+ itemDragSurface: false,
19646
+ toolbarAlign: "left",
19647
+ chromeGap: 10,
19648
+ showHandle: true,
19649
+ dragHandleLabel: "Reorder field",
19650
+ onDragHandleDragStart: handleFieldDragStart,
19651
+ onDragHandleDragEnd: handleFieldDragEnd,
19652
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19653
+ FormFieldToolbar,
20907
19654
  {
20908
- rect: toolbarRect,
20909
- elRef: glowElRef,
20910
- reorderHrefKey,
20911
- dragDisabled: reorderDragDisabled,
20912
- hideHandle: isItemDragging
19655
+ type: fieldPickState.type,
19656
+ required: fieldPickState.required,
19657
+ onTypeChange: handleFieldTypeChange,
19658
+ onRequiredToggle: handleFieldRequiredToggle,
19659
+ onDuplicate: handleFieldDuplicate,
19660
+ onDelete: handleFieldDelete
20913
19661
  }
20914
- ),
20915
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20916
- FloatingToolbar,
19662
+ )
19663
+ }
19664
+ ),
19665
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19666
+ "div",
19667
+ {
19668
+ className: "pointer-events-none fixed z-[2147483644]",
19669
+ style: { top: slot.top, left: slot.left, width: slot.width },
19670
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19671
+ DropIndicator,
20917
19672
  {
20918
- rect: toolbarRect,
20919
- parentScroll: parentScrollRef.current,
20920
- elRef: toolbarElRef,
20921
- onCommand: handleCommand,
20922
- activeCommands,
20923
- showEditLink,
20924
- onEditLink: openLinkPopoverForActive
19673
+ direction: "horizontal",
19674
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19675
+ className: "!w-full"
20925
19676
  }
20926
19677
  )
20927
- ] }),
20928
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20929
- "div",
20930
- {
20931
- "data-ohw-max-badge": "",
20932
- style: {
20933
- position: "fixed",
20934
- top: maxBadge.rect.bottom + 4,
20935
- left: maxBadge.rect.right,
20936
- transform: "translateX(-100%)",
20937
- zIndex: 2147483647,
20938
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20939
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20940
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20941
- borderRadius: 4,
20942
- padding: "2px 6px",
20943
- fontSize: 11,
20944
- fontWeight: 500,
20945
- pointerEvents: "none"
20946
- },
20947
- children: [
20948
- maxBadge.current,
20949
- "/",
20950
- maxBadge.max
20951
- ]
20952
- }
20953
- ),
20954
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20955
- StateToggle,
19678
+ },
19679
+ `field-drop-${i}`
19680
+ )) : null,
19681
+ fieldTypePickerOpen && formPickRect && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19682
+ "div",
19683
+ {
19684
+ className: "pointer-events-none fixed z-[2147483645]",
19685
+ style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
19686
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(FieldTypePicker, { onPick: handleAddField })
19687
+ }
19688
+ ),
19689
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19690
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19691
+ FooterContainerChrome,
19692
+ {
19693
+ rect: toolbarRect,
19694
+ onAdd: handleAddFooterColumn,
19695
+ addDisabled: !canAddFooterColumn()
19696
+ }
19697
+ ),
19698
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19699
+ ItemInteractionLayer,
19700
+ {
19701
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19702
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19703
+ elRef: glowElRef,
19704
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19705
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19706
+ dragDisabled: reorderDragDisabled,
19707
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19708
+ onDragHandleDragStart: handleItemDragStart,
19709
+ onDragHandleDragEnd: handleItemDragEnd,
19710
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19711
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19712
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19713
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19714
+ ItemActionToolbar,
19715
+ {
19716
+ onEditLink: openLinkPopoverForSelected,
19717
+ onStyle: () => {
19718
+ const row = selectedElRef.current;
19719
+ if (!row) return;
19720
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19721
+ else openSocialsDisplayPanel(row);
19722
+ },
19723
+ showStyle: selectedIsSocialsRow,
19724
+ styleActive: floatingPanel?.kind === "socials-display",
19725
+ onAddItem: handleAddChildItem,
19726
+ onSelectParent: handleSelectParent,
19727
+ onDuplicate: handleDuplicateSelected,
19728
+ onDelete: handleDeleteSelected,
19729
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19730
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19731
+ return row ? !canAddSocialItem(row) : false;
19732
+ })(),
19733
+ editLinkDisabled: false,
19734
+ moreDisabled: false,
19735
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19736
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19737
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19738
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19739
+ ),
19740
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19741
+ dropdownOpen: navDropdownPreviewOpen,
19742
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19743
+ headingVisible: footerHeadingVisible,
19744
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19745
+ }
19746
+ ) : void 0
19747
+ }
19748
+ ),
19749
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19750
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19751
+ EditGlowChrome,
20956
19752
  {
20957
- rect: toggleState.rect,
20958
- activeState: toggleState.activeState,
20959
- states: toggleState.states,
20960
- onStateChange: handleStateChange
19753
+ rect: toolbarRect,
19754
+ elRef: glowElRef,
19755
+ reorderHrefKey,
19756
+ dragDisabled: reorderDragDisabled,
19757
+ hideHandle: isItemDragging
20961
19758
  }
20962
19759
  ),
20963
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20964
- "div",
19760
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19761
+ FloatingToolbar,
20965
19762
  {
20966
- "data-ohw-section-insert-line": "",
20967
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20968
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
20969
- children: [
20970
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20971
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20972
- Badge,
20973
- {
20974
- 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",
20975
- onClick: () => {
20976
- window.parent.postMessage(
20977
- {
20978
- type: "ow:add-section",
20979
- insertAfter: sectionGap.insertAfter,
20980
- insertBefore: sectionGap.insertBefore
20981
- },
20982
- "*"
20983
- );
20984
- },
20985
- children: "Add Section"
20986
- }
20987
- ),
20988
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20989
- ]
19763
+ rect: toolbarRect,
19764
+ parentScroll: parentScrollRef.current,
19765
+ elRef: toolbarElRef,
19766
+ onCommand: handleCommand,
19767
+ activeCommands,
19768
+ showEditLink,
19769
+ onEditLink: openLinkPopoverForActive
20990
19770
  }
20991
- ),
20992
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20993
- LinkPopover,
20994
- {
20995
- panelRef: linkPopoverPanelRef,
20996
- portalContainer: dialogPortalContainer,
20997
- open: true,
20998
- mode: linkPopover.mode ?? "edit",
20999
- pages: sitePages,
21000
- sections: currentSections,
21001
- sectionsByPath,
21002
- initialTarget: linkPopover.target,
21003
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21004
- onClose: closeLinkPopover,
21005
- onSubmit: handleLinkPopoverSubmit
19771
+ )
19772
+ ] }),
19773
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19774
+ "div",
19775
+ {
19776
+ "data-ohw-max-badge": "",
19777
+ style: {
19778
+ position: "fixed",
19779
+ top: maxBadge.rect.bottom + 4,
19780
+ left: maxBadge.rect.right,
19781
+ transform: "translateX(-100%)",
19782
+ zIndex: 2147483647,
19783
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19784
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19785
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19786
+ borderRadius: 4,
19787
+ padding: "2px 6px",
19788
+ fontSize: 11,
19789
+ fontWeight: 500,
19790
+ pointerEvents: "none"
21006
19791
  },
21007
- linkPopover.key
21008
- ) : null,
21009
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21010
- FloatingPanel,
21011
- {
21012
- open: true,
21013
- title: floatingPanel.title,
21014
- context: floatingPanel.context,
21015
- position: floatingPanelPos,
21016
- onPositionChange: setFloatingPanelPos,
21017
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21018
- onClose: closeFloatingPanelOnly,
21019
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21020
- SocialsDisplayPanel,
19792
+ children: [
19793
+ maxBadge.current,
19794
+ "/",
19795
+ maxBadge.max
19796
+ ]
19797
+ }
19798
+ ),
19799
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19800
+ StateToggle,
19801
+ {
19802
+ rect: toggleState.rect,
19803
+ activeState: toggleState.activeState,
19804
+ states: toggleState.states,
19805
+ onStateChange: handleStateChange
19806
+ }
19807
+ ),
19808
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
19809
+ "div",
19810
+ {
19811
+ "data-ohw-section-insert-line": "",
19812
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19813
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19814
+ children: [
19815
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19816
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19817
+ Badge,
21021
19818
  {
21022
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21023
- onChange: (next) => {
21024
- changeSocialsDisplay(floatingPanel.row, next);
21025
- setFloatingPanel({ ...floatingPanel });
21026
- }
19819
+ 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",
19820
+ onClick: () => {
19821
+ window.parent.postMessage(
19822
+ {
19823
+ type: "ow:add-section",
19824
+ insertAfter: sectionGap.insertAfter,
19825
+ insertBefore: sectionGap.insertBefore
19826
+ },
19827
+ "*"
19828
+ );
19829
+ },
19830
+ children: "Add Section"
21027
19831
  }
21028
- )
21029
- }
21030
- ) : null
21031
- ] }),
21032
- bridgeRoot
21033
- ) : null
21034
- ] });
21035
- }
21036
-
21037
- // src/ui/EmptySection.tsx
21038
- var import_link = __toESM(require("next/link"), 1);
21039
- var import_jsx_runtime34 = require("react/jsx-runtime");
21040
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21041
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
21042
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21043
- "p",
21044
- {
21045
- style: {
21046
- fontFamily: "var(--brand-font-body)",
21047
- fontSize: "0.75rem",
21048
- fontWeight: 500,
21049
- letterSpacing: "0.15em",
21050
- textTransform: "uppercase",
21051
- color: "var(--brand-accent)",
21052
- marginBottom: "1.5rem"
21053
- },
21054
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
21055
- }
21056
- ),
21057
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21058
- "h1",
21059
- {
21060
- style: {
21061
- fontFamily: "var(--brand-font-heading)",
21062
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21063
- lineHeight: 1.1,
21064
- letterSpacing: "-0.025em",
21065
- color: "var(--brand-text)",
21066
- marginBottom: "1rem"
21067
- },
21068
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21069
- children: title
21070
- }
21071
- ),
21072
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
21073
- "p",
21074
- {
21075
- style: {
21076
- fontFamily: "var(--brand-font-body)",
21077
- fontSize: "1rem",
21078
- lineHeight: 1.7,
21079
- fontWeight: 300,
21080
- color: "var(--brand-text-muted)",
21081
- maxWidth: "340px"
19832
+ ),
19833
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19834
+ ]
19835
+ }
19836
+ ),
19837
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19838
+ LinkPopover,
19839
+ {
19840
+ panelRef: linkPopoverPanelRef,
19841
+ portalContainer: dialogPortalContainer,
19842
+ open: true,
19843
+ mode: linkPopover.mode ?? "edit",
19844
+ pages: sitePages,
19845
+ sections: currentSections,
19846
+ sectionsByPath,
19847
+ initialTarget: linkPopover.target,
19848
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19849
+ onClose: closeLinkPopover,
19850
+ onSubmit: handleLinkPopoverSubmit
21082
19851
  },
21083
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21084
- children: "This page doesn't have any content yet."
21085
- }
21086
- )
21087
- ] });
19852
+ linkPopover.key
19853
+ ) : null,
19854
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19855
+ FloatingPanel,
19856
+ {
19857
+ open: true,
19858
+ title: floatingPanel.title,
19859
+ context: floatingPanel.context,
19860
+ position: floatingPanelPos,
19861
+ onPositionChange: setFloatingPanelPos,
19862
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19863
+ onClose: closeFloatingPanelOnly,
19864
+ children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19865
+ SocialsDisplayPanel,
19866
+ {
19867
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19868
+ onChange: (next) => {
19869
+ changeSocialsDisplay(floatingPanel.row, next);
19870
+ setFloatingPanel({ ...floatingPanel });
19871
+ }
19872
+ }
19873
+ )
19874
+ }
19875
+ ) : null
19876
+ ] }),
19877
+ bridgeRoot
19878
+ ) : null;
21088
19879
  }
21089
19880
  // Annotate the CommonJS export names for ESM import in node:
21090
19881
  0 && (module.exports = {
@@ -21103,7 +19894,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
21103
19894
  DropdownMenuItem,
21104
19895
  DropdownMenuSeparator,
21105
19896
  DropdownMenuTrigger,
21106
- EmptySection,
21107
19897
  ItemActionToolbar,
21108
19898
  ItemInteractionLayer,
21109
19899
  LinkEditorPanel,